markdown-text-editor 1.8.0 → 1.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -40,7 +40,7 @@ Most JavaScript markdown editors (EasyMDE, SimpleMDE, CodeMirror-based editors)
40
40
  | Swap the markdown parser | ✅ | ❌ |
41
41
  | Keyboard shortcuts | ✅ | Partial |
42
42
  | Dark mode / theming | ✅ | Limited |
43
- | Bundle size, gzipped | 51 KB | 107 KB (JS + CSS) |
43
+ | Bundle size, gzipped | 54 KB | 107 KB (JS + CSS) |
44
44
 
45
45
  ## 🚀 Quick Start
46
46
 
@@ -96,13 +96,14 @@ That's it. Form submission, `.value` access, and all native textarea behaviour w
96
96
  - 🔄 **Undo / Redo** — Full diff-based history with exact cursor restoration. Works with `Ctrl+Z`, `Ctrl+Y`, `Ctrl+Shift+Z`
97
97
  - ♿ **Accessible by Default** — `role="toolbar"`, `aria-pressed`, `aria-disabled`, `disabled`, screen-reader-friendly SVGs, and correct focus restoration on modal close
98
98
  - 🛡️ **XSS Safe** — Preview output sanitized via [DOMPurify](https://github.com/cure53/DOMPurify) before rendering, including the output of a custom renderer
99
- - 🛡️ **CSP Compatible** — No inline event handlers. Works with strict Content Security Policy headers
99
+ - 🛡️ **No inline scripts** — No inline event handlers and no `eval`, so `script-src` needs no exception. The stylesheet is currently injected as a `<style>` element, which a strict `style-src` blocks ([#42](https://github.com/nezanuha/markdown-text-editor/issues/42))
100
100
  - 🌍 **RTL Support** — Native Right-to-Left support for Arabic, Urdu, Farsi, and other RTL languages
101
101
  - 🌙 **Dark Mode & Theming** — Inherits `data-theme` from any ancestor element. Built-in light, dark, snowberry, and darkberry themes. Fully customizable via CSS variables
102
+ - 🧩 **Custom Tools** — Add your own toolbar button with `{ custom: { title, icon, action } }`, or extend `MarkdownEditor.Tool` when it builds its own markup. Keyboard shortcuts, translation and teardown work exactly as they do for the built-ins. No fork, no patching
102
103
  - 🎛️ **Modular Toolbar** — Pick exactly which tools appear and in what order
103
104
  - 🟦 **TypeScript Ready** — Definitions ship with the package. Options, toolbar entries and variable shapes are all checked, so a mistyped tool name is a compile error rather than a silently missing button
104
105
  - 📦 **Universal Module Support** — ESM, CommonJS, UMD, and IIFE. Works with Vite, webpack, Rollup, or directly via `<script src>` CDN — no configuration needed
105
- - 🚀 **High Performance** — ~52KB gzipped (245KB minified). Debounced preview, cached layout calculations, conflict-free Tab/Enter handling for large documents
106
+ - 🚀 **High Performance** — ~54KB gzipped (253KB minified). Debounced preview, cached layout calculations, conflict-free Tab/Enter handling for large documents
106
107
 
107
108
  ## 🛠 Developer Workflow
108
109
 
@@ -140,6 +141,46 @@ const editor = new MarkdownEditor('#markdown-editor', {
140
141
  });
141
142
  ```
142
143
 
144
+ ### Add your own toolbar button
145
+
146
+ Most tools are just a title, an icon and a function. No class, no fork:
147
+
148
+ ```javascript
149
+ new MarkdownEditor('#markdown-editor', {
150
+ toolbar: ['bold', 'italic', {
151
+ custom: {
152
+ title: 'Callout', // tooltip, and the .callout-btn class
153
+ icon: '<svg>…</svg>',
154
+ shortcut: 'Ctrl+Shift+C', // optional, shown in the tooltip
155
+ action(editor) {
156
+ editor.insertText('> [!NOTE]\n> ');
157
+ }
158
+ }
159
+ }, 'preview']
160
+ });
161
+ ```
162
+
163
+ Use `editor.insertText(text, caretOffset, trailingLength)` rather than writing to the textarea yourself — it replaces the selection, restores focus, moves the caret, re-renders the preview, fires `onChange`, and keeps undo working.
164
+
165
+ A tool that builds its own markup, such as a dropdown or a dialog, extends the base class instead:
166
+
167
+ ```javascript
168
+ class EmbedTool extends MarkdownEditor.Tool {
169
+ constructor(editor) {
170
+ super(editor, 'Embed video');
171
+ this.button = this.createButton('<svg>…</svg>');
172
+ }
173
+ applySyntax(event) {
174
+ // MarkdownEditor.modal is the same dialog the link and image tools use
175
+ const dialog = MarkdownEditor.modal(event, 'fj:max-w-sm', '…', 'Embed');
176
+ }
177
+ }
178
+
179
+ new MarkdownEditor('#markdown-editor', { toolbar: ['bold', EmbedTool, 'preview'] });
180
+ ```
181
+
182
+ Two helpers exist for tools that need them: `editor.renderMarkdown(md)` returns sanitized HTML exactly as the preview does, and `editor.createToolbar(textarea, ['bold', 'italic'])` builds a real toolbar bound to another textarea, for a tool collecting rich text in its own dialog.
183
+
143
184
  ### Tear down in SPAs
144
185
 
145
186
  ```javascript