@richscripts/richtexteditor 2.14.1 → 2.16.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 +182 -10
- package/angular/build-manifest.json +23 -0
- package/angular/index.d.ts +71 -76
- package/angular/index.mjs +2 -0
- package/angular/package.json +4 -0
- package/headless/index.d.ts +3 -1
- package/headless/index.js +72 -16
- package/index.d.ts +40 -52
- package/integrations/initialization-scope.js +27 -0
- package/integrations/native-mount.js +30 -0
- package/integrations/shared.d.ts +23 -1
- package/integrations/shared.js +68 -22
- package/package.json +25 -3
- package/react/index.js +118 -37
- package/react/index.mjs +29 -0
- package/richtexteditor/all_plugins.js +8816 -2373
- package/richtexteditor/all_plugins.min.js +77 -59
- package/richtexteditor/lang/emoji/LICENSE-CLDR.txt +41 -0
- package/richtexteditor/lang/emoji/rte-emoji-de.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-es.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-fr.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-it.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-ja.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-ko.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-nl.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-pt-pt.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-pt.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-ru.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-zh-Hans.js +3 -0
- package/richtexteditor/lang/emoji/rte-emoji-zh-Hant.js +3 -0
- package/richtexteditor/lang/rte-lang-af.js +1 -0
- package/richtexteditor/lang/rte-lang-ar.js +1 -0
- package/richtexteditor/lang/rte-lang-bg.js +1 -0
- package/richtexteditor/lang/rte-lang-bn.js +1 -0
- package/richtexteditor/lang/rte-lang-bs.js +1 -0
- package/richtexteditor/lang/rte-lang-ca.js +1 -0
- package/richtexteditor/lang/rte-lang-cs.js +1 -0
- package/richtexteditor/lang/rte-lang-cy.js +1 -0
- package/richtexteditor/lang/rte-lang-da.js +1 -0
- package/richtexteditor/lang/rte-lang-de.js +1050 -2
- package/richtexteditor/lang/rte-lang-el.js +1 -0
- package/richtexteditor/lang/rte-lang-en.js +1 -0
- package/richtexteditor/lang/rte-lang-es.js +1056 -2
- package/richtexteditor/lang/rte-lang-et.js +1 -0
- package/richtexteditor/lang/rte-lang-fa.js +1 -0
- package/richtexteditor/lang/rte-lang-fi.js +1 -0
- package/richtexteditor/lang/rte-lang-fil.js +1 -0
- package/richtexteditor/lang/rte-lang-fj.js +1 -0
- package/richtexteditor/lang/rte-lang-fr.js +1056 -2
- package/richtexteditor/lang/rte-lang-ga.js +1 -0
- package/richtexteditor/lang/rte-lang-gu.js +1 -0
- package/richtexteditor/lang/rte-lang-he.js +1 -0
- package/richtexteditor/lang/rte-lang-hi.js +1 -0
- package/richtexteditor/lang/rte-lang-hr.js +1 -0
- package/richtexteditor/lang/rte-lang-ht.js +1 -0
- package/richtexteditor/lang/rte-lang-hu.js +1 -0
- package/richtexteditor/lang/rte-lang-id.js +1 -0
- package/richtexteditor/lang/rte-lang-is.js +1 -0
- package/richtexteditor/lang/rte-lang-it.js +1056 -2
- package/richtexteditor/lang/rte-lang-ja.js +1056 -2
- package/richtexteditor/lang/rte-lang-kn.js +1 -0
- package/richtexteditor/lang/rte-lang-ko.js +1056 -2
- package/richtexteditor/lang/rte-lang-lt.js +1 -0
- package/richtexteditor/lang/rte-lang-lv.js +1 -0
- package/richtexteditor/lang/rte-lang-mg.js +1 -0
- package/richtexteditor/lang/rte-lang-mi.js +1 -0
- package/richtexteditor/lang/rte-lang-ml.js +1 -0
- package/richtexteditor/lang/rte-lang-mr.js +1 -0
- package/richtexteditor/lang/rte-lang-ms.js +1 -0
- package/richtexteditor/lang/rte-lang-mt.js +1 -0
- package/richtexteditor/lang/rte-lang-mww.js +1 -0
- package/richtexteditor/lang/rte-lang-nb.js +1 -0
- package/richtexteditor/lang/rte-lang-nl.js +1056 -2
- package/richtexteditor/lang/rte-lang-otq.js +1 -0
- package/richtexteditor/lang/rte-lang-pa.js +1 -0
- package/richtexteditor/lang/rte-lang-pl.js +1 -0
- package/richtexteditor/lang/rte-lang-pt-pt.js +1056 -2
- package/richtexteditor/lang/rte-lang-pt.js +1056 -2
- package/richtexteditor/lang/rte-lang-ro.js +1 -0
- package/richtexteditor/lang/rte-lang-ru.js +1056 -2
- package/richtexteditor/lang/rte-lang-sk.js +1 -0
- package/richtexteditor/lang/rte-lang-sl.js +1 -0
- package/richtexteditor/lang/rte-lang-sm.js +1 -0
- package/richtexteditor/lang/rte-lang-sr-Cyrl.js +1 -0
- package/richtexteditor/lang/rte-lang-sr-Latn.js +1 -0
- package/richtexteditor/lang/rte-lang-sv.js +1 -0
- package/richtexteditor/lang/rte-lang-sw.js +1 -0
- package/richtexteditor/lang/rte-lang-ta.js +1 -0
- package/richtexteditor/lang/rte-lang-te.js +1 -0
- package/richtexteditor/lang/rte-lang-th.js +1 -0
- package/richtexteditor/lang/rte-lang-tlh-Latn.js +1 -0
- package/richtexteditor/lang/rte-lang-tlh-Piqd.js +1 -0
- package/richtexteditor/lang/rte-lang-to.js +1 -0
- package/richtexteditor/lang/rte-lang-tr.js +1 -0
- package/richtexteditor/lang/rte-lang-ty.js +1 -0
- package/richtexteditor/lang/rte-lang-uk.js +1 -0
- package/richtexteditor/lang/rte-lang-ur.js +1 -0
- package/richtexteditor/lang/rte-lang-vi.js +1 -0
- package/richtexteditor/lang/rte-lang-yua.js +1 -0
- package/richtexteditor/lang/rte-lang-zh-Hans.js +1050 -2
- package/richtexteditor/lang/rte-lang-zh-Hant.js +1050 -2
- package/richtexteditor/plugins/a11yenhance.js +4 -1
- package/richtexteditor/plugins/a11yenhance.min.js +1 -1
- package/richtexteditor/plugins/accessibilitychecker.js +256 -64
- package/richtexteditor/plugins/accessibilitychecker.min.js +1 -1
- package/richtexteditor/plugins/aitoolkit.js +1057 -386
- package/richtexteditor/plugins/aitoolkit.min.js +7 -7
- package/richtexteditor/plugins/all_plugins.js +8816 -2373
- package/richtexteditor/plugins/all_plugins.min.js +77 -59
- package/richtexteditor/plugins/autocorrect.js +66 -31
- package/richtexteditor/plugins/autocorrect.min.js +1 -1
- package/richtexteditor/plugins/autoembed.js +18 -1
- package/richtexteditor/plugins/autoembed.min.js +1 -1
- package/richtexteditor/plugins/blocktypes.js +18 -9
- package/richtexteditor/plugins/blocktypes.min.js +1 -1
- package/richtexteditor/plugins/bookmarkcard.js +12 -5
- package/richtexteditor/plugins/bookmarkcard.min.js +2 -2
- package/richtexteditor/plugins/changecase.js +72 -19
- package/richtexteditor/plugins/changecase.min.js +1 -1
- package/richtexteditor/plugins/charlimit.js +62 -2
- package/richtexteditor/plugins/charlimit.min.js +2 -2
- package/richtexteditor/plugins/comments.js +460 -61
- package/richtexteditor/plugins/comments.min.js +4 -3
- package/richtexteditor/plugins/contentminimap.js +28 -9
- package/richtexteditor/plugins/contentminimap.min.js +1 -1
- package/richtexteditor/plugins/crdt-engine.js +27 -1
- package/richtexteditor/plugins/crossreference.js +1 -1
- package/richtexteditor/plugins/crossreference.min.js +1 -1
- package/richtexteditor/plugins/dialoga11y.js +26 -4
- package/richtexteditor/plugins/dialoga11y.min.js +1 -1
- package/richtexteditor/plugins/dictation.js +1 -1
- package/richtexteditor/plugins/documentimport.js +250 -59
- package/richtexteditor/plugins/documentimport.min.js +4 -4
- package/richtexteditor/plugins/documentoutline.js +47 -8
- package/richtexteditor/plugins/documentoutline.min.js +1 -1
- package/richtexteditor/plugins/docxexport.js +233 -32
- package/richtexteditor/plugins/docxexport.min.js +2 -2
- package/richtexteditor/plugins/draghandle.js +267 -3
- package/richtexteditor/plugins/draghandle.min.js +1 -1
- package/richtexteditor/plugins/emailtoolkit.js +28 -14
- package/richtexteditor/plugins/emailtoolkit.min.js +1 -1
- package/richtexteditor/plugins/emojiautocomplete.js +111 -57
- package/richtexteditor/plugins/emojiautocomplete.min.js +1 -1
- package/richtexteditor/plugins/footnotes.js +65 -11
- package/richtexteditor/plugins/footnotes.min.js +1 -1
- package/richtexteditor/plugins/formatpainter.js +10 -0
- package/richtexteditor/plugins/formatpainter.min.js +1 -1
- package/richtexteditor/plugins/formattingmarks.js +6 -6
- package/richtexteditor/plugins/formattingmarks.min.js +1 -1
- package/richtexteditor/plugins/gapcursor.js +60 -0
- package/richtexteditor/plugins/gapcursor.min.js +1 -1
- package/richtexteditor/plugins/ghostcomplete.js +1 -1
- package/richtexteditor/plugins/html2pdf.js +8 -8
- package/richtexteditor/plugins/html2pdf.min.js +1 -1
- package/richtexteditor/plugins/imageeditor.js +31 -12
- package/richtexteditor/plugins/imageeditor.min.js +1 -1
- package/richtexteditor/plugins/importstyles.js +1 -1
- package/richtexteditor/plugins/inlinecode.js +25 -0
- package/richtexteditor/plugins/inlinecode.min.js +1 -1
- package/richtexteditor/plugins/insertcode.js +29 -11
- package/richtexteditor/plugins/insertcode.min.js +6 -6
- package/richtexteditor/plugins/insertemoji.js +113 -16
- package/richtexteditor/plugins/insertemoji.min.js +1 -1
- package/richtexteditor/plugins/insertgallery.js +46 -40
- package/richtexteditor/plugins/insertgallery.min.js +1 -1
- package/richtexteditor/plugins/inserttemplate.js +43 -19
- package/richtexteditor/plugins/inserttemplate.min.js +1 -1
- package/richtexteditor/plugins/keyboarda11y.js +66 -3
- package/richtexteditor/plugins/keyboarda11y.min.js +1 -1
- package/richtexteditor/plugins/layouttable.js +20 -0
- package/richtexteditor/plugins/layouttable.min.js +1 -1
- package/richtexteditor/plugins/linkchecker.js +29 -9
- package/richtexteditor/plugins/linkchecker.min.js +1 -1
- package/richtexteditor/plugins/localdraft.js +51 -7
- package/richtexteditor/plugins/localdraft.min.js +1 -1
- package/richtexteditor/plugins/markdownexport.js +159 -0
- package/richtexteditor/plugins/markdownexport.min.js +2 -2
- package/richtexteditor/plugins/mathdialog.js +11 -5
- package/richtexteditor/plugins/mathdialog.min.js +1 -1
- package/richtexteditor/plugins/mentionplugin.js +90 -27
- package/richtexteditor/plugins/mentionplugin.min.js +1 -1
- package/richtexteditor/plugins/mermaiddiagram.js +14 -8
- package/richtexteditor/plugins/mermaiddiagram.min.js +2 -2
- package/richtexteditor/plugins/multilevellist.js +4 -0
- package/richtexteditor/plugins/multilevellist.min.js +1 -1
- package/richtexteditor/plugins/nodetypes.js +1 -1
- package/richtexteditor/plugins/nodetypes.min.js +1 -1
- package/richtexteditor/plugins/pagination.js +2 -2
- package/richtexteditor/plugins/pagination.min.js +1 -1
- package/richtexteditor/plugins/pdfexport.js +1752 -1167
- package/richtexteditor/plugins/pdfexport.min.js +28 -13
- package/richtexteditor/plugins/permanentpen.js +3 -3
- package/richtexteditor/plugins/permanentpen.min.js +1 -1
- package/richtexteditor/plugins/readabilitystats.js +25 -11
- package/richtexteditor/plugins/readabilitystats.min.js +1 -1
- package/richtexteditor/plugins/readaloud.js +30 -16
- package/richtexteditor/plugins/readaloud.min.js +1 -1
- package/richtexteditor/plugins/restrictedediting.js +166 -0
- package/richtexteditor/plugins/restrictedediting.min.js +2 -2
- package/richtexteditor/plugins/revisionhistory.js +173 -41
- package/richtexteditor/plugins/revisionhistory.min.js +3 -3
- package/richtexteditor/plugins/rubyannotation.js +21 -11
- package/richtexteditor/plugins/rubyannotation.min.js +1 -1
- package/richtexteditor/plugins/sanitizer.js +119 -7
- package/richtexteditor/plugins/sanitizer.min.js +1 -1
- package/richtexteditor/plugins/slashcommand.js +32 -18
- package/richtexteditor/plugins/slashcommand.min.js +2 -2
- package/richtexteditor/plugins/smartchips.js +39 -25
- package/richtexteditor/plugins/smartchips.min.js +2 -2
- package/richtexteditor/plugins/spellcheck.js +20 -11
- package/richtexteditor/plugins/spellcheck.min.js +2 -2
- package/richtexteditor/plugins/stateinspector.js +21 -11
- package/richtexteditor/plugins/stateinspector.min.js +2 -2
- package/richtexteditor/plugins/structured-content-bridge.js +90 -32
- package/richtexteditor/plugins/structured-content-bridge.min.js +8 -8
- package/richtexteditor/plugins/tableofcontents.js +5 -2
- package/richtexteditor/plugins/tableofcontents.min.js +1 -1
- package/richtexteditor/plugins/tabletools.js +388 -3
- package/richtexteditor/plugins/tabletools.min.js +1 -1
- package/richtexteditor/plugins/textdirection.js +19 -6
- package/richtexteditor/plugins/textdirection.min.js +1 -1
- package/richtexteditor/plugins/textpartlanguage.js +161 -32
- package/richtexteditor/plugins/textpartlanguage.min.js +1 -1
- package/richtexteditor/plugins/todolist.js +90 -6
- package/richtexteditor/plugins/todolist.min.js +1 -1
- package/richtexteditor/plugins/trackedchanges.js +1812 -25
- package/richtexteditor/plugins/trackedchanges.min.js +5 -3
- package/richtexteditor/plugins/wordexport.js +2 -2
- package/richtexteditor/plugins/yjscollab.js +11 -6
- package/richtexteditor/plugins/yjscollab.min.js +1 -1
- package/richtexteditor/plugins/zz_richtextbox_dialog_style.js +22 -13
- package/richtexteditor/plugins/zz_richtextbox_dialog_style.min.js +1 -1
- package/richtexteditor/rte-config.js +144 -86
- package/richtexteditor/rte-headless.js +19 -4
- package/richtexteditor/rte-watchdog.js +3 -1
- package/richtexteditor/rte-webcomponent.js +91 -16
- package/richtexteditor/rte.js +146 -88
- package/richtexteditor/runtime/colorpicker_more_ns.htm +3 -1
- package/scripts/build-angular.mjs +97 -0
- package/svelte/index.d.ts +2 -1
- package/svelte/index.js +80 -9
- package/vue/index.js +130 -34
- package/angular/component.ts +0 -297
- package/angular/index.ts +0 -24
package/README.md
CHANGED
|
@@ -60,7 +60,7 @@ A full collaborative-document workspace, not just a textarea replacement:
|
|
|
60
60
|
- **Smart link paste** *(2.2.4)* — pasting a URL or email while text is selected wraps the selection in `<a href>` instead of replacing it. Matches Google Docs / Notion / TipTap / ProseMirror behavior. Opt-out via `smartLinkPaste: false`.
|
|
61
61
|
- **Mobile toolbar mode**, **classic toolbar customization**, **plugins**, **localization**, **image editing**, **PDF export**, **paste-from-Word fidelity**, **find & replace**, **autosave**, **draft recovery**.
|
|
62
62
|
- **Configurable empty-editor placeholders** — set `placeholder`, `placeholderShowOnlyWhenEditable`, and `placeholderColor` to match the guided empty-state UX offered by current Tiptap and TinyMCE setups.
|
|
63
|
-
- **TypeScript declarations** —
|
|
63
|
+
- **TypeScript declarations** — typed editor methods, commands, event handlers, plugin namespaces, and configuration interfaces, with strict integration compilation tests.
|
|
64
64
|
|
|
65
65
|
The structured content bridge now returns a semantic document model while still carrying compatibility HTML and plain text:
|
|
66
66
|
|
|
@@ -196,6 +196,15 @@ const validation = validateStructuredContent(documentModel);
|
|
|
196
196
|
|
|
197
197
|
Use `@richscripts/richtexteditor/server` when you only need conversion and rendering on the server. Use `@richscripts/richtexteditor/integrations/shared` when you also need browser asset loading and editor bootstrapping helpers.
|
|
198
198
|
|
|
199
|
+
Queued accessibility repairs are rechecked against the current document before
|
|
200
|
+
they are applied. If that issue code no longer exists at its node path, the
|
|
201
|
+
helper returns a cloned, normalized current document without replacing newer
|
|
202
|
+
heading text, image descriptions or table-header choices. Repeating an already
|
|
203
|
+
completed repair is also a no-op. Re-run `auditAccessibility` after structural
|
|
204
|
+
edits: issue paths are positions, not persistent node identities, so this check
|
|
205
|
+
cannot distinguish a different node that happens to have the same issue at the
|
|
206
|
+
same path. Use `renderHTML(repairedDocument)` to render the returned model.
|
|
207
|
+
|
|
199
208
|
The same server/shared helpers also expose `getTextStatistics(value)` for consistent word and character counts outside the browser. The React, Vue, and Angular package entry points re-export this same helper family so framework apps can import editor components and document-workflow utilities from one place.
|
|
200
209
|
|
|
201
210
|
## DOCX import
|
|
@@ -214,6 +223,8 @@ Pass `file` to skip the built-in file picker, or use `mode: "insert"` to insert
|
|
|
214
223
|
## React
|
|
215
224
|
|
|
216
225
|
```jsx
|
|
226
|
+
"use client"; // Required for your own state/callback wrapper in Next.js App Router.
|
|
227
|
+
|
|
217
228
|
import { useState } from "react";
|
|
218
229
|
import { RichTextEditorReact } from "@richscripts/richtexteditor/react";
|
|
219
230
|
|
|
@@ -231,6 +242,18 @@ export default function EditorPage() {
|
|
|
231
242
|
}
|
|
232
243
|
```
|
|
233
244
|
|
|
245
|
+
The `/react` ESM entry declares its own client boundary. A Next.js App Router
|
|
246
|
+
Server Component may render `<RichTextEditorReact value="<p>Hello</p>" />` with
|
|
247
|
+
serializable props. Put `useState`, `onChange`, refs and function-valued editor
|
|
248
|
+
configuration in your own `"use client"` wrapper, as above; do not pass ordinary
|
|
249
|
+
callbacks across the server/client boundary. Copy the runtime to `public/richtexteditor`
|
|
250
|
+
as in the installation steps. Server-side HTML/Markdown conversion belongs in
|
|
251
|
+
`@richscripts/richtexteditor/server`, not in the React client entry.
|
|
252
|
+
|
|
253
|
+
CommonJS `require("@richscripts/richtexteditor/react")` remains available with
|
|
254
|
+
the same named API. No `ssr: false` workaround is needed just to render the wrapper;
|
|
255
|
+
the browser-only editor is created after the component mounts.
|
|
256
|
+
|
|
234
257
|
## Vue
|
|
235
258
|
|
|
236
259
|
```js
|
|
@@ -268,7 +291,9 @@ const app = createApp({
|
|
|
268
291
|
|
|
269
292
|
## Angular
|
|
270
293
|
|
|
271
|
-
Angular apps can
|
|
294
|
+
Angular 20.3+ apps can use the packaged standalone wrapper component. The public
|
|
295
|
+
entry point is precompiled partial-Ivy ESM, with generated Angular component
|
|
296
|
+
metadata; consumers do not need to compile the wrapper's TypeScript source:
|
|
272
297
|
|
|
273
298
|
```ts
|
|
274
299
|
import { Component } from "@angular/core";
|
|
@@ -308,8 +333,57 @@ export class AppComponent {
|
|
|
308
333
|
|
|
309
334
|
The Angular wrapper exposes the same JSON bridge and convenience instance methods as the React and Vue wrappers: `focus()`, `getEditor()`, `getHTMLCode()`, `getJSON()`, `setHTMLCode()`, `setJSON()`, and plugin accessors such as `getAiToolkit()` / `getCollab()` / `getComments()`.
|
|
310
335
|
|
|
336
|
+
When asset loading fails, show the `(error)` message and offer an explicit retry:
|
|
337
|
+
`await editorComponent.retry()`. It retries a failed initialization while keeping
|
|
338
|
+
the current bound form value. It does not replace an editor that is already ready,
|
|
339
|
+
start a second concurrent load, or revive a destroyed component. Fix missing asset
|
|
340
|
+
paths/CSP permissions before retrying. Asset autoload waits for theme CSS as well
|
|
341
|
+
as core/plugins; failed script or stylesheet requests can be retried without
|
|
342
|
+
refreshing the whole page. Manually preloaded (`autoload=false`) assets remain
|
|
343
|
+
your application's responsibility.
|
|
344
|
+
|
|
311
345
|
The repo also includes a full Angular starter in `Demos/rte-ng-ts/` that uses the same wrapper pattern.
|
|
312
346
|
|
|
347
|
+
For maintainers: `npm run build:angular` regenerates the ESM entry point,
|
|
348
|
+
declarations and source/output hash manifest. `npm pack` runs this step through
|
|
349
|
+
`prepack`; the build needs the declared Angular/compiler/TypeScript/esbuild dev
|
|
350
|
+
dependencies (or the installed Angular demo toolchain in a repository checkout).
|
|
351
|
+
The normal test suite rejects stale generated files. Angular dependencies are
|
|
352
|
+
optional peers and are not required by React/Vue/server-only consumers.
|
|
353
|
+
|
|
354
|
+
### Angular forms
|
|
355
|
+
|
|
356
|
+
The wrapper implements `ControlValueAccessor`: import `FormsModule` for
|
|
357
|
+
`[(ngModel)]="body"`, or `ReactiveFormsModule` for `[formControl]="bodyControl"`
|
|
358
|
+
and `formControlName`. These modules come from `@angular/forms`; use matching
|
|
359
|
+
Angular core/forms versions. Angular peers are optional for React/Vue users.
|
|
360
|
+
|
|
361
|
+
```ts
|
|
362
|
+
import { FormControl, ReactiveFormsModule } from "@angular/forms";
|
|
363
|
+
// Add ReactiveFormsModule and RichTextEditorAngularComponent to your imports.
|
|
364
|
+
bodyControl = new FormControl("<p>Hello</p>", {
|
|
365
|
+
nonNullable: true,
|
|
366
|
+
updateOn: "blur"
|
|
367
|
+
});
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
```html
|
|
371
|
+
<rich-text-editor [formControl]="bodyControl"
|
|
372
|
+
[assetBasePath]="'/assets/richtexteditor'" />
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
HTML is the default; use `valueFormat="json"` for structured document values.
|
|
376
|
+
External writes do not echo as user changes, null resets clear the editor,
|
|
377
|
+
and `disable()` / `enable()` update read-only state. Pending edits are flushed
|
|
378
|
+
before blur so `updateOn: "blur"` receives the final character. The default
|
|
379
|
+
120 ms change coalescing also applies to form changes; set `[changeDelay]="0"`
|
|
380
|
+
for the shortest quiet period. Do not combine `[value]` with a form binding.
|
|
381
|
+
An explicit `config.readOnly: true` remains read-only after `enable()`.
|
|
382
|
+
|
|
383
|
+
Use a content-aware required validator: `Validators.required` on the HTML
|
|
384
|
+
string alone accepts empty markup such as `<p><br></p>`. Check outstanding image
|
|
385
|
+
uploads before saving; valid form state is not an upload-completion guarantee.
|
|
386
|
+
|
|
313
387
|
## Svelte
|
|
314
388
|
|
|
315
389
|
`@richscripts/richtexteditor/svelte` ships a plain Svelte **action** — no compiler coupling,
|
|
@@ -324,10 +398,12 @@ controller, leaving the toolbar markup entirely to you.
|
|
|
324
398
|
let state = {}; // active formats, refreshed as the caret moves
|
|
325
399
|
</script>
|
|
326
400
|
|
|
327
|
-
<button class:is-active={state.bold}
|
|
328
|
-
on:mousedown|preventDefault={() =>
|
|
329
|
-
|
|
330
|
-
|
|
401
|
+
<button disabled={!editor} aria-pressed={!!state.bold} class:is-active={state.bold}
|
|
402
|
+
on:mousedown|preventDefault={() => {}}
|
|
403
|
+
on:click={() => editor.run("bold")}>Bold</button>
|
|
404
|
+
<button disabled={!editor || !state.canUndo}
|
|
405
|
+
on:mousedown|preventDefault={() => {}}
|
|
406
|
+
on:click={() => editor.run("undo")}>Undo</button>
|
|
331
407
|
|
|
332
408
|
<div use:richTextEditor={{
|
|
333
409
|
value: "<p>Hello</p>",
|
|
@@ -336,12 +412,48 @@ controller, leaving the toolbar markup entirely to you.
|
|
|
336
412
|
}}></div>
|
|
337
413
|
```
|
|
338
414
|
|
|
339
|
-
|
|
415
|
+
Prevent the pointer's default mousedown focus change to keep the caret, but run commands
|
|
416
|
+
from `click` so keyboard activation works too. Changing
|
|
340
417
|
the `value` you pass in pushes new content into the editor, so a store can own the document, and
|
|
341
418
|
the action calls `destroy()` for you when the node unmounts. In SvelteKit this is client-only
|
|
342
419
|
code — keep it in a component that renders in the browser.
|
|
343
420
|
|
|
344
|
-
Options: `value`, `config`, `assetBasePath`, `onReady`, `onUpdate`, `onChange`, `onError`.
|
|
421
|
+
Options: `value`, `config`, `assetBasePath`, `signal`, `onReady`, `onUpdate`, `onChange`, `onError`.
|
|
422
|
+
|
|
423
|
+
Updating the action's options replaces callbacks without remounting. Only a
|
|
424
|
+
changed bound `value` replaces the document; an unrelated callback/state update
|
|
425
|
+
does not overwrite typing. Unmounting during asset loading disposes any late
|
|
426
|
+
controller and does not emit ready/error callbacks into a destroyed view.
|
|
427
|
+
|
|
428
|
+
For Svelte 5 runes, use reactive controller/state variables and the modern event syntax:
|
|
429
|
+
|
|
430
|
+
```svelte
|
|
431
|
+
<script>
|
|
432
|
+
import { richTextEditor } from "@richscripts/richtexteditor/svelte";
|
|
433
|
+
let editor = $state(null);
|
|
434
|
+
let state = $state({});
|
|
435
|
+
let html = $state("<p>Hello</p>");
|
|
436
|
+
</script>
|
|
437
|
+
|
|
438
|
+
<button disabled={!editor} aria-pressed={!!state.bold}
|
|
439
|
+
onmousedown={event => event.preventDefault()}
|
|
440
|
+
onclick={() => editor.run("bold")}>Bold</button>
|
|
441
|
+
<div use:richTextEditor={{
|
|
442
|
+
value: html,
|
|
443
|
+
onReady: controller => { editor = controller; },
|
|
444
|
+
onUpdate: next => { state = next; },
|
|
445
|
+
onChange: function () { html = this.getHTML(); }
|
|
446
|
+
}}></div>
|
|
447
|
+
<textarea aria-label="HTML output" readonly value={html}></textarea>
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
`onChange` runs with the controller as `this`. On unmount it can synchronously
|
|
451
|
+
deliver a final native edit before the core's deferred change event. Read/save the
|
|
452
|
+
value inside that callback; do not clear your controller reference first. A
|
|
453
|
+
programmatic bound-value update is not emitted again as a final user edit.
|
|
454
|
+
Toolbar controls should have visible names, `aria-pressed` for toggle state and
|
|
455
|
+
disabled state until ready. This is a keyboard-usable starting point, not a
|
|
456
|
+
complete accessibility certification for a custom toolbar.
|
|
345
457
|
|
|
346
458
|
## Web component
|
|
347
459
|
|
|
@@ -349,8 +461,12 @@ For pages that use none of the framework bindings above — Rails, Laravel,
|
|
|
349
461
|
htmx, plain HTML.
|
|
350
462
|
|
|
351
463
|
```html
|
|
464
|
+
<link rel="stylesheet" href="richtexteditor/rte_theme_default.min.css">
|
|
465
|
+
<link rel="stylesheet" href="richtexteditor/rte_mobile.min.css">
|
|
352
466
|
<script src="richtexteditor/rte-config.js"></script>
|
|
353
467
|
<script src="richtexteditor/rte.js"></script>
|
|
468
|
+
<!-- Optional plugins for the full toolbar. Omit unused plugins in a modular build. -->
|
|
469
|
+
<script src="richtexteditor/plugins/all_plugins.min.js"></script>
|
|
354
470
|
<script src="richtexteditor/rte-webcomponent.js"></script>
|
|
355
471
|
|
|
356
472
|
<form method="post">
|
|
@@ -359,8 +475,41 @@ htmx, plain HTML.
|
|
|
359
475
|
</form>
|
|
360
476
|
```
|
|
361
477
|
|
|
362
|
-
|
|
363
|
-
|
|
478
|
+
Serve the page and runtime from your local HTTP server, not `file://`. That form
|
|
479
|
+
posts `body=...` with no value-copying glue in browsers supporting form-associated
|
|
480
|
+
custom elements. `required` and `form.elements.body` use `ElementInternals`;
|
|
481
|
+
older-browser hidden-input fallback supports submission, not full native validation.
|
|
482
|
+
Always validate and sanitize the submitted HTML on your server.
|
|
483
|
+
|
|
484
|
+
React and Vue components commit the latest native input on editor blur, even if
|
|
485
|
+
their normal change callback is coalesced or the core change event is still pending.
|
|
486
|
+
This makes an ordinary editor-to-Save-button interaction safer, but it is not an
|
|
487
|
+
upload-completion or persistence guarantee. For programmatic saves, read fresh
|
|
488
|
+
HTML through the editor ref in the save/submit handler and wait for your image
|
|
489
|
+
upload adapter's pending requests first. A `form.submit()` call skips native
|
|
490
|
+
validation and submit listeners; use `requestSubmit()` when you need that workflow.
|
|
491
|
+
React can still batch a parent state update when code forces focus and clicks Save
|
|
492
|
+
inside one synchronous function. Use the editor ref for that same-turn programmatic
|
|
493
|
+
snapshot; a captured value from the previous parent render is not a fresh document.
|
|
494
|
+
|
|
495
|
+
The `value` attribute is the default document; alternatively put initial HTML
|
|
496
|
+
between the tags. `form.reset()` restores that initial document. Set the `.value`
|
|
497
|
+
property for application updates, and await readiness before calling editor APIs:
|
|
498
|
+
|
|
499
|
+
```js
|
|
500
|
+
const field = document.querySelector("rich-text-editor");
|
|
501
|
+
field.value = "<p>Application content</p>"; // also works before first connection
|
|
502
|
+
await field.ready;
|
|
503
|
+
console.log(field.value); // current HTML, not the original value attribute
|
|
504
|
+
const payload = new FormData(field.form); // name="body" participates automatically
|
|
505
|
+
```
|
|
506
|
+
|
|
507
|
+
`disabled` (including an enclosing disabled `<fieldset>`) disables editing and
|
|
508
|
+
excludes the value from form submission. `readonly` prevents editing but keeps
|
|
509
|
+
the submitted value. Rich-text emptiness ignores whitespace/entities and blank
|
|
510
|
+
paragraphs; images and other media count as content. These client checks are not
|
|
511
|
+
upload validation. Use the image-handling guide for a persistent upload backend
|
|
512
|
+
and wait for pending uploads before saving a document.
|
|
364
513
|
|
|
365
514
|
Attributes: `value`, `name`, `toolbar`, `height`, `width`, `readonly`, `disabled`, `required`,
|
|
366
515
|
`shadow`, `config` (JSON). Properties: `.value`, `.editor`, `.ready` (a Promise). Events: `input`,
|
|
@@ -395,6 +544,29 @@ Block-level formats go through `run("formatblock", "h1")` rather than `run("h1")
|
|
|
395
544
|
from `/richtexteditor` unless you pass `assetBasePath`; pass `autoload: false` if the page already
|
|
396
545
|
loads them.
|
|
397
546
|
|
|
547
|
+
Initialization supports `signal: AbortSignal`. Cancel an abandoned view while
|
|
548
|
+
assets load without cancelling other editors that share the same asset request:
|
|
549
|
+
|
|
550
|
+
```js
|
|
551
|
+
const pending = new AbortController();
|
|
552
|
+
const initialization = createHeadlessEditor("#host", { signal: pending.signal });
|
|
553
|
+
// If the view closes before initialization settles: pending.abort();
|
|
554
|
+
const controller = await initialization;
|
|
555
|
+
// Once mounted, explicitly call controller.destroy() when the view closes.
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
Cancellation rejects with the signal's reason (`AbortError` by default). It
|
|
559
|
+
does not destroy an already mounted editor. The React/Vue headless bindings and
|
|
560
|
+
Svelte action wire their own pending-initialization cancellation on unmount.
|
|
561
|
+
React headless bindings use the latest `value` and callbacks. For Vue, pass a
|
|
562
|
+
reactive options object if the value should follow application state:
|
|
563
|
+
|
|
564
|
+
```js
|
|
565
|
+
const options = reactive({ value: "<p>Initial</p>" }); // import reactive from vue
|
|
566
|
+
const { mountRef, editor, state } = useRichTextEditor(options);
|
|
567
|
+
options.value = "<p>Loaded from the application</p>";
|
|
568
|
+
```
|
|
569
|
+
|
|
398
570
|
## Classic usage
|
|
399
571
|
|
|
400
572
|
```html
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"angularCompiler": "20.3.31",
|
|
3
|
+
"typescript": "5.9.3",
|
|
4
|
+
"esbuild": "0.28.1",
|
|
5
|
+
"sources": {
|
|
6
|
+
"angular/component.ts": "c20f6c003689c8b931b55fd08232d4da56ca7ab95257bfe82edd2a42b34829f8",
|
|
7
|
+
"angular/index.ts": "e20427ea679cdac2f9103663089d60b59cc6739d973c3c9d2983b3b9be07a6f5",
|
|
8
|
+
"integrations/shared.js": "543fde78fb67291cdc2d338f751dd63af6cd0acf647e84b5bd677bc586ddd2e8",
|
|
9
|
+
"integrations/shared.d.ts": "66e7f7e60f31f4896e902ae562b68e56250ec3bd58ae851027ff77c27e1daf04",
|
|
10
|
+
"index.d.ts": "4f77c6b537eed915f67b61ab268e487fd2ec5890e54a99ae5bcfc3bef3f0ffe8",
|
|
11
|
+
"scripts/build-angular.mjs": "3e087b5d7f297299ff9d729b4e47c888a11b4e5a72f45f39852a1721159d4313"
|
|
12
|
+
},
|
|
13
|
+
"outputs": {
|
|
14
|
+
"angular/index.mjs": {
|
|
15
|
+
"bytes": 124563,
|
|
16
|
+
"sha256": "03bcd629a876f6a68025a1f42f7d7dbcc4518d6f4a822244969f111e3fdadd42"
|
|
17
|
+
},
|
|
18
|
+
"angular/index.d.ts": {
|
|
19
|
+
"bytes": 5009,
|
|
20
|
+
"sha256": "f533d2ac09f202326cfe3cc256489f0b345c1daba5f4c8ab6e05558f1056a90a"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
package/angular/index.d.ts
CHANGED
|
@@ -1,80 +1,75 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
RichTextEditorComments,
|
|
6
|
-
RichTextEditorDictation,
|
|
7
|
-
RichTextEditorDocumentMetrics,
|
|
8
|
-
RichTextEditorDocumentOutlineItem,
|
|
9
|
-
RichTextEditorFootnoteItem,
|
|
10
|
-
RichTextEditorInstance,
|
|
11
|
-
RichTextEditorMentions,
|
|
12
|
-
RichTextEditorPageSetup,
|
|
13
|
-
RichTextEditorReviewLedger,
|
|
14
|
-
RichTextEditorRevisionHistory,
|
|
15
|
-
RichTextEditorSlashCommands,
|
|
16
|
-
RichTextEditorStructuredDocument,
|
|
17
|
-
RichTextEditorStructuredInput,
|
|
18
|
-
RichTextEditorTableOfContentsItem,
|
|
19
|
-
RichTextEditorTableOfContentsOptions,
|
|
20
|
-
RichTextEditorTextStatistics,
|
|
21
|
-
RichTextEditorValueFormat
|
|
22
|
-
} from "../index";
|
|
23
|
-
|
|
1
|
+
import { AfterViewInit, ElementRef, EventEmitter, OnChanges, OnDestroy, SimpleChanges } from "@angular/core";
|
|
2
|
+
import { type ControlValueAccessor } from "@angular/forms";
|
|
3
|
+
import type { RichTextEditorAccessibilityResult, RichTextEditorAiToolkit, RichTextEditorCollab, RichTextEditorComments, RichTextEditorDictation, RichTextEditorDocumentMetrics, RichTextEditorDocumentOutlineItem, RichTextEditorFootnoteItem, RichTextEditorInstance, RichTextEditorMentions, RichTextEditorPageSetup, RichTextEditorReviewLedger, RichTextEditorRevisionHistory, RichTextEditorSlashCommands, RichTextEditorStructuredDocument, RichTextEditorStructuredInput, RichTextEditorTableOfContentsItem, RichTextEditorTableOfContentsOptions, RichTextEditorTextStatistics, RichTextEditorValueFormat } from "../index";
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
24
5
|
export interface RichTextEditorAngularChangeEvent {
|
|
25
|
-
|
|
26
|
-
|
|
6
|
+
editor: RichTextEditorInstance;
|
|
7
|
+
value: string | RichTextEditorStructuredDocument;
|
|
27
8
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
9
|
+
export declare class RichTextEditorAngularComponent implements AfterViewInit, OnChanges, OnDestroy, ControlValueAccessor {
|
|
10
|
+
assetBasePath: string;
|
|
11
|
+
autoload: boolean;
|
|
12
|
+
config: Record<string, unknown>;
|
|
13
|
+
value?: RichTextEditorStructuredInput;
|
|
14
|
+
valueFormat: RichTextEditorValueFormat;
|
|
15
|
+
changeDelay: number;
|
|
16
|
+
disabled: boolean;
|
|
17
|
+
change: EventEmitter<RichTextEditorAngularChangeEvent>;
|
|
18
|
+
error: EventEmitter<Error>;
|
|
19
|
+
ready: EventEmitter<RichTextEditorInstance>;
|
|
20
|
+
hostRef: ElementRef<HTMLDivElement>;
|
|
21
|
+
private changeHandler;
|
|
22
|
+
private emitChange;
|
|
23
|
+
private lastEmitted;
|
|
24
|
+
private editor;
|
|
25
|
+
private destroyed;
|
|
26
|
+
private initializing;
|
|
27
|
+
private writingValue;
|
|
28
|
+
private lastKnownHtml;
|
|
29
|
+
private blurHandler;
|
|
30
|
+
private onModelChange;
|
|
31
|
+
private onModelTouched;
|
|
32
|
+
ngAfterViewInit(): Promise<void>;
|
|
33
|
+
/** Retry a failed initial load; never replace a ready or destroyed instance. */
|
|
34
|
+
retry(): Promise<void>;
|
|
35
|
+
ngOnChanges(changes: SimpleChanges): void;
|
|
36
|
+
writeValue(value: RichTextEditorStructuredInput | null | undefined): void;
|
|
37
|
+
registerOnChange(fn: (value: string | RichTextEditorStructuredDocument) => void): void;
|
|
38
|
+
registerOnTouched(fn: () => void): void;
|
|
39
|
+
setDisabledState(disabled: boolean): void;
|
|
40
|
+
private applyDisabledState;
|
|
41
|
+
private emitCurrentValue;
|
|
42
|
+
ngOnDestroy(): void;
|
|
43
|
+
private releaseEditor;
|
|
44
|
+
focus(): void;
|
|
45
|
+
getEditor(): RichTextEditorInstance | null;
|
|
46
|
+
getHTMLCode(): string;
|
|
47
|
+
setHTMLCode(value: string): void;
|
|
48
|
+
getJSON(): RichTextEditorStructuredDocument | null;
|
|
49
|
+
setJSON(value: RichTextEditorStructuredInput): void;
|
|
50
|
+
getTextStatistics(): RichTextEditorTextStatistics | null;
|
|
51
|
+
getSelectionStatistics(): RichTextEditorTextStatistics | null;
|
|
52
|
+
getDocumentMetrics(): RichTextEditorDocumentMetrics | null;
|
|
53
|
+
getDocumentPageSetup(): RichTextEditorPageSetup | null;
|
|
54
|
+
setDocumentPageSetup(pageSetup: RichTextEditorPageSetup | null): RichTextEditorAngularComponent | null;
|
|
55
|
+
getDocumentOutline(): RichTextEditorDocumentOutlineItem[];
|
|
56
|
+
getFootnotes(): RichTextEditorFootnoteItem[];
|
|
57
|
+
getTableOfContents(options?: RichTextEditorTableOfContentsOptions): RichTextEditorTableOfContentsItem[];
|
|
58
|
+
syncTableOfContents(options?: RichTextEditorTableOfContentsOptions): RichTextEditorStructuredDocument | null;
|
|
59
|
+
auditAccessibility(): RichTextEditorAccessibilityResult | null;
|
|
60
|
+
getAiToolkit(): RichTextEditorAiToolkit | null | undefined;
|
|
61
|
+
getDictation(): RichTextEditorDictation | null | undefined;
|
|
62
|
+
getRevisionHistory(): RichTextEditorRevisionHistory | null | undefined;
|
|
63
|
+
getCollab(): RichTextEditorCollab | null | undefined;
|
|
64
|
+
getSlashCommands(): RichTextEditorSlashCommands | null | undefined;
|
|
65
|
+
getMentions(): RichTextEditorMentions | null | undefined;
|
|
66
|
+
getComments(): RichTextEditorComments | null | undefined;
|
|
67
|
+
getReviewLedger(): RichTextEditorReviewLedger | null | undefined;
|
|
68
|
+
private getPluginNamespace;
|
|
69
|
+
private syncEditor;
|
|
70
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<RichTextEditorAngularComponent, never>;
|
|
71
|
+
static ɵcmp: i0.ɵɵComponentDeclaration<RichTextEditorAngularComponent, "rich-text-editor", never, { "assetBasePath": { "alias": "assetBasePath"; "required": false; }; "autoload": { "alias": "autoload"; "required": false; }; "config": { "alias": "config"; "required": false; }; "value": { "alias": "value"; "required": false; }; "valueFormat": { "alias": "valueFormat"; "required": false; }; "changeDelay": { "alias": "changeDelay"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; }, { "change": "change"; "error": "error"; "ready": "ready"; }, never, never, true, never>;
|
|
61
72
|
}
|
|
62
73
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
createStructuredContent,
|
|
66
|
-
createStructuredDocument,
|
|
67
|
-
fromMarkdown,
|
|
68
|
-
getDocumentPageSetup,
|
|
69
|
-
getDocumentMetrics,
|
|
70
|
-
getDocumentOutline,
|
|
71
|
-
getFootnotes,
|
|
72
|
-
getTableOfContents,
|
|
73
|
-
getTextStatistics,
|
|
74
|
-
loadRichTextEditorAssets,
|
|
75
|
-
renderHTML,
|
|
76
|
-
setDocumentPageSetup,
|
|
77
|
-
syncTableOfContents,
|
|
78
|
-
toMarkdown,
|
|
79
|
-
validateStructuredContent
|
|
80
|
-
} from "../integrations/shared";
|
|
74
|
+
|
|
75
|
+
export { auditAccessibility, auditLinks, createStructuredContent, createStructuredDocument, fromMarkdown, getDocumentPageSetup, getDocumentMetrics, getDocumentOutline, getFootnotes, getTableOfContents, getTextStatistics, loadRichTextEditorAssets, renderHTML, setDocumentPageSetup, syncTableOfContents, toMarkdown, validateStructuredContent } from "../integrations/shared";
|