@richscripts/richtexteditor 2.14.1 → 2.15.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 +173 -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 +33 -54
- 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 +58 -22
- package/package.json +25 -3
- package/react/index.js +118 -37
- package/react/index.mjs +29 -0
- package/richtexteditor/all_plugins.js +7001 -1078
- package/richtexteditor/all_plugins.min.js +62 -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 +1017 -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 +1023 -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 +1023 -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 +1023 -2
- package/richtexteditor/lang/rte-lang-ja.js +1023 -2
- package/richtexteditor/lang/rte-lang-kn.js +1 -0
- package/richtexteditor/lang/rte-lang-ko.js +1023 -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 +1023 -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 +1023 -2
- package/richtexteditor/lang/rte-lang-pt.js +1023 -2
- package/richtexteditor/lang/rte-lang-ro.js +1 -0
- package/richtexteditor/lang/rte-lang-ru.js +1023 -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 +1017 -2
- package/richtexteditor/lang/rte-lang-zh-Hant.js +1017 -2
- package/richtexteditor/plugins/a11yenhance.js +2 -1
- package/richtexteditor/plugins/a11yenhance.min.js +1 -1
- package/richtexteditor/plugins/accessibilitychecker.js +252 -60
- package/richtexteditor/plugins/accessibilitychecker.min.js +1 -1
- package/richtexteditor/plugins/aitoolkit.js +966 -303
- package/richtexteditor/plugins/aitoolkit.min.js +7 -7
- package/richtexteditor/plugins/all_plugins.js +7001 -1078
- package/richtexteditor/plugins/all_plugins.min.js +62 -59
- package/richtexteditor/plugins/autocorrect.js +66 -31
- package/richtexteditor/plugins/autocorrect.min.js +1 -1
- package/richtexteditor/plugins/autoembed.js +17 -0
- 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 +458 -59
- package/richtexteditor/plugins/comments.min.js +4 -3
- package/richtexteditor/plugins/contentminimap.js +25 -6
- package/richtexteditor/plugins/contentminimap.min.js +1 -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 +220 -51
- 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 +204 -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 +110 -56
- 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 +1 -1
- package/richtexteditor/plugins/html2pdf.min.js +1 -1
- package/richtexteditor/plugins/imageeditor.js +12 -6
- 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 +21 -3
- package/richtexteditor/plugins/insertcode.min.js +4 -4
- package/richtexteditor/plugins/insertemoji.js +112 -15
- package/richtexteditor/plugins/insertemoji.min.js +1 -1
- package/richtexteditor/plugins/insertgallery.js +42 -36
- package/richtexteditor/plugins/insertgallery.min.js +1 -1
- package/richtexteditor/plugins/inserttemplate.js +33 -17
- 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 +88 -25
- package/richtexteditor/plugins/mentionplugin.min.js +1 -1
- package/richtexteditor/plugins/mermaiddiagram.js +9 -3
- 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/pdfexport.js +235 -35
- package/richtexteditor/plugins/pdfexport.min.js +12 -12
- 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 +29 -15
- 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 +169 -37
- package/richtexteditor/plugins/revisionhistory.min.js +3 -3
- package/richtexteditor/plugins/rubyannotation.js +19 -9
- package/richtexteditor/plugins/rubyannotation.min.js +1 -1
- package/richtexteditor/plugins/sanitizer.js +62 -3
- package/richtexteditor/plugins/sanitizer.min.js +1 -1
- package/richtexteditor/plugins/slashcommand.js +30 -16
- package/richtexteditor/plugins/slashcommand.min.js +2 -2
- package/richtexteditor/plugins/smartchips.js +36 -22
- package/richtexteditor/plugins/smartchips.min.js +2 -2
- package/richtexteditor/plugins/spellcheck.js +17 -8
- package/richtexteditor/plugins/spellcheck.min.js +2 -2
- package/richtexteditor/plugins/stateinspector.js +19 -9
- package/richtexteditor/plugins/stateinspector.min.js +2 -2
- package/richtexteditor/plugins/structured-content-bridge.js +56 -24
- package/richtexteditor/plugins/structured-content-bridge.min.js +7 -7
- 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 +18 -5
- 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 +9 -4
- 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 +130 -50
- package/richtexteditor/rte-headless.js +19 -4
- package/richtexteditor/rte-webcomponent.js +89 -16
- package/richtexteditor/rte.js +132 -52
- 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
|
|
|
@@ -214,6 +214,8 @@ Pass `file` to skip the built-in file picker, or use `mode: "insert"` to insert
|
|
|
214
214
|
## React
|
|
215
215
|
|
|
216
216
|
```jsx
|
|
217
|
+
"use client"; // Required for your own state/callback wrapper in Next.js App Router.
|
|
218
|
+
|
|
217
219
|
import { useState } from "react";
|
|
218
220
|
import { RichTextEditorReact } from "@richscripts/richtexteditor/react";
|
|
219
221
|
|
|
@@ -231,6 +233,18 @@ export default function EditorPage() {
|
|
|
231
233
|
}
|
|
232
234
|
```
|
|
233
235
|
|
|
236
|
+
The `/react` ESM entry declares its own client boundary. A Next.js App Router
|
|
237
|
+
Server Component may render `<RichTextEditorReact value="<p>Hello</p>" />` with
|
|
238
|
+
serializable props. Put `useState`, `onChange`, refs and function-valued editor
|
|
239
|
+
configuration in your own `"use client"` wrapper, as above; do not pass ordinary
|
|
240
|
+
callbacks across the server/client boundary. Copy the runtime to `public/richtexteditor`
|
|
241
|
+
as in the installation steps. Server-side HTML/Markdown conversion belongs in
|
|
242
|
+
`@richscripts/richtexteditor/server`, not in the React client entry.
|
|
243
|
+
|
|
244
|
+
CommonJS `require("@richscripts/richtexteditor/react")` remains available with
|
|
245
|
+
the same named API. No `ssr: false` workaround is needed just to render the wrapper;
|
|
246
|
+
the browser-only editor is created after the component mounts.
|
|
247
|
+
|
|
234
248
|
## Vue
|
|
235
249
|
|
|
236
250
|
```js
|
|
@@ -268,7 +282,9 @@ const app = createApp({
|
|
|
268
282
|
|
|
269
283
|
## Angular
|
|
270
284
|
|
|
271
|
-
Angular apps can
|
|
285
|
+
Angular 20.3+ apps can use the packaged standalone wrapper component. The public
|
|
286
|
+
entry point is precompiled partial-Ivy ESM, with generated Angular component
|
|
287
|
+
metadata; consumers do not need to compile the wrapper's TypeScript source:
|
|
272
288
|
|
|
273
289
|
```ts
|
|
274
290
|
import { Component } from "@angular/core";
|
|
@@ -308,8 +324,57 @@ export class AppComponent {
|
|
|
308
324
|
|
|
309
325
|
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
326
|
|
|
327
|
+
When asset loading fails, show the `(error)` message and offer an explicit retry:
|
|
328
|
+
`await editorComponent.retry()`. It retries a failed initialization while keeping
|
|
329
|
+
the current bound form value. It does not replace an editor that is already ready,
|
|
330
|
+
start a second concurrent load, or revive a destroyed component. Fix missing asset
|
|
331
|
+
paths/CSP permissions before retrying. Asset autoload waits for theme CSS as well
|
|
332
|
+
as core/plugins; failed script or stylesheet requests can be retried without
|
|
333
|
+
refreshing the whole page. Manually preloaded (`autoload=false`) assets remain
|
|
334
|
+
your application's responsibility.
|
|
335
|
+
|
|
311
336
|
The repo also includes a full Angular starter in `Demos/rte-ng-ts/` that uses the same wrapper pattern.
|
|
312
337
|
|
|
338
|
+
For maintainers: `npm run build:angular` regenerates the ESM entry point,
|
|
339
|
+
declarations and source/output hash manifest. `npm pack` runs this step through
|
|
340
|
+
`prepack`; the build needs the declared Angular/compiler/TypeScript/esbuild dev
|
|
341
|
+
dependencies (or the installed Angular demo toolchain in a repository checkout).
|
|
342
|
+
The normal test suite rejects stale generated files. Angular dependencies are
|
|
343
|
+
optional peers and are not required by React/Vue/server-only consumers.
|
|
344
|
+
|
|
345
|
+
### Angular forms
|
|
346
|
+
|
|
347
|
+
The wrapper implements `ControlValueAccessor`: import `FormsModule` for
|
|
348
|
+
`[(ngModel)]="body"`, or `ReactiveFormsModule` for `[formControl]="bodyControl"`
|
|
349
|
+
and `formControlName`. These modules come from `@angular/forms`; use matching
|
|
350
|
+
Angular core/forms versions. Angular peers are optional for React/Vue users.
|
|
351
|
+
|
|
352
|
+
```ts
|
|
353
|
+
import { FormControl, ReactiveFormsModule } from "@angular/forms";
|
|
354
|
+
// Add ReactiveFormsModule and RichTextEditorAngularComponent to your imports.
|
|
355
|
+
bodyControl = new FormControl("<p>Hello</p>", {
|
|
356
|
+
nonNullable: true,
|
|
357
|
+
updateOn: "blur"
|
|
358
|
+
});
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
```html
|
|
362
|
+
<rich-text-editor [formControl]="bodyControl"
|
|
363
|
+
[assetBasePath]="'/assets/richtexteditor'" />
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
HTML is the default; use `valueFormat="json"` for structured document values.
|
|
367
|
+
External writes do not echo as user changes, null resets clear the editor,
|
|
368
|
+
and `disable()` / `enable()` update read-only state. Pending edits are flushed
|
|
369
|
+
before blur so `updateOn: "blur"` receives the final character. The default
|
|
370
|
+
120 ms change coalescing also applies to form changes; set `[changeDelay]="0"`
|
|
371
|
+
for the shortest quiet period. Do not combine `[value]` with a form binding.
|
|
372
|
+
An explicit `config.readOnly: true` remains read-only after `enable()`.
|
|
373
|
+
|
|
374
|
+
Use a content-aware required validator: `Validators.required` on the HTML
|
|
375
|
+
string alone accepts empty markup such as `<p><br></p>`. Check outstanding image
|
|
376
|
+
uploads before saving; valid form state is not an upload-completion guarantee.
|
|
377
|
+
|
|
313
378
|
## Svelte
|
|
314
379
|
|
|
315
380
|
`@richscripts/richtexteditor/svelte` ships a plain Svelte **action** — no compiler coupling,
|
|
@@ -324,10 +389,12 @@ controller, leaving the toolbar markup entirely to you.
|
|
|
324
389
|
let state = {}; // active formats, refreshed as the caret moves
|
|
325
390
|
</script>
|
|
326
391
|
|
|
327
|
-
<button class:is-active={state.bold}
|
|
328
|
-
on:mousedown|preventDefault={() =>
|
|
329
|
-
|
|
330
|
-
|
|
392
|
+
<button disabled={!editor} aria-pressed={!!state.bold} class:is-active={state.bold}
|
|
393
|
+
on:mousedown|preventDefault={() => {}}
|
|
394
|
+
on:click={() => editor.run("bold")}>Bold</button>
|
|
395
|
+
<button disabled={!editor || !state.canUndo}
|
|
396
|
+
on:mousedown|preventDefault={() => {}}
|
|
397
|
+
on:click={() => editor.run("undo")}>Undo</button>
|
|
331
398
|
|
|
332
399
|
<div use:richTextEditor={{
|
|
333
400
|
value: "<p>Hello</p>",
|
|
@@ -336,12 +403,48 @@ controller, leaving the toolbar markup entirely to you.
|
|
|
336
403
|
}}></div>
|
|
337
404
|
```
|
|
338
405
|
|
|
339
|
-
|
|
406
|
+
Prevent the pointer's default mousedown focus change to keep the caret, but run commands
|
|
407
|
+
from `click` so keyboard activation works too. Changing
|
|
340
408
|
the `value` you pass in pushes new content into the editor, so a store can own the document, and
|
|
341
409
|
the action calls `destroy()` for you when the node unmounts. In SvelteKit this is client-only
|
|
342
410
|
code — keep it in a component that renders in the browser.
|
|
343
411
|
|
|
344
|
-
Options: `value`, `config`, `assetBasePath`, `onReady`, `onUpdate`, `onChange`, `onError`.
|
|
412
|
+
Options: `value`, `config`, `assetBasePath`, `signal`, `onReady`, `onUpdate`, `onChange`, `onError`.
|
|
413
|
+
|
|
414
|
+
Updating the action's options replaces callbacks without remounting. Only a
|
|
415
|
+
changed bound `value` replaces the document; an unrelated callback/state update
|
|
416
|
+
does not overwrite typing. Unmounting during asset loading disposes any late
|
|
417
|
+
controller and does not emit ready/error callbacks into a destroyed view.
|
|
418
|
+
|
|
419
|
+
For Svelte 5 runes, use reactive controller/state variables and the modern event syntax:
|
|
420
|
+
|
|
421
|
+
```svelte
|
|
422
|
+
<script>
|
|
423
|
+
import { richTextEditor } from "@richscripts/richtexteditor/svelte";
|
|
424
|
+
let editor = $state(null);
|
|
425
|
+
let state = $state({});
|
|
426
|
+
let html = $state("<p>Hello</p>");
|
|
427
|
+
</script>
|
|
428
|
+
|
|
429
|
+
<button disabled={!editor} aria-pressed={!!state.bold}
|
|
430
|
+
onmousedown={event => event.preventDefault()}
|
|
431
|
+
onclick={() => editor.run("bold")}>Bold</button>
|
|
432
|
+
<div use:richTextEditor={{
|
|
433
|
+
value: html,
|
|
434
|
+
onReady: controller => { editor = controller; },
|
|
435
|
+
onUpdate: next => { state = next; },
|
|
436
|
+
onChange: function () { html = this.getHTML(); }
|
|
437
|
+
}}></div>
|
|
438
|
+
<textarea aria-label="HTML output" readonly value={html}></textarea>
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
`onChange` runs with the controller as `this`. On unmount it can synchronously
|
|
442
|
+
deliver a final native edit before the core's deferred change event. Read/save the
|
|
443
|
+
value inside that callback; do not clear your controller reference first. A
|
|
444
|
+
programmatic bound-value update is not emitted again as a final user edit.
|
|
445
|
+
Toolbar controls should have visible names, `aria-pressed` for toggle state and
|
|
446
|
+
disabled state until ready. This is a keyboard-usable starting point, not a
|
|
447
|
+
complete accessibility certification for a custom toolbar.
|
|
345
448
|
|
|
346
449
|
## Web component
|
|
347
450
|
|
|
@@ -349,8 +452,12 @@ For pages that use none of the framework bindings above — Rails, Laravel,
|
|
|
349
452
|
htmx, plain HTML.
|
|
350
453
|
|
|
351
454
|
```html
|
|
455
|
+
<link rel="stylesheet" href="richtexteditor/rte_theme_default.min.css">
|
|
456
|
+
<link rel="stylesheet" href="richtexteditor/rte_mobile.min.css">
|
|
352
457
|
<script src="richtexteditor/rte-config.js"></script>
|
|
353
458
|
<script src="richtexteditor/rte.js"></script>
|
|
459
|
+
<!-- Optional plugins for the full toolbar. Omit unused plugins in a modular build. -->
|
|
460
|
+
<script src="richtexteditor/plugins/all_plugins.min.js"></script>
|
|
354
461
|
<script src="richtexteditor/rte-webcomponent.js"></script>
|
|
355
462
|
|
|
356
463
|
<form method="post">
|
|
@@ -359,8 +466,41 @@ htmx, plain HTML.
|
|
|
359
466
|
</form>
|
|
360
467
|
```
|
|
361
468
|
|
|
362
|
-
|
|
363
|
-
|
|
469
|
+
Serve the page and runtime from your local HTTP server, not `file://`. That form
|
|
470
|
+
posts `body=...` with no value-copying glue in browsers supporting form-associated
|
|
471
|
+
custom elements. `required` and `form.elements.body` use `ElementInternals`;
|
|
472
|
+
older-browser hidden-input fallback supports submission, not full native validation.
|
|
473
|
+
Always validate and sanitize the submitted HTML on your server.
|
|
474
|
+
|
|
475
|
+
React and Vue components commit the latest native input on editor blur, even if
|
|
476
|
+
their normal change callback is coalesced or the core change event is still pending.
|
|
477
|
+
This makes an ordinary editor-to-Save-button interaction safer, but it is not an
|
|
478
|
+
upload-completion or persistence guarantee. For programmatic saves, read fresh
|
|
479
|
+
HTML through the editor ref in the save/submit handler and wait for your image
|
|
480
|
+
upload adapter's pending requests first. A `form.submit()` call skips native
|
|
481
|
+
validation and submit listeners; use `requestSubmit()` when you need that workflow.
|
|
482
|
+
React can still batch a parent state update when code forces focus and clicks Save
|
|
483
|
+
inside one synchronous function. Use the editor ref for that same-turn programmatic
|
|
484
|
+
snapshot; a captured value from the previous parent render is not a fresh document.
|
|
485
|
+
|
|
486
|
+
The `value` attribute is the default document; alternatively put initial HTML
|
|
487
|
+
between the tags. `form.reset()` restores that initial document. Set the `.value`
|
|
488
|
+
property for application updates, and await readiness before calling editor APIs:
|
|
489
|
+
|
|
490
|
+
```js
|
|
491
|
+
const field = document.querySelector("rich-text-editor");
|
|
492
|
+
field.value = "<p>Application content</p>"; // also works before first connection
|
|
493
|
+
await field.ready;
|
|
494
|
+
console.log(field.value); // current HTML, not the original value attribute
|
|
495
|
+
const payload = new FormData(field.form); // name="body" participates automatically
|
|
496
|
+
```
|
|
497
|
+
|
|
498
|
+
`disabled` (including an enclosing disabled `<fieldset>`) disables editing and
|
|
499
|
+
excludes the value from form submission. `readonly` prevents editing but keeps
|
|
500
|
+
the submitted value. Rich-text emptiness ignores whitespace/entities and blank
|
|
501
|
+
paragraphs; images and other media count as content. These client checks are not
|
|
502
|
+
upload validation. Use the image-handling guide for a persistent upload backend
|
|
503
|
+
and wait for pending uploads before saving a document.
|
|
364
504
|
|
|
365
505
|
Attributes: `value`, `name`, `toolbar`, `height`, `width`, `readonly`, `disabled`, `required`,
|
|
366
506
|
`shadow`, `config` (JSON). Properties: `.value`, `.editor`, `.ready` (a Promise). Events: `input`,
|
|
@@ -395,6 +535,29 @@ Block-level formats go through `run("formatblock", "h1")` rather than `run("h1")
|
|
|
395
535
|
from `/richtexteditor` unless you pass `assetBasePath`; pass `autoload: false` if the page already
|
|
396
536
|
loads them.
|
|
397
537
|
|
|
538
|
+
Initialization supports `signal: AbortSignal`. Cancel an abandoned view while
|
|
539
|
+
assets load without cancelling other editors that share the same asset request:
|
|
540
|
+
|
|
541
|
+
```js
|
|
542
|
+
const pending = new AbortController();
|
|
543
|
+
const initialization = createHeadlessEditor("#host", { signal: pending.signal });
|
|
544
|
+
// If the view closes before initialization settles: pending.abort();
|
|
545
|
+
const controller = await initialization;
|
|
546
|
+
// Once mounted, explicitly call controller.destroy() when the view closes.
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
Cancellation rejects with the signal's reason (`AbortError` by default). It
|
|
550
|
+
does not destroy an already mounted editor. The React/Vue headless bindings and
|
|
551
|
+
Svelte action wire their own pending-initialization cancellation on unmount.
|
|
552
|
+
React headless bindings use the latest `value` and callbacks. For Vue, pass a
|
|
553
|
+
reactive options object if the value should follow application state:
|
|
554
|
+
|
|
555
|
+
```js
|
|
556
|
+
const options = reactive({ value: "<p>Initial</p>" }); // import reactive from vue
|
|
557
|
+
const { mountRef, editor, state } = useRichTextEditor(options);
|
|
558
|
+
options.value = "<p>Loaded from the application</p>";
|
|
559
|
+
```
|
|
560
|
+
|
|
398
561
|
## Classic usage
|
|
399
562
|
|
|
400
563
|
```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": "df288497a07fd2f5652fccaf33299ba2d5c6468af7453d801f56013451875f11",
|
|
9
|
+
"integrations/shared.d.ts": "66e7f7e60f31f4896e902ae562b68e56250ec3bd58ae851027ff77c27e1daf04",
|
|
10
|
+
"index.d.ts": "87ede19a371082213cda51db0dfc99621f83480f215776f99cf0a9d8619cd503",
|
|
11
|
+
"scripts/build-angular.mjs": "3e087b5d7f297299ff9d729b4e47c888a11b4e5a72f45f39852a1721159d4313"
|
|
12
|
+
},
|
|
13
|
+
"outputs": {
|
|
14
|
+
"angular/index.mjs": {
|
|
15
|
+
"bytes": 124323,
|
|
16
|
+
"sha256": "75093e8ff2410a07cb5a7cb43a20274cd06eada4f7d404a3526f2369fa7ec925"
|
|
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";
|