@mdaemon/html-editor-react 1.8.3 → 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.
Files changed (2) hide show
  1. package/README.md +103 -19
  2. package/package.json +5 -2
package/README.md CHANGED
@@ -1,19 +1,25 @@
1
- [![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fmdaemon-technologies%2FMDHTMLEditor-react%2Fmaster%2Fpackage.json&query=%24.version&prefix=v&label=npm&color=blue)](https://www.npmjs.com/package/@mdaemon/html-editor-react) [![install size](https://packagephobia.com/badge?p=@mdaemon/html-editor-react)](https://packagephobia.com/result?p=@mdaemon/html-editor-react) [![Dynamic JSON Badge](https://img.shields.io/badge/dynamic/json?url=https%3A%2F%2Fraw.githubusercontent.com%2Fmdaemon-technologies%2FMDHTMLEditor-react%2Fmaster%2Fpackage.json&query=%24.license&prefix=v&label=license&color=green)](https://github.com/mdaemon-technologies/MDHTMLEditor-react/blob/master/LICENSE) [![Node.js CI](https://github.com/mdaemon-technologies/MDHTMLEditor-react/actions/workflows/ci.yml/badge.svg)](https://github.com/mdaemon-technologies/MDHTMLEditor-react/actions/workflows/ci.yml)
1
+ # @mdaemon/html-editor-react
2
2
 
3
- # MDHTMLEditor React
3
+ [![npm](https://img.shields.io/npm/v/@mdaemon/html-editor-react?color=blue)](https://www.npmjs.com/package/@mdaemon/html-editor-react)
4
+ [![license](https://img.shields.io/npm/l/@mdaemon/html-editor-react?color=green)](LICENSE)
5
+ [![node](https://img.shields.io/node/v/@mdaemon/html-editor-react)](https://nodejs.org)
6
+ [![install size](https://packagephobia.com/badge?p=@mdaemon/html-editor-react)](https://packagephobia.com/result?p=@mdaemon/html-editor-react)
7
+ [![CI](https://github.com/mdaemon-technologies/MDHTMLEditor-react/actions/workflows/ci.yml/badge.svg)](https://github.com/mdaemon-technologies/MDHTMLEditor-react/actions/workflows/ci.yml)
8
+
9
+ React wrapper for MDHTMLEditor
4
10
 
5
11
  A React wrapper for [MDHTMLEditor](https://github.com/mdaemon-technologies/MDHTMLEditor) — a WYSIWYG HTML editor built on TipTap. Provides a drop-in replacement for `@tinymce/tinymce-react` with no license key required.
6
12
 
7
- ## Installation
13
+ ## Install
8
14
 
9
15
  ```bash
10
- npm install @mdaemon/html-editor-react @mdaemon/html-editor
16
+ npm install @mdaemon/html-editor-react
11
17
  ```
12
18
 
13
19
  **Peer dependencies:** `react` and `react-dom` (v18 or v19).
14
20
 
15
21
  **TipTap:** the editor is built on TipTap 3, and this package tracks the same version the
16
- engine uses — currently **3.31.3** (`@mdaemon/html-editor` `^1.12.3`,
22
+ engine uses — currently **3.31.3** (`@mdaemon/html-editor` `^1.13.0`,
17
23
  `@tiptap/react` `^3.31.3`). If your app depends on any `@tiptap/*` package directly, keep
18
24
  it on that version too: ProseMirror throws at runtime if two copies of `@tiptap/core` /
19
25
  `@tiptap/pm` end up in the bundle. If you only use `<Editor>` or `useEditor`, there is
@@ -260,6 +266,7 @@ The `config` prop (or `useEditor`'s `config` option) accepts an `EditorConfig` o
260
266
  | `browser_spellcheck` | `boolean` | `true` | Enable browser spell check. |
261
267
  | `entity_encoding` | `'raw' \| 'named' \| 'numeric'` | `'raw'` | HTML entity encoding mode. |
262
268
  | `paste_from_office` | `boolean` | `true` | Clean and preserve formatting when pasting from Microsoft Word/Excel. Pasted list indentation is normalized either way &mdash; see [Lists & Indentation](#lists--indentation). |
269
+ | `paste_markdown` | `boolean` | `false` | Start with paste-as-Markdown on, so a paste is read as Markdown and inserted as real formatting. Toggle at runtime via `getEditor()?.setPasteMarkdown()` or the `pastemarkdown` toolbar button &mdash; see [Pasting Markdown](#pasting-markdown). |
263
270
  | `speech_to_text` | `boolean` | `true` | Enable the `speechtotext` and `dictate` toolbar buttons (requires the Web Speech API). |
264
271
  | `convert_unsafe_embeds` | `boolean` | `true` | Sanitize embedded content. |
265
272
  | `format_empty_lines` | `boolean` | `true` | Preserve blank lines outside the editor. On the way out (`getContent()`, the `onChange` payload, preview, and the source dialog) each empty block is filled with a `<br>` &mdash; bare empty blocks otherwise collapse to zero height in mail clients; on the way in (`setContent()`, `insertContent()`, templates) it is stripped back out, so `setContent(getContent(x))` is stable across round-trips. A block is only "empty" if it has no visible content &mdash; a `<div>&nbsp;</div>` spacer counts as content and is left alone. Set `false` to pass content through unchanged in both directions. |
@@ -455,6 +462,74 @@ Lists pasted from Word, Outlook, Google Docs, another editor, or a web page are
455
462
 
456
463
  Word/Excel cleaning as a whole can be turned off with [`paste_from_office: false`](#configuration); list indentation is normalized either way.
457
464
 
465
+ ## Pasting Markdown
466
+
467
+ Chat apps, AI assistants and README files hand out Markdown, which by default pastes in as
468
+ the raw `#`, `*` and `|` characters. The editor's **Paste Markdown** mode reads a paste
469
+ as Markdown and inserts it as real formatting: headings, bold, italic, strikethrough, inline
470
+ code, links, images, bullet/ordered/nested lists, blockquotes, horizontal rules, fenced code
471
+ blocks with their language, and GFM tables.
472
+
473
+ The mode is **off by default** and, like TinyMCE's *Paste as text*, stays on once turned on
474
+ until it is turned off again. It is per editor instance and the editor does not persist it.
475
+
476
+ Turn it on at init with the `paste_markdown` config option, or at runtime through the raw
477
+ editor instance:
478
+
479
+ ```tsx
480
+ <Editor config={{ paste_markdown: true }} />
481
+
482
+ // At runtime
483
+ editorRef.current?.getEditor()?.setPasteMarkdown(true);
484
+ const on = editorRef.current?.getEditor()?.isPasteMarkdownEnabled();
485
+
486
+ // Or toggle it the TinyMCE way
487
+ editorRef.current?.getEditor()?.execCommand('mceTogglePasteMarkdown');
488
+ ```
489
+
490
+ The `pastemarkdown` toolbar button lets the user toggle the mode. It is deliberately **not**
491
+ in any default toolbar, so no existing layout changes &mdash; add it to a `toolbar` string
492
+ to offer it:
493
+
494
+ ```tsx
495
+ <Editor config={{ toolbar: 'bold italic | copy cut paste pastemarkdown | undo redo' }} />
496
+ ```
497
+
498
+ While the mode is on the button shows the active background, a dot badge and
499
+ `aria-pressed="true"`, and the toolbar's `paste` button converts as well.
500
+
501
+ To remember the user's choice, listen for the `pastemarkdownchange` event &mdash; fired with
502
+ the new boolean, and only when it actually changes &mdash; and pass the saved value back as
503
+ `paste_markdown` next time:
504
+
505
+ ```tsx
506
+ <Editor
507
+ config={{ paste_markdown: savedPreference }}
508
+ onInit={(editor) => {
509
+ editor.on('pastemarkdownchange', (enabled) => savePreference(enabled));
510
+ }}
511
+ />
512
+ ```
513
+
514
+ A few things worth knowing:
515
+
516
+ - **A single newline is a line break**, not a continuation of the paragraph, because chat and
517
+ assistant output is written that way. A blank line still starts a new paragraph.
518
+ - **Task lists paste as plain bullets** (`- [ ] item` becomes a bullet reading `item`) &mdash;
519
+ the editor has no checkbox node.
520
+ - While the mode is on the clipboard's `text/plain` is used and its `text/html` ignored, so
521
+ syntax-highlighted HTML copied from a code editor does not paste as coloured code. Markdown
522
+ mode also takes precedence over the built-in code-block paste for clipboards that VS Code
523
+ (and editors that copy the way it does) mark as code.
524
+ - Pastes that carry files (images), Markdown pasted inside a code block, and drag-and-drop are
525
+ never converted. A URL pasted over a selection still becomes a link either way.
526
+ - **Pasted Markdown cannot run script.** Raw HTML inside the Markdown is escaped to visible
527
+ text, the converted HTML is sanitized in an inert document before it reaches ProseMirror,
528
+ and links are limited to the schemes TipTap allows.
529
+ - Conversion runs on a budget so a crafted paste cannot freeze the tab: input over 256 KB, any
530
+ single paragraph, heading, list item or table cell over 5,000 characters, or a parse that
531
+ takes longer than 750 ms is abandoned and the text goes in as an ordinary paste instead.
532
+
458
533
  ## Templates
459
534
 
460
535
  Enable the template dropdown and provide a `templates` array:
@@ -484,7 +559,7 @@ const templates: Template[] = [
484
559
 
485
560
  The `Template` interface:
486
561
 
487
- ```typescript
562
+ ```ts
488
563
  interface Template {
489
564
  id?: number | string;
490
565
  title: string;
@@ -606,7 +681,8 @@ Buttons after `||` begin collapsed behind a toggle (`...`) button.
606
681
  | `removeformat` | Strip all formatting |
607
682
  | `copy` | Copy selection |
608
683
  | `cut` | Cut selection |
609
- | `paste` | Paste from clipboard |
684
+ | `paste` | Paste from clipboard (follows the paste-as-Markdown mode) |
685
+ | `pastemarkdown` | Toggle paste-as-Markdown mode &mdash; not in any default toolbar (see [Pasting Markdown](#pasting-markdown)) |
610
686
  | `undo` | Undo |
611
687
  | `redo` | Redo |
612
688
  | `image` | Insert image (upload or URL) |
@@ -620,7 +696,7 @@ Buttons after `||` begin collapsed behind a toggle (`...`) button.
620
696
  | `anchor` | Insert a named anchor (`<a id>` target) |
621
697
  | `codesample` | Toggle code sample |
622
698
  | `fullscreen` | Toggle fullscreen |
623
- | `preview` | Preview in new window |
699
+ | `preview` | Preview in new window (the window carries a Content Security Policy that blocks script) |
624
700
  | `searchreplace` | Find & Replace dialog |
625
701
  | `speechtotext` | Open Speech to Text dialog (requires `speech_to_text` + browser support) |
626
702
  | `dictate` | Toggle inline dictation &mdash; inserts speech at the cursor (requires `speech_to_text` + browser support) |
@@ -807,16 +883,6 @@ Key differences:
807
883
  - `plugins` option is not needed &mdash; all features are built in
808
884
  - Toolbar customization uses `basicEditor: true/false` or a `toolbar` string
809
885
 
810
- ## Running the Demo
811
-
812
- A demo app is included to see the editor in action:
813
-
814
- ```bash
815
- npm run demo
816
- ```
817
-
818
- This starts a Vite dev server at `http://localhost:5173` with three sections: the `<Editor>` component, the `useEditor` hook, and a [Fonts](#fonts) panel with a live `getFontFamily()` / `getFontSize()` readout that follows the cursor and buttons for the block-font commands.
819
-
820
886
  ## Development
821
887
 
822
888
  The package is bundled with [Vite 8](https://vite.dev/) (Rolldown) and ships ES, CommonJS, and TypeScript declaration outputs.
@@ -836,6 +902,24 @@ The package is bundled with [Vite 8](https://vite.dev/) (Rolldown) and ships ES,
836
902
 
837
903
  Lint, typecheck, and tests run automatically in [CI](.github/workflows/ci.yml) on every push and pull request to `master` across Node 20, 22, 24, and 26.
838
904
 
905
+ ### Running the Demo
906
+
907
+ A demo app is included to see the editor in action:
908
+
909
+ ```bash
910
+ npm run demo
911
+ ```
912
+
913
+ This starts a Vite dev server at `http://localhost:5173` with three sections: the `<Editor>` component, the `useEditor` hook, and a [Fonts](#fonts) panel with a live `getFontFamily()` / `getFontSize()` readout that follows the cursor and buttons for the block-font commands.
914
+
915
+ ## Changelog
916
+
917
+ See [CHANGELOG.md](CHANGELOG.md).
918
+
839
919
  ## License
840
920
 
841
- LGPL-3.0-or-later &mdash; [MDaemon Technologies, Ltd.](https://www.mdaemon.com)
921
+ Published under the [LGPL-3.0-or-later](LICENSE) license.
922
+
923
+ Published by **MDaemon Technologies, Ltd.**
924
+ Simple Secure Email
925
+ [https://www.mdaemon.com](https://www.mdaemon.com)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mdaemon/html-editor-react",
3
- "version": "1.8.3",
3
+ "version": "1.9.0",
4
4
  "description": "React wrapper for MDHTMLEditor",
5
5
  "homepage": "https://github.com/mdaemon-technologies/MDHTMLEditor-react",
6
6
  "repository": {
@@ -48,12 +48,15 @@
48
48
  "url": "https://www.mdaemon.com"
49
49
  },
50
50
  "license": "LGPL-3.0-or-later",
51
+ "engines": {
52
+ "node": ">=20"
53
+ },
51
54
  "peerDependencies": {
52
55
  "react": "^19.0.0 || ^18.0.0",
53
56
  "react-dom": "^19.0.0 || ^18.0.0"
54
57
  },
55
58
  "dependencies": {
56
- "@mdaemon/html-editor": "^1.12.3",
59
+ "@mdaemon/html-editor": "^1.13.0",
57
60
  "@tiptap/react": "^3.31.3"
58
61
  },
59
62
  "devDependencies": {