@powerduck/md-editor 0.2.0 → 0.5.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 +134 -2
- package/dist/Editor.d.ts +20 -0
- package/dist/Renderer.d.ts +20 -0
- package/dist/Toolbar.d.ts +1 -1
- package/dist/icons.d.ts +8 -0
- package/dist/index.cjs +23 -5
- package/dist/index.d.ts +48 -12
- package/dist/index.mjs +7901 -274
- package/dist/plugins/code.d.ts +16 -0
- package/dist/plugins/keyboard.d.ts +22 -0
- package/dist/plugins/math.d.ts +1 -5
- package/dist/plugins/media.d.ts +23 -0
- package/dist/plugins/mindmap.d.ts +5 -0
- package/dist/plugins/popup.d.ts +34 -0
- package/dist/plugins/tips.d.ts +2 -0
- package/dist/plugins/video.d.ts +7 -0
- package/dist/react/MarkdownEditor.d.ts +3 -3
- package/dist/react.mjs +70 -68
- package/dist/style.css +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
1
|
# @powerduck/md-editor
|
|
2
2
|
|
|
3
|
-
High-performance embeddable Markdown editor built on the markdown-it ecosystem. Supports KaTeX math formulas, Markmap mindmaps, 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
|
+
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.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Markdown editing** powered by CodeMirror 6 with markdown syntax highlighting
|
|
8
|
-
- **Math formulas** via KaTeX (`$E=mc^2$` inline, `$$...$$` block)
|
|
8
|
+
- **Math formulas** via self-contained KaTeX plugin (`$E=mc^2$` inline, `$$...$$` block) -- no texmath dependency, no double-rendering
|
|
9
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
|
|
10
20
|
- **Block-level incremental rendering** -- only changed sections re-render
|
|
11
21
|
- **Adaptive debounce** -- preview render delay scales with document length
|
|
12
22
|
- **Simple / Complex modes** -- toggle toolbar and status bar at runtime
|
|
13
23
|
- **Light / Dark themes** -- CSS custom properties, inherits host design tokens
|
|
14
24
|
- **React component** -- `forwardRef` with imperative handle
|
|
25
|
+
- **Zero Chinese** -- all code, comments, and UI strings in American English
|
|
15
26
|
|
|
16
27
|
## Installation
|
|
17
28
|
|
|
@@ -65,7 +76,11 @@ function App() {
|
|
|
65
76
|
| `theme` | `'light' \| 'dark'` | `'light'` | Color theme |
|
|
66
77
|
| `math` | `boolean` | `true` | Enable KaTeX math |
|
|
67
78
|
| `mindmap` | `boolean` | `true` | Enable Markmap mindmaps |
|
|
79
|
+
| `codeHighlight` | `boolean` | `true` | Enable highlight.js code blocks with copy button |
|
|
80
|
+
| `tips` | `boolean` | `true` | Enable admonition/tip blocks (:::notice, :::warning, etc.) |
|
|
68
81
|
| `preview` | `boolean` | `true` | Show preview pane |
|
|
82
|
+
| `toolbar` | `ToolbarConfig` | all items | Configure which toolbar items show, their labels and icons |
|
|
83
|
+
| `onImageUpload` | `(file: File) => Promise<string>` | - | Image upload hook for paste/drop |
|
|
69
84
|
| `autoPreview` | `boolean` | `true` | Auto-render preview on edit |
|
|
70
85
|
| `renderDebounce` | `number \| false` | adaptive | Preview debounce in ms |
|
|
71
86
|
| `onChange` | `(value: string) => void` | - | Change callback |
|
|
@@ -95,6 +110,123 @@ function App() {
|
|
|
95
110
|
```
|
|
96
111
|
````
|
|
97
112
|
|
|
113
|
+
## Code Blocks
|
|
114
|
+
|
|
115
|
+
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.
|
|
116
|
+
|
|
117
|
+
````markdown
|
|
118
|
+
```typescript
|
|
119
|
+
interface User {
|
|
120
|
+
name: string;
|
|
121
|
+
age: number;
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
````
|
|
125
|
+
|
|
126
|
+
Unknown languages are auto-detected; if detection fails, the content is HTML-escaped and displayed as plain text. Disable code highlighting with `codeHighlight: false`.
|
|
127
|
+
|
|
128
|
+
## Media Insertion
|
|
129
|
+
|
|
130
|
+
The complex-mode toolbar includes popup dialogs for inserting media:
|
|
131
|
+
|
|
132
|
+
- **Image** (`image` button): URL + alt text -> ``
|
|
133
|
+
- **Video** (`video` button): URL (.mp4, .webm, .ogg) -> renders as `<video controls>` in preview
|
|
134
|
+
- **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
|
|
135
|
+
|
|
136
|
+
YouTube insertion extracts the video ID automatically and produces:
|
|
137
|
+
```markdown
|
|
138
|
+
[](https://www.youtube.com/watch?v=VIDEO_ID)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
## Standalone Renderer
|
|
142
|
+
|
|
143
|
+
Use `renderMarkdown()` to render markdown with the same styling and plugins as the editor preview, without mounting an editor:
|
|
144
|
+
|
|
145
|
+
```ts
|
|
146
|
+
import { renderMarkdown } from '@powerduck/md-editor';
|
|
147
|
+
import '@powerduck/md-editor/dist/style.css';
|
|
148
|
+
|
|
149
|
+
const html = renderMarkdown('# Hello\n\n$E=mc^2$\n\n:::tip\nWorks!\n:::');
|
|
150
|
+
container.innerHTML = html;
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
Options: `math`, `mindmap`, `codeHighlight`, `tips`, `html`, `breaks` -- all default to `true` except `html` and `breaks`.
|
|
154
|
+
|
|
155
|
+
## Keyboard Shortcuts
|
|
156
|
+
|
|
157
|
+
| Shortcut | Action |
|
|
158
|
+
|----------|--------|
|
|
159
|
+
| `Ctrl+B` / `Cmd+B` | Bold |
|
|
160
|
+
| `Ctrl+I` / `Cmd+I` | Italic |
|
|
161
|
+
| `Ctrl+Alt+1` | Heading |
|
|
162
|
+
| `Ctrl+K` / `Cmd+K` | Insert link |
|
|
163
|
+
| `Ctrl+Alt+C` | Code block |
|
|
164
|
+
| `Ctrl+Shift+.` | Blockquote |
|
|
165
|
+
| `Ctrl+Shift+8` | Unordered list |
|
|
166
|
+
| `Ctrl+Shift+7` | Ordered list |
|
|
167
|
+
| `Ctrl+Alt+M` | Math formula |
|
|
168
|
+
| `Ctrl+Alt+P` | Toggle preview |
|
|
169
|
+
| `Ctrl+Shift+L` | Toggle theme |
|
|
170
|
+
|
|
171
|
+
Click the **Help** (?) button in the toolbar to see all shortcuts at runtime.
|
|
172
|
+
|
|
173
|
+
## Configurable Toolbar
|
|
174
|
+
|
|
175
|
+
Control which buttons appear and customize their labels/icons:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
// Only show specific buttons
|
|
179
|
+
new MarkdownEditor('#editor', {
|
|
180
|
+
mode: 'complex',
|
|
181
|
+
toolbar: ['bold', 'italic', 'link', 'code']
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Fine-grained control
|
|
185
|
+
new MarkdownEditor('#editor', {
|
|
186
|
+
mode: 'complex',
|
|
187
|
+
toolbar: {
|
|
188
|
+
bold: { label: 'Make bold', icon: '<b>B</b>' },
|
|
189
|
+
image: { show: false },
|
|
190
|
+
youtube: { show: false }
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Image Upload
|
|
196
|
+
|
|
197
|
+
Provide an upload hook to handle pasted/dropped images:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
new MarkdownEditor('#editor', {
|
|
201
|
+
mode: 'complex',
|
|
202
|
+
onImageUpload: async (file) => {
|
|
203
|
+
const formData = new FormData();
|
|
204
|
+
formData.append('file', file);
|
|
205
|
+
const res = await fetch('/api/upload', { method: 'POST', body: formData });
|
|
206
|
+
const { url } = await res.json();
|
|
207
|
+
return url; // inserted as 
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
## Admonition Blocks
|
|
213
|
+
|
|
214
|
+
```markdown
|
|
215
|
+
:::tip Pro tip
|
|
216
|
+
Use admonition blocks for callouts.
|
|
217
|
+
:::
|
|
218
|
+
|
|
219
|
+
:::warning
|
|
220
|
+
This action cannot be undone.
|
|
221
|
+
:::
|
|
222
|
+
|
|
223
|
+
:::danger
|
|
224
|
+
Destructive operation.
|
|
225
|
+
:::
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Supported types: `notice`, `info`, `tip`, `success`, `warning`, `danger`.
|
|
229
|
+
|
|
98
230
|
## Performance
|
|
99
231
|
|
|
100
232
|
- **Block splitting**: documents are split at ATX headings (`#` through `######`). Content inside code fences is never split.
|
package/dist/Editor.d.ts
CHANGED
|
@@ -5,15 +5,35 @@ export interface CodeEditorOptions {
|
|
|
5
5
|
/** Show line numbers. Off in simple mode, on in complex mode by default. */
|
|
6
6
|
lineNumbers?: boolean;
|
|
7
7
|
placeholder?: string;
|
|
8
|
+
/** Called when an image file is pasted or dropped into the editor. */
|
|
9
|
+
onImageFile?: (file: File) => void;
|
|
8
10
|
}
|
|
9
11
|
export declare class CodeEditor {
|
|
10
12
|
readonly view: EditorView;
|
|
11
13
|
private lineNumbersCompartment;
|
|
14
|
+
private customKeymapCompartment;
|
|
15
|
+
private onImageFile?;
|
|
12
16
|
constructor(container: HTMLElement, options: CodeEditorOptions);
|
|
17
|
+
private handlePaste;
|
|
18
|
+
private handleDrop;
|
|
19
|
+
/**
|
|
20
|
+
* Register custom keyboard shortcuts. Each entry is a CodeMirror keymap
|
|
21
|
+
* spec: { key: 'Mod-b', run: (view) => boolean }.
|
|
22
|
+
*/
|
|
23
|
+
setKeymap(bindings: Array<{
|
|
24
|
+
key: string;
|
|
25
|
+
run: (view: EditorView) => boolean;
|
|
26
|
+
}>): void;
|
|
13
27
|
getValue(): string;
|
|
14
28
|
setValue(value: string): void;
|
|
15
29
|
setLineNumbers(enabled: boolean): void;
|
|
16
30
|
insertAtCursor(text: string): void;
|
|
31
|
+
/**
|
|
32
|
+
* Wrap the current selection with prefix and suffix. If nothing is
|
|
33
|
+
* selected, insert prefix + placeholder + suffix and select the placeholder.
|
|
34
|
+
*/
|
|
35
|
+
wrapSelection(prefix: string, suffix: string, placeholder: string): void;
|
|
36
|
+
getSelection(): string;
|
|
17
37
|
focus(): void;
|
|
18
38
|
destroy(): void;
|
|
19
39
|
}
|
package/dist/Renderer.d.ts
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import MarkdownIt from 'markdown-it';
|
|
2
|
+
import 'github-markdown-css/github-markdown.css';
|
|
2
3
|
export interface RendererOptions {
|
|
3
4
|
/** Enable KaTeX math rendering. Default: true. */
|
|
4
5
|
math?: boolean;
|
|
5
6
|
/** Enable Markmap mindmap rendering. Default: true. */
|
|
6
7
|
mindmap?: boolean;
|
|
8
|
+
/** Enable syntax highlighting for code blocks. Default: true. */
|
|
9
|
+
codeHighlight?: boolean;
|
|
10
|
+
/** Enable admonition/tip blocks (:::notice, :::warning, etc.). Default: true. */
|
|
11
|
+
tips?: boolean;
|
|
7
12
|
/** Allow raw HTML in markdown source. Default: false (safer). */
|
|
8
13
|
html?: boolean;
|
|
9
14
|
/** Convert soft line breaks to <br>. Default: false. */
|
|
@@ -20,3 +25,18 @@ export declare class Renderer {
|
|
|
20
25
|
*/
|
|
21
26
|
hydrate(container: HTMLElement): Promise<void>;
|
|
22
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Standalone markdown rendering function with the same styling and plugins
|
|
30
|
+
* as the editor preview. Use this in other parts of your app to render
|
|
31
|
+
* markdown consistently without mounting an editor.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* import { renderMarkdown } from '@powerduck/md-editor';
|
|
36
|
+
* import '@powerduck/md-editor/dist/style.css';
|
|
37
|
+
*
|
|
38
|
+
* const html = renderMarkdown('# Hello\n\n$E=mc^2$');
|
|
39
|
+
* container.innerHTML = html;
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare function renderMarkdown(source: string, options?: RendererOptions): string;
|
package/dist/Toolbar.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export interface ToolbarAction {
|
|
|
3
3
|
title: string;
|
|
4
4
|
/** SVG/HTML icon markup */
|
|
5
5
|
icon: string;
|
|
6
|
-
handler: () => void;
|
|
6
|
+
handler: (button: HTMLButtonElement) => void;
|
|
7
7
|
/** Append a group separator after this button */
|
|
8
8
|
groupEnd?: boolean;
|
|
9
9
|
/** Whether this is a toggle button (e.g. preview visibility, theme) */
|
package/dist/icons.d.ts
CHANGED
|
@@ -11,5 +11,13 @@ export declare const icons: {
|
|
|
11
11
|
readonly refresh: string;
|
|
12
12
|
readonly moon: string;
|
|
13
13
|
readonly sun: string;
|
|
14
|
+
readonly image: string;
|
|
15
|
+
readonly video: string;
|
|
16
|
+
readonly youtube: string;
|
|
17
|
+
readonly quote: string;
|
|
18
|
+
readonly list: string;
|
|
19
|
+
readonly listOrdered: string;
|
|
20
|
+
readonly hr: string;
|
|
21
|
+
readonly help: string;
|
|
14
22
|
};
|
|
15
23
|
export type IconName = keyof typeof icons;
|