@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.
- package/README.md +103 -19
- package/package.json +5 -2
package/README.md
CHANGED
|
@@ -1,19 +1,25 @@
|
|
|
1
|
-
|
|
1
|
+
# @mdaemon/html-editor-react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@mdaemon/html-editor-react)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
[](https://nodejs.org)
|
|
6
|
+
[](https://packagephobia.com/result?p=@mdaemon/html-editor-react)
|
|
7
|
+
[](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
|
-
##
|
|
13
|
+
## Install
|
|
8
14
|
|
|
9
15
|
```bash
|
|
10
|
-
npm install @mdaemon/html-editor-react
|
|
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.
|
|
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 — 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 — 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>` — 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 — a `<div> </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 — 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 — fired with
|
|
502
|
+
the new boolean, and only when it actually changes — 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`) —
|
|
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
|
-
```
|
|
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 — 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 — inserts speech at the cursor (requires `speech_to_text` + browser support) |
|
|
@@ -807,16 +883,6 @@ Key differences:
|
|
|
807
883
|
- `plugins` option is not needed — 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
|
|
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.
|
|
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.
|
|
59
|
+
"@mdaemon/html-editor": "^1.13.0",
|
|
57
60
|
"@tiptap/react": "^3.31.3"
|
|
58
61
|
},
|
|
59
62
|
"devDependencies": {
|