@dojo-ng/rich-text 0.1.0 → 0.1.1
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 +2 -2
- package/dist/dj-rich-text.d.ts +4 -0
- package/dist/dj-rich-text.js +25 -4
- package/package.json +29 -5
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ Part of [Dojo NG](../../README.md), a framework-agnostic web component library b
|
|
|
6
6
|
|
|
7
7
|
A form-associated WYSIWYG editor built on the Lexical core. The editable region renders in LIGHT DOM (Lexical's selection handling is not reliable inside a shadow root yet), so this component overrides `createRenderRoot`; theming still works because `--dj-*` tokens cascade in light DOM. The editor is a PLUGIN HOST: bold/italic/underline and undo/redo ship as the default plugin set (`default-plugins.ts`) and flow through the same {@link RichTextPlugin} API third-party plugins use. Foundational behavior (`registerRichText`, value sync, root-element setup) stays as core. Toolbar controls, node registration, and output formats all come from plugins. Constraint: Lexical needs node classes at creation, so a `plugins` change after creation rebuilds the editor (serialize → recreate → deserialize). Value is HTML by default; the `format` property selects an alternate serializer contributed by a plugin. Event: `dj-change`.
|
|
8
8
|
|
|
9
|
-
> Pasted HTML is sanitized against an allowlist by default (scripts, styles, event handlers, inline styles, and unsafe `javascript:`/`data:` URLs are stripped; unknown tags are unwrapped, keeping their text) — a security and consistency hook, not a nicety. Set `sanitizePaste = false` in JS to turn it off, or supply your own `pasteSanitizer(html) => html`. Plain-text pastes bypass it. The exported `sanitizeHtml(html)` is the default and can be reused. Formatting, headings/lists/links, and other node types come from plugins; setting `plugins` replaces the default set, so spread `...defaultPlugins` to keep the basics.
|
|
9
|
+
> Pasted HTML is sanitized against an allowlist by default (scripts, styles, event handlers, inline styles, and unsafe `javascript:`/`data:` URLs are stripped; unknown tags are unwrapped, keeping their text) — a security and consistency hook, not a nicety. Set `sanitizePaste = false` in JS to turn it off, or supply your own `pasteSanitizer(html) => html`. Plain-text pastes bypass it. The exported `sanitizeHtml(html)` is the default and can be reused. Formatting, headings/lists/links, and other node types come from plugins; setting `plugins` replaces the default set, so spread `...defaultPlugins` to keep the basics. `value` is readable and writable at any time, not just at construction: assigning it replaces the whole document (discarding the selection and undo history) and emits no `dj-change`, the same as setting a native input's `value`.
|
|
10
10
|
|
|
11
11
|
## Install
|
|
12
12
|
|
|
@@ -58,4 +58,4 @@ Follows the project's WCAG 2.2 AA and localization conventions.
|
|
|
58
58
|
|
|
59
59
|
## More
|
|
60
60
|
|
|
61
|
-
Live, interactive examples are
|
|
61
|
+
Live, interactive examples are at [play.dojo-ng.com](https://play.dojo-ng.com). For the full API reference, theming, accessibility, and localization guides, see the [Dojo NG documentation](../../README.md).
|
package/dist/dj-rich-text.d.ts
CHANGED
|
@@ -26,6 +26,10 @@ export declare class DjRichText extends DjRichText_base implements Partial<DojoF
|
|
|
26
26
|
static formAssociated: boolean;
|
|
27
27
|
protected createRenderRoot(): this;
|
|
28
28
|
private editable;
|
|
29
|
+
/** The document, serialized through the active `format` (HTML by default). Readable and writable
|
|
30
|
+
* at any time, not just at construction: assigning after the editor is built replaces the whole
|
|
31
|
+
* document, discarding the selection and undo history, and emits no `dj-change` — the same as
|
|
32
|
+
* setting a native input's `value`. */
|
|
29
33
|
value: string;
|
|
30
34
|
name?: string;
|
|
31
35
|
label?: string;
|
package/dist/dj-rich-text.js
CHANGED
|
@@ -15,7 +15,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
15
15
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
16
16
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
17
17
|
};
|
|
18
|
-
var _DjRichText_instances, _DjRichText_internals, _DjRichText_editor, _DjRichText_applyingValue, _DjRichText_built, _DjRichText_disposers, _DjRichText_active, _DjRichText_selectionSubs, _DjRichText_serializers, _DjRichText_plugins, _DjRichText_ctx, _DjRichText_resolvePlugins, _DjRichText_currentFormat, _DjRichText_buildEditor, _DjRichText_teardown, _DjRichText_serialize, _DjRichText_syncValue, _DjRichText_applyValue, _DjRichText_icon, _DjRichText_renderItem, _DjRichText_toolbarItems;
|
|
18
|
+
var _DjRichText_instances, _DjRichText_internals, _DjRichText_editor, _DjRichText_applyingValue, _DjRichText_appliedValue, _DjRichText_built, _DjRichText_disposers, _DjRichText_active, _DjRichText_selectionSubs, _DjRichText_serializers, _DjRichText_plugins, _DjRichText_ctx, _DjRichText_resolvePlugins, _DjRichText_currentFormat, _DjRichText_buildEditor, _DjRichText_teardown, _DjRichText_serialize, _DjRichText_syncValue, _DjRichText_applyValue, _DjRichText_icon, _DjRichText_renderItem, _DjRichText_toolbarItems;
|
|
19
19
|
import { html, nothing } from "lit";
|
|
20
20
|
import { property, state, query } from "lit/decorators.js";
|
|
21
21
|
import DojoElement, { FormControl } from "@dojo-ng/dojo-element";
|
|
@@ -66,6 +66,10 @@ export class DjRichText extends FormControl(DojoElement) {
|
|
|
66
66
|
_DjRichText_internals.set(this, void 0);
|
|
67
67
|
_DjRichText_editor.set(this, void 0);
|
|
68
68
|
_DjRichText_applyingValue.set(this, false);
|
|
69
|
+
/** The value the editor last LOADED or last serialized OUT. `#syncValue()` writes `this.value` on
|
|
70
|
+
* every editor change, so `value` is in the changed-properties map on every keystroke; comparing
|
|
71
|
+
* against this is what tells an outside assignment apart from the editor's own echo. */
|
|
72
|
+
_DjRichText_appliedValue.set(this, "");
|
|
69
73
|
_DjRichText_built.set(this, false);
|
|
70
74
|
_DjRichText_disposers.set(this, []);
|
|
71
75
|
_DjRichText_active.set(this, new Set());
|
|
@@ -73,6 +77,10 @@ export class DjRichText extends FormControl(DojoElement) {
|
|
|
73
77
|
_DjRichText_serializers.set(this, { html: HTML_FORMAT });
|
|
74
78
|
_DjRichText_plugins.set(this, []);
|
|
75
79
|
_DjRichText_ctx.set(this, void 0);
|
|
80
|
+
/** The document, serialized through the active `format` (HTML by default). Readable and writable
|
|
81
|
+
* at any time, not just at construction: assigning after the editor is built replaces the whole
|
|
82
|
+
* document, discarding the selection and undo history, and emits no `dj-change` — the same as
|
|
83
|
+
* setting a native input's `value`. */
|
|
76
84
|
this.value = "";
|
|
77
85
|
this.placeholder = "";
|
|
78
86
|
this.disabled = false;
|
|
@@ -121,6 +129,7 @@ export class DjRichText extends FormControl(DojoElement) {
|
|
|
121
129
|
__classPrivateFieldSet(this, _DjRichText_built, false, "f");
|
|
122
130
|
}
|
|
123
131
|
updated(c) {
|
|
132
|
+
let appliedValue = false;
|
|
124
133
|
if (!__classPrivateFieldGet(this, _DjRichText_editor, "f")) {
|
|
125
134
|
__classPrivateFieldGet(this, _DjRichText_instances, "m", _DjRichText_buildEditor).call(this);
|
|
126
135
|
}
|
|
@@ -130,12 +139,21 @@ export class DjRichText extends FormControl(DojoElement) {
|
|
|
130
139
|
__classPrivateFieldGet(this, _DjRichText_instances, "m", _DjRichText_teardown).call(this);
|
|
131
140
|
__classPrivateFieldGet(this, _DjRichText_instances, "m", _DjRichText_buildEditor).call(this);
|
|
132
141
|
}
|
|
142
|
+
else if (c.has("value") && this.value !== __classPrivateFieldGet(this, _DjRichText_appliedValue, "f")) {
|
|
143
|
+
// A value set from OUTSIDE the editor. An equal value here is the editor's own echo and
|
|
144
|
+
// must not be re-deserialized: doing so would rebuild the document under the caret on
|
|
145
|
+
// every character typed.
|
|
146
|
+
__classPrivateFieldGet(this, _DjRichText_instances, "m", _DjRichText_applyValue).call(this, this.value, __classPrivateFieldGet(this, _DjRichText_instances, "m", _DjRichText_currentFormat).call(this));
|
|
147
|
+
appliedValue = true;
|
|
148
|
+
}
|
|
133
149
|
if (c.has("disabled")) {
|
|
134
150
|
__classPrivateFieldGet(this, _DjRichText_editor, "f")?.setEditable(!this.isDisabled);
|
|
135
151
|
if (this.editable)
|
|
136
152
|
this.editable.contentEditable = this.isDisabled ? "false" : "true";
|
|
137
153
|
}
|
|
138
|
-
|
|
154
|
+
// Skipped when the value branch just ran: that already loaded the document through the new
|
|
155
|
+
// format, and serializing straight back out would emit a spurious dj-change.
|
|
156
|
+
if (c.has("format") && !c.has("plugins") && !appliedValue && __classPrivateFieldGet(this, _DjRichText_built, "f"))
|
|
139
157
|
__classPrivateFieldGet(this, _DjRichText_instances, "m", _DjRichText_syncValue).call(this);
|
|
140
158
|
}
|
|
141
159
|
/** Replace the document with the given HTML (regardless of the active `format`). */
|
|
@@ -171,7 +189,7 @@ export class DjRichText extends FormControl(DojoElement) {
|
|
|
171
189
|
`;
|
|
172
190
|
}
|
|
173
191
|
}
|
|
174
|
-
_DjRichText_internals = new WeakMap(), _DjRichText_editor = new WeakMap(), _DjRichText_applyingValue = new WeakMap(), _DjRichText_built = new WeakMap(), _DjRichText_disposers = new WeakMap(), _DjRichText_active = new WeakMap(), _DjRichText_selectionSubs = new WeakMap(), _DjRichText_serializers = new WeakMap(), _DjRichText_plugins = new WeakMap(), _DjRichText_ctx = new WeakMap(), _DjRichText_instances = new WeakSet(), _DjRichText_resolvePlugins = function _DjRichText_resolvePlugins() {
|
|
192
|
+
_DjRichText_internals = new WeakMap(), _DjRichText_editor = new WeakMap(), _DjRichText_applyingValue = new WeakMap(), _DjRichText_appliedValue = new WeakMap(), _DjRichText_built = new WeakMap(), _DjRichText_disposers = new WeakMap(), _DjRichText_active = new WeakMap(), _DjRichText_selectionSubs = new WeakMap(), _DjRichText_serializers = new WeakMap(), _DjRichText_plugins = new WeakMap(), _DjRichText_ctx = new WeakMap(), _DjRichText_instances = new WeakSet(), _DjRichText_resolvePlugins = function _DjRichText_resolvePlugins() {
|
|
175
193
|
return this.plugins.length ? this.plugins : defaultPlugins;
|
|
176
194
|
}, _DjRichText_currentFormat = function _DjRichText_currentFormat() {
|
|
177
195
|
return __classPrivateFieldGet(this, _DjRichText_serializers, "f")[this.format] ?? HTML_FORMAT;
|
|
@@ -261,6 +279,7 @@ _DjRichText_internals = new WeakMap(), _DjRichText_editor = new WeakMap(), _DjRi
|
|
|
261
279
|
}
|
|
262
280
|
__classPrivateFieldSet(this, _DjRichText_built, true, "f");
|
|
263
281
|
this.ready = true; // re-render so the toolbar shows now that ctx.editor is live
|
|
282
|
+
__classPrivateFieldSet(this, _DjRichText_appliedValue, this.value, "f");
|
|
264
283
|
if (this.value)
|
|
265
284
|
__classPrivateFieldGet(this, _DjRichText_instances, "m", _DjRichText_applyValue).call(this, this.value, __classPrivateFieldGet(this, _DjRichText_instances, "m", _DjRichText_currentFormat).call(this));
|
|
266
285
|
}, _DjRichText_teardown = function _DjRichText_teardown() {
|
|
@@ -277,12 +296,14 @@ _DjRichText_internals = new WeakMap(), _DjRichText_editor = new WeakMap(), _DjRi
|
|
|
277
296
|
return editor.getEditorState().read(() => fmt.serialize(editor));
|
|
278
297
|
}, _DjRichText_syncValue = function _DjRichText_syncValue() {
|
|
279
298
|
const out = __classPrivateFieldGet(this, _DjRichText_instances, "m", _DjRichText_serialize).call(this);
|
|
299
|
+
__classPrivateFieldSet(this, _DjRichText_appliedValue, out, "f");
|
|
280
300
|
if (out !== this.value) {
|
|
281
301
|
this.value = out;
|
|
282
302
|
__classPrivateFieldGet(this, _DjRichText_internals, "f").setFormValue(out);
|
|
283
303
|
this.emit("dj-change");
|
|
284
304
|
}
|
|
285
305
|
}, _DjRichText_applyValue = function _DjRichText_applyValue(data, fmt) {
|
|
306
|
+
__classPrivateFieldSet(this, _DjRichText_appliedValue, data, "f");
|
|
286
307
|
const editor = __classPrivateFieldGet(this, _DjRichText_editor, "f");
|
|
287
308
|
if (!editor) {
|
|
288
309
|
this.value = data;
|
|
@@ -322,7 +343,7 @@ _DjRichText_internals = new WeakMap(), _DjRichText_editor = new WeakMap(), _DjRi
|
|
|
322
343
|
}
|
|
323
344
|
return items;
|
|
324
345
|
};
|
|
325
|
-
DjRichText.version = "0.1.
|
|
346
|
+
DjRichText.version = "0.1.1";
|
|
326
347
|
DjRichText.focusable = true;
|
|
327
348
|
DjRichText.formAssociated = true;
|
|
328
349
|
__decorate([
|
package/package.json
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
|
-
{
|
|
2
|
-
"
|
|
3
|
-
"
|
|
4
|
-
"
|
|
5
|
-
"
|
|
1
|
+
{
|
|
2
|
+
"name": "@dojo-ng/rich-text",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"license": "BSD-3-Clause",
|
|
5
|
+
"description": "Dojo NG rich-text (WYSIWYG) web component on Lexical",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"!dist/**/*.map"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc -p tsconfig.json",
|
|
16
|
+
"clean": "rm -rf dist"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@dojo-ng/dojo-element": "^0.1.0",
|
|
20
|
+
"@dojo-ng/button": "^0.1.1",
|
|
21
|
+
"lexical": "^0.21.0",
|
|
22
|
+
"@lexical/rich-text": "^0.21.0",
|
|
23
|
+
"@lexical/history": "^0.21.0",
|
|
24
|
+
"@lexical/html": "^0.21.0",
|
|
25
|
+
"@lexical/clipboard": "^0.21.0",
|
|
26
|
+
"@lexical/utils": "^0.21.0",
|
|
27
|
+
"lit": "^3.3.0"
|
|
28
|
+
}
|
|
29
|
+
}
|