@powerduck/md-editor 0.3.0 → 0.6.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
@@ -1,17 +1,22 @@
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, highlight.js code blocks with traffic-light UI and copy button, github-markdown-css preview styling, rich toolbar with image/video/YouTube popup dialogs, 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
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
11
12
  - **github-markdown-css** preview -- proper heading, list, table, and typography styling
12
- - **Rich toolbar** -- heading, bold, italic, link, image, video, YouTube, quote, lists, code, table, math, mindmap, horizontal rule, preview toggle, theme toggle
13
- - **Popup dialogs** -- image URL + alt text, video URL, YouTube URL/ID extraction
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
14
18
  - **Video rendering** -- `.mp4`, `.webm`, `.ogg` links render as `<video>` elements
19
+ - **Standalone renderer** -- `renderMarkdown(source, options)` for consistent styling outside the editor
15
20
  - **Block-level incremental rendering** -- only changed sections re-render
16
21
  - **Adaptive debounce** -- preview render delay scales with document length
17
22
  - **Simple / Complex modes** -- toggle toolbar and status bar at runtime
@@ -72,7 +77,10 @@ function App() {
72
77
  | `math` | `boolean` | `true` | Enable KaTeX math |
73
78
  | `mindmap` | `boolean` | `true` | Enable Markmap mindmaps |
74
79
  | `codeHighlight` | `boolean` | `true` | Enable highlight.js code blocks with copy button |
80
+ | `tips` | `boolean` | `true` | Enable admonition/tip blocks (:::notice, :::warning, etc.) |
75
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 |
76
84
  | `autoPreview` | `boolean` | `true` | Auto-render preview on edit |
77
85
  | `renderDebounce` | `number \| false` | adaptive | Preview debounce in ms |
78
86
  | `onChange` | `(value: string) => void` | - | Change callback |
@@ -130,6 +138,95 @@ YouTube insertion extracts the video ID automatically and produces:
130
138
  [![YouTube video](https://img.youtube.com/vi/VIDEO_ID/hqdefault.jpg)](https://www.youtube.com/watch?v=VIDEO_ID)
131
139
  ```
132
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 ![filename](url)
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
+
133
230
  ## Performance
134
231
 
135
232
  - **Block splitting**: documents are split at ATX headings (`#` through `######`). Content inside code fences is never split.
@@ -148,6 +245,31 @@ npm test # run all tests (vitest + jsdom)
148
245
  npm run build # vite build + d.ts generation
149
246
  ```
150
247
 
248
+ ## Changelog
249
+
250
+ ### v0.5.0
251
+
252
+ - **Fixed**: Admonition `:::` closing marker no longer leaks into rendered body content.
253
+ - **Fixed**: Quote, unordered list, and ordered list toolbar actions now wrap selected text (or the current line) instead of replacing it.
254
+ - **Improved**: Tip/admonition toolbar button now opens a type-picker popup with all six styles (notice, info, tip, success, warning, danger).
255
+ - **Improved**: Help dialog now displays keyboard shortcuts with styled key caps and modifier-key symbols (⌘, ⌥, ⇧).
256
+ - **Improved**: All toolbar icons redesigned in a clean Lucide/Feather line style for a modern Western aesthetic.
257
+ - **Fixed**: Mindmap `transform: translate(NaN,NaN)` error guarded when SVG has zero layout size.
258
+ - **Added**: `formatShortcutHtml()` export for rendering styled key caps.
259
+ - **Test**: 251 tests, all passing.
260
+
261
+ ### v0.4.0
262
+
263
+ - Self-contained KaTeX math plugin (removed `markdown-it-texmath`); currency `$5` no longer misparsed.
264
+ - Image upload hook `onImageUpload(file)` with paste/drag support.
265
+ - 11 keyboard shortcuts with macOS Cmd auto-mapping.
266
+ - Help dialog listing all shortcuts.
267
+ - Table rows/columns popup dialog.
268
+ - Theme toggle fixed for dark mode with github-markdown-css.
269
+ - Admonition/tip blocks (`:::notice`, `:::warning`, etc.).
270
+ - Configurable toolbar (include-list or per-item show/label/icon).
271
+ - Standalone `renderMarkdown(source, options)` API export.
272
+
151
273
  ## License
152
274
 
153
275
  MIT
package/dist/Editor.d.ts CHANGED
@@ -5,15 +5,41 @@ 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;
37
+ /**
38
+ * Prefix each line of the current selection (or current line if no
39
+ * selection) with the given prefix. Used for blockquote, unordered list,
40
+ * ordered list, etc. If nothing is selected, inserts prefix + placeholder.
41
+ */
42
+ wrapLines(prefix: string, placeholder: string): void;
17
43
  focus(): void;
18
44
  destroy(): void;
19
45
  }
@@ -1,5 +1,5 @@
1
- import MarkdownIt from 'markdown-it';
2
- import 'github-markdown-css/github-markdown.css';
1
+ import type { MarkdownIt } from "markdown-it";
2
+ import "github-markdown-css/github-markdown.css";
3
3
  export interface RendererOptions {
4
4
  /** Enable KaTeX math rendering. Default: true. */
5
5
  math?: boolean;
@@ -7,6 +7,8 @@ export interface RendererOptions {
7
7
  mindmap?: boolean;
8
8
  /** Enable syntax highlighting for code blocks. Default: true. */
9
9
  codeHighlight?: boolean;
10
+ /** Enable admonition/tip blocks (:::notice, :::warning, etc.). Default: true. */
11
+ tips?: boolean;
10
12
  /** Allow raw HTML in markdown source. Default: false (safer). */
11
13
  html?: boolean;
12
14
  /** Convert soft line breaks to <br>. Default: false. */
@@ -23,3 +25,18 @@ export declare class Renderer {
23
25
  */
24
26
  hydrate(container: HTMLElement): Promise<void>;
25
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/icons.d.ts CHANGED
@@ -4,19 +4,21 @@ export declare const icons: {
4
4
  readonly heading: string;
5
5
  readonly link: string;
6
6
  readonly code: string;
7
- readonly table: string;
8
- readonly sigma: string;
9
- readonly mindmap: string;
10
- readonly eye: string;
11
- readonly refresh: string;
12
- readonly moon: string;
13
- readonly sun: string;
14
7
  readonly image: string;
15
8
  readonly video: string;
16
9
  readonly youtube: string;
17
10
  readonly quote: string;
18
11
  readonly list: string;
19
12
  readonly listOrdered: string;
13
+ readonly table: string;
20
14
  readonly hr: string;
15
+ readonly alert: string;
16
+ readonly sigma: string;
17
+ readonly mindmap: string;
18
+ readonly eye: string;
19
+ readonly help: string;
20
+ readonly moon: string;
21
+ readonly sun: string;
22
+ readonly refresh: string;
21
23
  };
22
24
  export type IconName = keyof typeof icons;