@powerduck/md-editor 0.10.10 → 0.11.2

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.
Files changed (2) hide show
  1. package/README.md +185 -397
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -1,467 +1,255 @@
1
1
  # @powerduck/md-editor
2
2
 
3
- High-performance embeddable Markdown editor built on the markdown-it ecosystem. Supports KaTeX math formulas (self-contained, no texmath), Markmap mindmaps, highlight.js code blocks with traffic-light UI and copy button, github-markdown-css preview styling, admonition/tip blocks, rich toolbar with image/video/YouTube/table popup dialogs, keyboard shortcuts with help dialog, configurable toolbar, image upload hook, standalone `renderMarkdown()` API, native React integration, block-level incremental rendering with debounced scheduling. Ships in two modes: **simple** (no toolbar, pure edit + preview) and **complex** (toolbar + status bar). Styled via CSS custom properties with light/dark themes.
3
+ [![npm version](https://img.shields.io/npm/v/@powerduck/md-editor)](https://www.npmjs.com/package/@powerduck/md-editor)
4
+ [![license](https://img.shields.io/npm/l/@powerduck/md-editor)](https://github.com/PowerDuckie/md-editor/blob/main/LICENSE)
5
+ [![downloads](https://img.shields.io/npm/dm/@powerduck/md-editor)](https://www.npmjs.com/package/@powerduck/md-editor)
4
6
 
5
- ## Features
7
+ High-performance embeddable Markdown editor with syntax highlighting, math formulas, mindmaps, @mentions, document link cards, and incremental rendering. Built on CodeMirror 6 with a React wrapper.
6
8
 
7
- - **Markdown editing** powered by CodeMirror 6 with markdown syntax highlighting
8
- - **Math formulas** via self-contained KaTeX plugin (`$E=mc^2$` inline, `$$...$$` block) -- no texmath dependency, no double-rendering
9
- - **Mindmaps** via Markmap (```` ```mindmap ```` code fences)
10
- - **Code highlighting** via highlight.js -- 20+ languages, macOS-style traffic-light header, one-click copy button
11
- - **Admonition blocks** -- `:::notice`, `:::warning`, `:::tip`, `:::danger`, `:::info`, `:::success` with icons and colored borders
12
- - **github-markdown-css** preview -- proper heading, list, table, and typography styling
13
- - **Rich toolbar** -- heading, bold, italic, link, image, video, YouTube, quote, lists, code, table, math, mindmap, horizontal rule, tip block, preview toggle, help, theme toggle
14
- - **Popup dialogs** -- image URL, video URL, YouTube URL/ID, table rows/columns
15
- - **Keyboard shortcuts** -- Ctrl+B bold, Ctrl+I italic, Ctrl+K link, etc. with a Help dialog listing all shortcuts
16
- - **Configurable toolbar** -- show/hide items, custom labels and icons via `toolbar` option
17
- - **Image upload hook** -- paste/drop images, call `onImageUpload(file)` to get a URL
18
- - **Video rendering** -- `.mp4`, `.webm`, `.ogg` links render as `<video>` elements
19
- - **Standalone renderer** -- `renderMarkdown(source, options)` for consistent styling outside the editor
20
- - **Block-level incremental rendering** -- only changed sections re-render
21
- - **Adaptive debounce** -- preview render delay scales with document length
22
- - **Simple / Complex modes** -- toggle toolbar and status bar at runtime
23
- - **Light / Dark themes** -- CSS custom properties, inherits host design tokens
24
- - **React component** -- `forwardRef` with imperative handle
25
-
26
- ## Installation
9
+ ---
27
10
 
28
- ```bash
29
- npm install @powerduck/md-editor
30
- ```
11
+ Powerduck is an open-source developer tooling platform for teams building modern API workflows.
31
12
 
32
- ## Usage
13
+ - **CodeMirror 6 Core** — Incremental rendering, virtual scrolling, and 60fps editing for large documents
14
+ - **KaTeX Math** — Render LaTeX math formulas inline and in display blocks
15
+ - **Markmap Mindmaps** — Visualize markdown outlines as interactive mindmaps
16
+ - **highlight.js Code Blocks** — Syntax highlighting for 190+ programming languages
17
+ - **@mentions** — Type `@` to search and mention users with avatars and descriptions
18
+ - **Document Link Cards** — Type `/` to insert rich doc-link preview cards with thumbnails
19
+ - **Admonition Blocks** — `:::tip`, `:::warning`, `:::note`, and more
20
+ - **Simple & Complex Modes** — Lightweight mode for comments, full-featured mode for docs
21
+ - **Light & Dark Themes** — Built-in themes with CSS variable customization
33
22
 
34
- ### Vanilla JS
23
+ ---
35
24
 
36
- ```ts
37
- import { MarkdownEditor } from '@powerduck/md-editor';
38
- import '@powerduck/md-editor/dist/style.css';
39
-
40
- const editor = new MarkdownEditor('#editor', {
41
- value: '# Hello\n\nStart typing...',
42
- mode: 'complex', // 'simple' | 'complex'
43
- theme: 'light', // 'light' | 'dark'
44
- math: true,
45
- mindmap: true,
46
- onChange: (value) => console.log(value)
47
- });
25
+ ## Quick Start
26
+
27
+ ### Install
28
+
29
+ ```bash
30
+ npm install @powerduck/md-editor
48
31
  ```
49
32
 
50
- ### React
33
+ ### React Component
51
34
 
52
35
  ```tsx
53
- import { MarkdownEditorReact } from '@powerduck/md-editor/react';
54
- import '@powerduck/md-editor/dist/style.css';
36
+ import { useRef, useState } from "react";
37
+ import {
38
+ MarkdownEditorReact,
39
+ type MarkdownEditorHandle,
40
+ } from "@powerduck/md-editor/react";
41
+ import "@powerduck/md-editor/dist/style.css";
55
42
 
56
43
  function App() {
44
+ const [value, setValue] = useState("# Hello\n\nStart typing...");
45
+ const editorRef = useRef<MarkdownEditorHandle>(null);
46
+
57
47
  return (
58
- <MarkdownEditorReact
59
- defaultValue="# Hello"
60
- mode="complex"
61
- onChange={(v) => console.log(v)}
62
- />
48
+ <div style={{ height: "600px" }}>
49
+ <MarkdownEditorReact
50
+ ref={editorRef}
51
+ value={value}
52
+ onChange={setValue}
53
+ mode="complex"
54
+ theme="light"
55
+ />
56
+ <button onClick={() => console.log(editorRef.current?.getHtml())}>
57
+ Get HTML
58
+ </button>
59
+ </div>
63
60
  );
64
61
  }
65
62
  ```
66
63
 
67
- ## API
68
-
69
- ### MarkdownEditorOptions
70
-
71
- | Option | Type | Default | Description |
72
- |--------|------|---------|-------------|
73
- | `value` | `string` | `''` | Initial content |
74
- | `mode` | `'simple' \| 'complex'` | `'simple'` | Toolbar + status bar in complex mode |
75
- | `theme` | `'light' \| 'dark'` | `'light'` | Color theme |
76
- | `math` | `boolean` | `true` | Enable KaTeX math |
77
- | `mindmap` | `boolean` | `true` | Enable Markmap mindmaps |
78
- | `codeHighlight` | `boolean` | `true` | Enable highlight.js code blocks with copy button |
79
- | `tips` | `boolean` | `true` | Enable admonition/tip blocks (:::notice, :::warning, etc.) |
80
- | `preview` | `boolean` | `true` | Show preview pane |
81
- | `toolbar` | `ToolbarConfig` | all items | Configure which toolbar items show, their labels and icons |
82
- | `onImageUpload` | `(file: File) => Promise<string>` | - | Image upload hook for paste/drop |
83
- | `autoPreview` | `boolean` | `true` | Auto-render preview on edit |
84
- | `renderDebounce` | `number \| false` | adaptive | Preview debounce in ms |
85
- | `onChange` | `(value: string) => void` | - | Change callback |
86
-
87
- ### Methods
88
-
89
- - `getValue(): string`
90
- - `setValue(value: string): void`
91
- - `getHtml(): string`
92
- - `renderNow(): void` -- manual preview render (use with `autoPreview: false`)
93
- - `setMode(mode: EditorMode): void`
94
- - `setTheme(theme: EditorTheme): void`
95
- - `setAutoPreview(auto: boolean): void`
96
- - `focus(): void`
97
- - `destroy(): void`
98
-
99
- ## Mindmap Syntax
100
-
101
- ````markdown
102
- ```mindmap
103
- # Root topic
104
- ## Branch one
105
- - Child A
106
- - Child B
107
- ## Branch two
108
- - Child C
109
- ```
110
- ````
111
-
112
- ## Code Blocks
113
-
114
- Code fences are automatically highlighted with highlight.js (20+ languages including JavaScript, TypeScript, Python, JSON, Bash, CSS, HTML, SQL, YAML, Go, Rust, Java, C/C++). Each code block gets a macOS-style header with traffic-light dots, a language label, and a copy button.
64
+ ### Vanilla JS
115
65
 
116
- ````markdown
117
66
  ```typescript
118
- interface User {
119
- name: string;
120
- age: number;
121
- }
122
- ```
123
- ````
124
-
125
- Unknown languages are auto-detected; if detection fails, the content is HTML-escaped and displayed as plain text. Disable code highlighting with `codeHighlight: false`.
126
-
127
- ## Media Insertion
128
-
129
- The complex-mode toolbar includes popup dialogs for inserting media:
130
-
131
- - **Image** (`image` button): URL + alt text -> `![alt](url)`
132
- - **Video** (`video` button): URL (.mp4, .webm, .ogg) -> renders as `<video controls>` in preview
133
- - **YouTube** (`youtube` button): accepts any YouTube URL format (watch?v=, youtu.be, embed, shorts) or raw 11-char ID -> inserts a linked thumbnail image that opens the video on click
134
-
135
- YouTube insertion extracts the video ID automatically and produces:
136
- ```markdown
137
- [![YouTube video](https://img.youtube.com/vi/VIDEO_ID/hqdefault.jpg)](https://www.youtube.com/watch?v=VIDEO_ID)
138
- ```
139
-
140
- ## Standalone Renderer
141
-
142
- Use `renderMarkdown()` to render markdown with the same styling and plugins as the editor preview, without mounting an editor:
143
-
144
- ```ts
145
- import { renderMarkdown } from '@powerduck/md-editor';
146
- import '@powerduck/md-editor/dist/style.css';
147
-
148
- const html = renderMarkdown('# Hello\n\n$E=mc^2$\n\n:::tip\nWorks!\n:::');
149
- container.innerHTML = html;
150
- ```
151
-
152
- Options: `math`, `mindmap`, `codeHighlight`, `tips`, `html`, `breaks` -- all default to `true` except `html` and `breaks`.
153
-
154
- ## Keyboard Shortcuts
155
-
156
- | Shortcut | Action |
157
- |----------|--------|
158
- | `Ctrl+B` / `Cmd+B` | Bold |
159
- | `Ctrl+I` / `Cmd+I` | Italic |
160
- | `Ctrl+Alt+1` | Heading |
161
- | `Ctrl+K` / `Cmd+K` | Insert link |
162
- | `Ctrl+Alt+C` | Code block |
163
- | `Ctrl+Shift+.` | Blockquote |
164
- | `Ctrl+Shift+8` | Unordered list |
165
- | `Ctrl+Shift+7` | Ordered list |
166
- | `Ctrl+Alt+M` | Math formula |
167
- | `Ctrl+Alt+P` | Toggle preview |
168
- | `Ctrl+Shift+L` | Toggle theme |
169
-
170
- Click the **Help** (?) button in the toolbar to see all shortcuts at runtime.
171
-
172
- ## Configurable Toolbar
173
-
174
- Control which buttons appear and customize their labels/icons:
67
+ import { MarkdownEditor } from "@powerduck/md-editor";
68
+ import "@powerduck/md-editor/dist/style.css";
175
69
 
176
- ```ts
177
- // Only show specific buttons
178
- new MarkdownEditor('#editor', {
179
- mode: 'complex',
180
- toolbar: ['bold', 'italic', 'link', 'code']
70
+ const editor = new MarkdownEditor("#editor", {
71
+ value: "# Hello\n\nStart typing...",
72
+ mode: "complex",
73
+ theme: "light",
74
+ onChange: (value) => console.log(value.length, "chars"),
181
75
  });
182
76
 
183
- // Fine-grained control
184
- new MarkdownEditor('#editor', {
185
- mode: 'complex',
186
- toolbar: {
187
- bold: { label: 'Make bold', icon: '<b>B</b>' },
188
- image: { show: false },
189
- youtube: { show: false }
190
- }
191
- });
77
+ const html = editor.getHtml();
192
78
  ```
193
79
 
194
- ## Image Upload
80
+ ---
195
81
 
196
- Provide an upload hook to handle pasted/dropped images:
82
+ ## Links
197
83
 
198
- ```ts
199
- new MarkdownEditor('#editor', {
200
- mode: 'complex',
201
- onImageUpload: async (file) => {
202
- const formData = new FormData();
203
- formData.append('file', file);
204
- const res = await fetch('/api/upload', { method: 'POST', body: formData });
205
- const { url } = await res.json();
206
- return url; // inserted as ![filename](url)
207
- }
208
- });
209
- ```
210
-
211
- ## Admonition Blocks
212
-
213
- ```markdown
214
- :::tip Pro tip
215
- Use admonition blocks for callouts.
216
- :::
217
-
218
- :::warning
219
- This action cannot be undone.
220
- :::
221
-
222
- :::danger
223
- Destructive operation.
224
- :::
225
- ```
84
+ - [Official Website](https://www.powerduck.com/opensource/md-editor.html)
85
+ - [Documentation](https://www.powerduck.com/docs/md-editor/introduction)
86
+ - [Live Demo](https://www.powerduck.com/demo/md-editor)
87
+ - [GitHub](https://github.com/PowerDuckie/md-editor)
88
+ - [npm](https://www.npmjs.com/package/@powerduck/md-editor)
226
89
 
227
- Supported types: `notice`, `info`, `tip`, `success`, `warning`, `danger`.
90
+ ---
228
91
 
229
- ## Performance
92
+ ## Features
230
93
 
231
- - **Block splitting**: documents are split at ATX headings (`#` through `######`). Content inside code fences is never split.
232
- - **Incremental rendering**: unchanged blocks reuse their DOM nodes directly, including already-hydrated mindmap SVGs.
233
- - **Content-hash cache**: render results are cached by content hash, so undo/redo and copy-paste hit the cache.
234
- - **Adaptive debounce**: `adaptiveDebounceMs(docLength)` scales from 120ms to 600ms based on document size.
235
- - **`content-visibility: auto`**: off-screen blocks skip layout and paint entirely.
94
+ - **CodeMirror 6 core** — incremental rendering, virtual scrolling, and 60fps editing for large documents
95
+ - **KaTeX math** — render LaTeX math formulas inline and in display blocks
96
+ - **Markmap mindmaps** — visualize markdown outlines as interactive mindmaps
97
+ - **highlight.js code blocks** — syntax highlighting for 190+ programming languages
98
+ - **@mentions** — type `@` to search and mention users with avatars and descriptions
99
+ - **Document link cards** — type `/` to insert rich doc-link preview cards with thumbnails
100
+ - **Admonition blocks** — `:::tip`, `:::warning`, `:::note`, and more
101
+ - **Simple & complex modes** — lightweight mode for comments, full-featured mode for docs
102
+ - **Light & dark themes** — built-in themes with CSS variable customization
103
+ - **Image upload hooks** — custom upload handlers with paste and drag-and-drop support
104
+ - **Toolbar & slash commands** — rich formatting toolbar and `/` command palette
105
+ - **Dual ESM/CJS builds** — works with `import` and `require`, with bundled TypeScript declarations
236
106
 
237
- ## Development
107
+ ---
238
108
 
239
- ```bash
240
- npm install
241
- npm run typecheck # src only
242
- npm run typecheck:test # src + tests
243
- npm test # run all tests (vitest + jsdom)
244
- npm run build # vite build + d.ts generation
245
- ```
109
+ ## @mention Integration
246
110
 
247
- ## React Demo
248
- ```jsx
249
- import { useRef, useCallback } from "react";
250
- import { type MentionItem, type DocItem } from "@powerduck/md-editor";
251
- import {
252
- MarkdownEditorReact,
253
- type MarkdownEditorHandle,
254
- } from "@powerduck/md-editor/react";
255
- import "@powerduck/md-editor/dist/style.css";
111
+ ```typescript
112
+ import { MarkdownEditor, type MentionItem } from "@powerduck/md-editor";
256
113
 
257
114
  const USERS: MentionItem[] = [
258
115
  {
259
116
  id: "1",
260
117
  label: "Alice",
261
- avatar: "https://i.pravatar.cc/40?u=alice",
118
+ avatar: "https://example.com/a.png",
262
119
  description: "alice@example.com",
263
120
  },
264
- {
265
- id: "2",
266
- label: "Bob",
267
- avatar: "https://i.pravatar.cc/40?u=bob",
268
- description: "bob@example.com",
269
- },
270
- { id: "3", label: "Charlie", description: "charlie@example.com" },
121
+ { id: "2", label: "Bob", description: "bob@example.com" },
271
122
  ];
272
123
 
273
- const DOCS: DocItem[] = [
274
- {
275
- id: "d1",
276
- title: "Getting Started",
277
- url: "https://docs.example.com/start",
278
- description: "Quick start guide",
279
- thumbnail: "https://picsum.photos/seed/start/96/72",
124
+ new MarkdownEditor("#editor", {
125
+ mode: "complex",
126
+ mention: {
127
+ onMentionSearch: async (query) =>
128
+ USERS.filter((u) => u.label.toLowerCase().includes(query.toLowerCase())),
129
+ onMentionSelect: (item) => `[@${item.label}](mention:${item.id})`,
130
+ minChars: 0,
131
+ maxItems: 8,
280
132
  },
281
- {
282
- id: "d2",
283
- title: "API Reference",
284
- url: "https://docs.example.com/api",
285
- description: "Full API documentation",
286
- },
287
- {
288
- id: "d3",
289
- title: "Changelog",
290
- url: "https://docs.example.com/changelog",
291
- description: "Release notes",
292
- },
293
- ];
133
+ });
134
+ ```
294
135
 
295
- function App() {
296
- const editorRef = useRef<MarkdownEditorHandle>(null);
136
+ ---
297
137
 
298
- const handleSave = useCallback(() => {
299
- const markdown = editorRef.current?.getValue() ?? "";
300
- console.log("Saving:", markdown);
301
- }, []);
302
-
303
- // Stable callbacks so the editor does not recreate on every render
304
- const searchUsers = useCallback(async (query: string) => {
305
- return USERS.filter((u) =>
306
- u.label.toLowerCase().includes(query.toLowerCase()),
307
- );
308
- }, []);
309
-
310
- const searchDocs = useCallback(async (query: string) => {
311
- return DOCS.filter((d) =>
312
- d.title.toLowerCase().includes(query.toLowerCase()),
313
- );
314
- }, []);
315
-
316
- const fetchDocMeta = useCallback(async (url: string) => {
317
- // In production, route through your backend to avoid CORS:
318
- // const res = await fetch(`/api/og?url=${encodeURIComponent(url)}`);
319
- // return res.json();
320
- // For demo: return whatever metadata the item already has
321
- const doc = DOCS.find((d) => d.url === url);
322
- return {
323
- title: doc?.title ?? new URL(url).hostname,
324
- description: doc?.description,
325
- thumbnail: doc?.thumbnail,
326
- url,
327
- };
328
- }, []);
138
+ ## Document Link Card
329
139
 
330
- return (
331
- <div style={{ padding: 24, maxWidth: 1100, margin: "0 auto" }}>
332
- <div style={{ marginBottom: 12, display: "flex", gap: 8 }}>
333
- <button onClick={handleSave}>Save</button>
334
- <button onClick={() => editorRef.current?.setTheme("dark")}>
335
- Dark
336
- </button>
337
- <button onClick={() => editorRef.current?.setTheme("light")}>
338
- Light
339
- </button>
340
- </div>
140
+ ```typescript
141
+ import { MarkdownEditor, type DocItem } from "@powerduck/md-editor";
341
142
 
342
- <MarkdownEditorReact
343
- ref={editorRef}
344
- defaultValue={[
345
- "# Welcome",
346
- "",
347
- "Type **@** to mention a user, or **/** to insert a document link.",
348
- "",
349
- "## Task list",
350
- "- [ ] This is checked (green)",
351
- "- [x] This is unchecked",
352
- "- [ x] Spaces inside brackets also work",
353
- "",
354
- "## Table",
355
- "| Name | Role |",
356
- "|------|------|",
357
- "| Alice | Admin |",
358
- "| Bob | Editor |",
359
- ].join("\n")}
360
- mode="complex"
361
- theme="light"
362
- onChange={(v) => console.log("auto-save:", v.length)}
363
- mention={{
364
- onMentionSearch: searchUsers,
365
- minChars: 0,
366
- maxItems: 8,
367
- }}
368
- docLink={{
369
- onDocSearch: searchDocs,
370
- onFetchDocMeta: fetchDocMeta,
371
- insertStyle: "auto",
372
- minChars: 0,
373
- maxItems: 8,
374
- }}
375
- />
376
- </div>
377
- );
378
- }
143
+ const DOCS: DocItem[] = [
144
+ {
145
+ id: "1",
146
+ title: "Getting Started",
147
+ url: "https://docs.example.com/getting-started",
148
+ thumbnail: "https://example.com/thumb.jpg",
149
+ description: "Quick start tutorial",
150
+ },
151
+ ];
379
152
 
380
- export default App;
153
+ new MarkdownEditor("#editor", {
154
+ mode: "complex",
155
+ docLink: {
156
+ onDocSearch: async (query) =>
157
+ DOCS.filter((d) => d.title.toLowerCase().includes(query.toLowerCase())),
158
+ insertStyle: "card",
159
+ minChars: 0,
160
+ maxItems: 6,
161
+ },
162
+ });
381
163
  ```
382
164
 
383
- ## Changelog
165
+ ---
384
166
 
385
- ### v0.8.4
167
+ ## API Reference
386
168
 
387
- - **Fixed**: React component `MarkdownEditorReact` now passes through all extra props (`mention`, `docLink`, `toolbar`, `onImageUpload`, `includeCommonHeaders`, `includeCookies`, `placeholder`, etc.) to the underlying `MarkdownEditor` instance. Previously only a subset of props were forwarded, so `mention` and `docLink` configs were silently ignored.
388
- - **Test**: 311 tests, all passing, zero unhandled errors.
169
+ ### React Props
389
170
 
390
- ### v0.8.3
171
+ | Prop | Type | Default | Description |
172
+ | ---------------- | ------------------------- | ----------- | --------------------------------------- |
173
+ | `value` | `string` | - | Markdown content (controlled) |
174
+ | `defaultValue` | `string` | - | Initial markdown content (uncontrolled) |
175
+ | `onChange` | `(value: string) => void` | - | Content change callback |
176
+ | `mode` | `"simple" \| "complex"` | `"complex"` | Editor mode |
177
+ | `theme` | `"light" \| "dark"` | `"light"` | Color theme |
178
+ | `math` | `boolean` | `true` | Enable KaTeX math rendering |
179
+ | `mindmap` | `boolean` | `true` | Enable Markmap mindmaps |
180
+ | `codeHighlight` | `boolean` | `true` | Enable highlight.js code blocks |
181
+ | `tips` | `boolean` | `true` | Enable admonition blocks |
182
+ | `preview` | `boolean` | `true` | Show preview pane |
183
+ | `autoPreview` | `boolean` | `true` | Auto-update preview |
184
+ | `renderDebounce` | `number` | `200` | Preview render debounce in ms |
185
+ | `mention` | `MentionConfig` | - | @mention configuration |
186
+ | `docLink` | `DocLinkConfig` | - | Document link card configuration |
391
187
 
392
- - **Changed**: Task list checkbox semantics inverted per project convention. `- [ ]` now renders as **checked** (green checkmark); `- [x]` / `- [X]` renders as **unchecked** (empty box). `toggleTaskList()` and all tests updated accordingly.
393
- - **Improved**: Clicking the @mention or document-link toolbar button without configuring the search hook now logs a clear `console.warn` explaining that `mention.onMentionSearch` / `docLink.onDocSearch` must be provided.
394
- - **Test**: 310 tests, all passing, zero unhandled errors.
188
+ ### Imperative Handle (React)
395
189
 
396
- ### v0.8.2
397
-
398
- - **Fixed**: @mention and `/` doc-link dropdowns did not appear. Root cause: v0.8.1 mounted dropdowns inside `.md-editor-root` where ancestor `overflow:hidden` / stacking contexts could clip or misplace `position:fixed` elements. Reverted to `document.body` mounting with `position:fixed`, and added explicit light/dark colors via `data-theme` attribute (no dependency on editor-scoped CSS variables).
399
- - **Fixed**: Clicking toolbar button icons (SVG) did not open popups. Root cause: `mousedown` event bubbled to `document` and triggered the newly-opened Popup's outside-click handler (because `e.target` was the SVG, not the button). Fixed in two ways: Popup now uses `anchor.contains(target)` instead of `target !== anchor`; toolbar `mousedown` handler calls `e.stopPropagation()`.
400
- - **Fixed**: Task list checkboxes now render with a clear green checkmark when checked (`- [x]` or `- [X]`). Previously used native `accent-color` (orange) which was hard to distinguish in disabled state. Custom checkbox: gray border when unchecked, solid green with white checkmark when checked.
401
- - **Added**: Help dialog now includes a "Syntax" section with quick-reference guidance for task lists, @mentions, document links, math, mindmaps, and callouts.
402
- - **Fixed**: Help dialog and all popup-internal styles no longer use editor-scoped CSS variables (undefined when popup is on `document.body`), ensuring consistent light/dark rendering.
403
- - **Test**: 310 tests, all passing, zero unhandled errors.
404
-
405
- ### v0.8.1
190
+ ```typescript
191
+ interface MarkdownEditorHandle {
192
+ getValue(): string;
193
+ setValue(value: string): void;
194
+ getHtml(): string;
195
+ focus(): void;
196
+ blur(): void;
197
+ clear(): void;
198
+ }
199
+ ```
406
200
 
407
- - **Fixed**: Toolbar buttons now use `mousedown` + `preventDefault` instead of `click`, preventing the editor from losing focus and collapsing the selection before wrap operations. This fixes the long-standing issue where selecting text and clicking quote/list/other toolbar buttons replaced the selection with placeholder text ("quoted text", "list item").
408
- - **Fixed**: `toggleTaskList()` mixed-state logic. Previously, a mix of checked and unchecked items (or all-unchecked) removed all task markers. Now: mixed or all-unchecked → check all; all-checked → uncheck all. Also supports uppercase `[X]` markers.
409
- - **Fixed**: Code block copy button now falls back to `document.execCommand('copy')` when `navigator.clipboard` is unavailable (non-HTTPS contexts), instead of silently failing.
410
- - **Fixed**: @mention and doc-link dropdowns now close when the editor loses focus (blur), with a 150ms delay so clicks on the dropdown itself register first.
411
- - **Fixed**: @mention and doc-link dropdowns had transparent backgrounds because they used editor-scoped CSS variables (`--_surface`) while being appended to `document.body`. Now appended inside `.md-editor-root` with `position: fixed` (not clipped by `overflow: hidden`), so theme variables resolve correctly.
412
- - **Fixed**: Popup dialogs (image, video, YouTube, table, help, callout) now respect the editor theme. Previously always light-themed; now dark-themed when the editor is in dark mode.
413
- - **Test**: 310 tests, all passing, zero unhandled errors.
201
+ ### MentionConfig
414
202
 
415
- ### v0.8.0
203
+ ```typescript
204
+ interface MentionConfig {
205
+ onMentionSearch: (query: string) => MentionItem[] | Promise<MentionItem[]>;
206
+ onMentionSelect?: (item: MentionItem) => string;
207
+ minChars?: number;
208
+ maxItems?: number;
209
+ triggerChar?: string;
210
+ }
211
+ ```
416
212
 
417
- - **Added**: Document/article link inserter. Type `/` to open a searchable dropdown of documents. `onDocSearch(query)` returns matching documents; on selection, inserts either a plain markdown link or a `:::doc-link` preview card.
418
- - **Added**: `:::doc-link` preview card rendering — displays title, thumbnail, description, and domain as a clickable card. Auto-fetches Open Graph / meta tags via `onFetchDocMeta(url)` hook; falls back to plain link when metadata is unavailable or fetch fails.
419
- - **Added**: `insertStyle` option: `'auto'` (default, card when meta available), `'card'` (always card, fallback to link), `'link'` (always plain link).
420
- - **Added**: `docLink` option to `MarkdownEditorOptions` and `CodeEditorOptions`, with `triggerChar`, `minChars`, `maxItems` configuration.
421
- - **Added**: Toolbar button for document link insertion.
422
- - **Test**: 307 tests, all passing, zero unhandled errors.
213
+ ### DocLinkConfig
423
214
 
424
- ### v0.7.0
215
+ ```typescript
216
+ interface DocLinkConfig {
217
+ onDocSearch: (query: string) => DocItem[] | Promise<DocItem[]>;
218
+ onFetchDocMeta?: (url: string) => Promise<DocMeta>;
219
+ insertStyle?: "card" | "link" | "auto";
220
+ minChars?: number;
221
+ maxItems?: number;
222
+ triggerChar?: string;
223
+ }
224
+ ```
425
225
 
426
- - **Fixed**: Mindmap nested code fences no longer lose content. Custom block rule tracks fence nesting depth (lines with info string open, bare backticks close), so ` ```js ` inside a ` ```mindmap ` block is preserved.
427
- - **Added**: Task list (checkbox) toolbar button and `toggleTaskList()` API. Toggles `- [ ]` / `- [x]` on current line or selected lines. Renders as checkboxes in preview. Keyboard shortcut: `Ctrl+Shift+9`.
428
- - **Added**: @mention dropdown with configurable hooks. `onMentionSearch(query)` returns matching items, `onMentionSelect(item)` returns replacement text. Supports keyboard navigation (ArrowUp/Down, Enter, Escape), avatars, descriptions, `minChars`, and `maxItems` options.
429
- - **Added**: `mention` option to `MarkdownEditorOptions` and `CodeEditorOptions`.
430
- - **Test**: 281 tests, all passing, zero unhandled errors.
226
+ ---
431
227
 
432
- ### v0.6.0
228
+ ## TypeScript Types
433
229
 
434
- - **Fixed**: Mindmap `transform: translate(NaN,NaN) scale(NaN)` console errors (hundreds per mindmap). Root cause: `autoFit: true` computed transform on zero-size SVG before layout, and d3-zoom scheduled hundreds of animation frames each throwing "Expected number". Fix: create with `autoFit: false`, set safe default transform immediately, defer `fit()` to next animation frame with dimension guard.
435
- - **Fixed**: Code block colors now sync with editor theme (light/dark). Previously hardcoded to atom-one-dark in all themes. Now uses CSS variables (`--code-bg`, `--code-fg`, `--code-keyword`, etc.) with GitHub-style light and dark palettes.
436
- - **Fixed**: UL/OL list styling in preview now has consistent spacing, bullet alignment, and line height.
437
- - **Improved**: Removed `highlight.js/styles/atom-one-dark.css` import; syntax highlighting colors are now fully theme-aware via CSS variables.
438
- - **Improved**: Removed stale `markdown-it-texmath` from vite external deps (removed in v0.4.0).
439
- - **Improved**: Vitest config now excludes `__MACOSX` and AppleDouble (`._*`) files to prevent false test failures from macOS zip artifacts.
440
- - **Test**: 251 tests, all passing, zero unhandled errors.
230
+ ```typescript
231
+ import type {
232
+ MentionItem,
233
+ DocItem,
234
+ DocMeta,
235
+ MentionConfig,
236
+ DocLinkConfig,
237
+ MarkdownEditorHandle,
238
+ MarkdownEditorProps,
239
+ } from "@powerduck/md-editor";
240
+ ```
441
241
 
442
- ### v0.5.0
242
+ ---
443
243
 
444
- - **Fixed**: Admonition `:::` closing marker no longer leaks into rendered body content.
445
- - **Fixed**: Quote, unordered list, and ordered list toolbar actions now wrap selected text (or the current line) instead of replacing it.
446
- - **Improved**: Tip/admonition toolbar button now opens a type-picker popup with all six styles (notice, info, tip, success, warning, danger).
447
- - **Improved**: Help dialog now displays keyboard shortcuts with styled key caps and modifier-key symbols (⌘, ⌥, ⇧).
448
- - **Improved**: All toolbar icons redesigned in a clean Lucide/Feather line style for a modern Western aesthetic.
449
- - **Fixed**: Mindmap `transform: translate(NaN,NaN)` error guarded when SVG has zero layout size.
450
- - **Added**: `formatShortcutHtml()` export for rendering styled key caps.
451
- - **Test**: 251 tests, all passing.
244
+ ## Browser Support
452
245
 
453
- ### v0.4.0
246
+ - Chrome 90+
247
+ - Firefox 88+
248
+ - Safari 14+
249
+ - Edge 90+
454
250
 
455
- - Self-contained KaTeX math plugin (removed `markdown-it-texmath`); currency `$5` no longer misparsed.
456
- - Image upload hook `onImageUpload(file)` with paste/drag support.
457
- - 11 keyboard shortcuts with macOS Cmd auto-mapping.
458
- - Help dialog listing all shortcuts.
459
- - Table rows/columns popup dialog.
460
- - Theme toggle fixed for dark mode with github-markdown-css.
461
- - Admonition/tip blocks (`:::notice`, `:::warning`, etc.).
462
- - Configurable toolbar (include-list or per-item show/label/icon).
463
- - Standalone `renderMarkdown(source, options)` API export.
251
+ ---
464
252
 
465
253
  ## License
466
254
 
467
- MIT
255
+ MIT © [POWERDUCK LIMITED](https://www.powerduck.com)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@powerduck/md-editor",
3
- "version": "0.10.10",
3
+ "version": "0.11.2",
4
4
  "description": "High-performance embeddable Markdown editor: KaTeX math, Markmap mindmaps, highlight.js code blocks with copy button, github-markdown-css preview, admonition blocks, rich toolbar with image/video/YouTube/table popups, keyboard shortcuts, configurable toolbar, image upload hook, standalone renderMarkdown API, React component, block-level incremental rendering. Simple and complex modes, light/dark themes.",
5
5
  "type": "module",
6
6
  "main": "dist/index.cjs",