truerte-react 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/CHANGELOG.md +58 -0
  2. package/LICENSE.txt +22 -0
  3. package/README.md +54 -0
  4. package/lib/cjs/main/ts/EventNames.d.ts +8 -0
  5. package/lib/cjs/main/ts/EventNames.js +87 -0
  6. package/lib/cjs/main/ts/Events.d.ts +94 -0
  7. package/lib/cjs/main/ts/Events.js +2 -0
  8. package/lib/cjs/main/ts/ScriptLoader2.d.ts +10 -0
  9. package/lib/cjs/main/ts/ScriptLoader2.js +138 -0
  10. package/lib/cjs/main/ts/TrueRTE.d.ts +3 -0
  11. package/lib/cjs/main/ts/TrueRTE.js +8 -0
  12. package/lib/cjs/main/ts/Utils.d.ts +18 -0
  13. package/lib/cjs/main/ts/Utils.js +53 -0
  14. package/lib/cjs/main/ts/Uuid.d.ts +6 -0
  15. package/lib/cjs/main/ts/Uuid.js +16 -0
  16. package/lib/cjs/main/ts/components/Editor.d.ts +171 -0
  17. package/lib/cjs/main/ts/components/Editor.js +358 -0
  18. package/lib/cjs/main/ts/index.d.ts +2 -0
  19. package/lib/cjs/main/ts/index.js +5 -0
  20. package/lib/es2015/main/ts/EventNames.d.ts +8 -0
  21. package/lib/es2015/main/ts/EventNames.js +84 -0
  22. package/lib/es2015/main/ts/Events.d.ts +94 -0
  23. package/lib/es2015/main/ts/Events.js +1 -0
  24. package/lib/es2015/main/ts/ScriptLoader2.d.ts +10 -0
  25. package/lib/es2015/main/ts/ScriptLoader2.js +135 -0
  26. package/lib/es2015/main/ts/TrueRTE.d.ts +3 -0
  27. package/lib/es2015/main/ts/TrueRTE.js +5 -0
  28. package/lib/es2015/main/ts/Utils.d.ts +18 -0
  29. package/lib/es2015/main/ts/Utils.js +43 -0
  30. package/lib/es2015/main/ts/Uuid.d.ts +6 -0
  31. package/lib/es2015/main/ts/Uuid.js +12 -0
  32. package/lib/es2015/main/ts/components/Editor.d.ts +171 -0
  33. package/lib/es2015/main/ts/components/Editor.js +354 -0
  34. package/lib/es2015/main/ts/index.d.ts +2 -0
  35. package/lib/es2015/main/ts/index.js +2 -0
  36. package/package.json +63 -0
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Official TrueRTE React component
3
+ * Copyright (c) 2022 Ephox Corporation DBA Tiny Technologies, Inc.
4
+ * Copyright (c) 2024 TrueRTE contributors
5
+ * Licensed under the MIT license (https://github.com/truerte/truerte-react/blob/main/LICENSE.TXT)
6
+ */
7
+ import * as React from 'react';
8
+ import { IEvents } from '../Events';
9
+ import type { Editor as TrueRTEEditor, TrueRTE } from 'truerte';
10
+ type OmitStringIndexSignature<T> = {
11
+ [K in keyof T as string extends K ? never : K]: T[K];
12
+ };
13
+ interface DoNotUse<T extends string> {
14
+ __brand: T;
15
+ }
16
+ type OmittedInitProps = 'selector' | 'target' | 'readonly';
17
+ type EditorOptions = Parameters<TrueRTE['init']>[0];
18
+ export type InitOptions = Omit<OmitStringIndexSignature<EditorOptions>, OmittedInitProps> & {
19
+ selector?: DoNotUse<'selector prop is handled internally by the component'>;
20
+ target?: DoNotUse<'target prop is handled internally by the component'>;
21
+ readonly?: DoNotUse<'readonly prop is overridden by the component, use the `disabled` prop instead'>;
22
+ } & {
23
+ [key: string]: unknown;
24
+ };
25
+ export type Version = `${'1'}${'' | `.${number}` | `.${number}.${number}`}`;
26
+ export type EditorInstanceRef = React.Ref<TrueRTEEditor | null>;
27
+ export interface IProps {
28
+ /**
29
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#id React Tech Ref - id}
30
+ * @description The ID of the element to render the editor into.
31
+ */
32
+ id: string;
33
+ /**
34
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#inline React Tech Ref - inline}
35
+ * @description Whether the editor should be rendered inline. Equivalent to the `inline` option in TrueRTE.
36
+ */
37
+ inline: boolean;
38
+ /**
39
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#initialvalue React Tech Ref - initialValue}
40
+ * @description The initial HTML content of the editor.
41
+ *
42
+ * IMPORTANT: Ensure that this is **not** updated by `onEditorChange` or the editor will be unusable.
43
+ */
44
+ initialValue: string;
45
+ /**
46
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#oneditorchange React Tech Ref - onEditorChange}
47
+ * @description Used to store the state of the editor outside the component. Typically used for controlled components.
48
+ * @param a The current HTML content of the editor.
49
+ * @param editor The TrueRTE editor instance.
50
+ * @returns void
51
+ */
52
+ onEditorChange: (a: string, editor: TrueRTEEditor) => void;
53
+ /**
54
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#value React Tech Ref - value}
55
+ * @description The current HTML content of the editor. Typically used for controlled components.
56
+ */
57
+ value: string;
58
+ /**
59
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#init React Tech Ref - init}
60
+ * @description Additional settings passed to `truerte.init()` when initializing the editor.
61
+ */
62
+ init: InitOptions;
63
+ /**
64
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#tagname React Tech Ref - tagName}
65
+ * @description The tag name of the element to render the editor into. Only valid when `inline` is `true`.
66
+ */
67
+ tagName: string;
68
+ /**
69
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#tabIndex React Tech Ref - tabIndex}
70
+ * @description The tab index of the element that the editor wraps.
71
+ */
72
+ tabIndex: number;
73
+ /**
74
+ * @description The TrueRTE version to use when loading from jsDelivr CDN. By default, version 1
75
+ * (that is, the latest minor and patch release of the major version 1) will be used.
76
+ * For more info about the possible version formats, see the {@link https://www.jsdelivr.com/documentation#id-npm jsDelivr documentation}.
77
+ */
78
+ cdnVersion: Version;
79
+ /**
80
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#plugins React Tech Ref - plugins}
81
+ * @description The plugins to load into the editor. Equivalent to the `plugins` option in TrueRTE.
82
+ */
83
+ plugins: NonNullable<EditorOptions['plugins']>;
84
+ /**
85
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#toolbar React Tech Ref - toolbar}
86
+ * @description The toolbar to load into the editor. Equivalent to the `toolbar` option in TrueRTE.
87
+ */
88
+ toolbar: NonNullable<EditorOptions['toolbar']>;
89
+ /**
90
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#disabled React Tech Ref - disabled}
91
+ * @description Whether the editor should be "disabled" (read-only).
92
+ */
93
+ disabled: boolean;
94
+ /**
95
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#textareaname React Tech Ref - textareaName}
96
+ * @description Set the `name` attribute of the `textarea` element used for the editor in forms. Only valid in iframe mode.
97
+ */
98
+ textareaName: string;
99
+ /**
100
+ * @description Optional external ref that receives the underlying TrueRTE editor instance.
101
+ * Use this for imperative control from outside the component.
102
+ */
103
+ editorRef: EditorInstanceRef;
104
+ /**
105
+ * @description The URL of the TrueRTE script to lazy load.
106
+ */
107
+ truerteScriptSrc: string;
108
+ /**
109
+ * @description When true, automatically configures `icons: 'truerte-lucide'`
110
+ * unless you explicitly provide `init.icons` or `init.icons_url`.
111
+ */
112
+ useLucideIcons: boolean;
113
+ /**
114
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#rollback React Tech Ref - rollback}
115
+ * @description The number of milliseconds to wait before reverting to the previous value when the editor's content changes.
116
+ */
117
+ rollback: number | false;
118
+ /**
119
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/#scriptloading React Tech Ref - scriptLoading}
120
+ * @description Options for how the TrueRTE script should be loaded.
121
+ * @property async Whether the script should be loaded with the `async` attribute.
122
+ * @property defer Whether the script should be loaded with the `defer` attribute.
123
+ * @property delay The number of milliseconds to wait before loading the script.
124
+ */
125
+ scriptLoading: {
126
+ async?: boolean;
127
+ defer?: boolean;
128
+ delay?: number;
129
+ };
130
+ }
131
+ export interface IAllProps extends Partial<IProps>, Partial<IEvents> {
132
+ }
133
+ /**
134
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/ TrueRTE React Technical Reference}
135
+ */
136
+ export declare class Editor extends React.Component<IAllProps> {
137
+ static defaultProps: Partial<IAllProps>;
138
+ editor?: TrueRTEEditor;
139
+ private id;
140
+ private elementRef;
141
+ private inline;
142
+ private currentContent?;
143
+ private boundHandlers;
144
+ private rollbackTimer;
145
+ private valueCursor;
146
+ constructor(props: Partial<IAllProps>);
147
+ private get view();
148
+ componentDidUpdate(prevProps: Partial<IAllProps>): void;
149
+ componentDidMount(): void;
150
+ componentWillUnmount(): void;
151
+ render(): React.ReactElement<{
152
+ ref: React.RefObject<HTMLElement | null>;
153
+ id: string;
154
+ tabIndex: number | undefined;
155
+ }, string | React.JSXElementConstructor<any>>;
156
+ getEditor(): TrueRTEEditor | undefined;
157
+ private beforeInputEvent;
158
+ private renderInline;
159
+ private renderIframe;
160
+ private getScriptSources;
161
+ private getInitialValue;
162
+ private bindHandlers;
163
+ private rollbackChange;
164
+ private handleBeforeInput;
165
+ private handleBeforeInputSpecial;
166
+ private handleEditorChange;
167
+ private handleEditorChangeSpecial;
168
+ private assignEditorRef;
169
+ private initialise;
170
+ }
171
+ export {};
@@ -0,0 +1,358 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Editor = void 0;
4
+ /**
5
+ * Official TrueRTE React component
6
+ * Copyright (c) 2022 Ephox Corporation DBA Tiny Technologies, Inc.
7
+ * Copyright (c) 2024 TrueRTE contributors
8
+ * Licensed under the MIT license (https://github.com/truerte/truerte-react/blob/main/LICENSE.TXT)
9
+ */
10
+ const React = require("react");
11
+ const ScriptLoader2_1 = require("../ScriptLoader2");
12
+ const TrueRTE_1 = require("../TrueRTE");
13
+ const Utils_1 = require("../Utils");
14
+ const Uuid_1 = require("../Uuid");
15
+ const changeEvents = 'change keyup compositionend setcontent CommentChange';
16
+ /**
17
+ * @see {@link https://www.truerte.org/docs/truerte/1/react-ref/ TrueRTE React Technical Reference}
18
+ */
19
+ class Editor extends React.Component {
20
+ constructor(props) {
21
+ var _a, _b, _c;
22
+ super(props);
23
+ this.rollbackTimer = undefined;
24
+ this.valueCursor = undefined;
25
+ this.rollbackChange = () => {
26
+ const editor = this.editor;
27
+ const value = this.props.value;
28
+ if (editor && value && value !== this.currentContent) {
29
+ editor.undoManager.ignore(() => {
30
+ editor.setContent(value);
31
+ // only restore cursor on inline editors when they are focused
32
+ // as otherwise it will cause a focus grab
33
+ if (this.valueCursor && (!this.inline || editor.hasFocus())) {
34
+ try {
35
+ editor.selection.moveToBookmark(this.valueCursor);
36
+ }
37
+ catch (e) { /* ignore */ }
38
+ }
39
+ });
40
+ }
41
+ this.rollbackTimer = undefined;
42
+ };
43
+ this.handleBeforeInput = (_evt) => {
44
+ if (this.props.value !== undefined && this.props.value === this.currentContent && this.editor) {
45
+ if (!this.inline || this.editor.hasFocus()) {
46
+ try {
47
+ // getBookmark throws exceptions when the editor has not been focused
48
+ // possibly only in inline mode but I'm not taking chances
49
+ this.valueCursor = this.editor.selection.getBookmark(3);
50
+ }
51
+ catch (e) { /* ignore */ }
52
+ }
53
+ }
54
+ };
55
+ this.handleBeforeInputSpecial = (evt) => {
56
+ if (evt.key === 'Enter' || evt.key === 'Backspace' || evt.key === 'Delete') {
57
+ this.handleBeforeInput(evt);
58
+ }
59
+ };
60
+ this.handleEditorChange = (_evt) => {
61
+ const editor = this.editor;
62
+ if (editor && editor.initialized) {
63
+ const newContent = editor.getContent();
64
+ if (this.props.value !== undefined && this.props.value !== newContent && this.props.rollback !== false) {
65
+ // start a timer and revert to the value if not applied in time
66
+ if (!this.rollbackTimer) {
67
+ this.rollbackTimer = window.setTimeout(this.rollbackChange, typeof this.props.rollback === 'number' ? this.props.rollback : 200);
68
+ }
69
+ }
70
+ if (newContent !== this.currentContent) {
71
+ this.currentContent = newContent;
72
+ if ((0, Utils_1.isFunction)(this.props.onEditorChange)) {
73
+ this.props.onEditorChange(newContent, editor);
74
+ }
75
+ }
76
+ }
77
+ };
78
+ this.handleEditorChangeSpecial = (evt) => {
79
+ if (evt.key === 'Backspace' || evt.key === 'Delete') {
80
+ this.handleEditorChange(evt);
81
+ }
82
+ };
83
+ this.assignEditorRef = (editorRef, editor) => {
84
+ if (editorRef === undefined || editorRef === null) {
85
+ return;
86
+ }
87
+ if (typeof editorRef === 'function') {
88
+ editorRef(editor);
89
+ }
90
+ else {
91
+ editorRef.current = editor;
92
+ }
93
+ };
94
+ this.initialise = (attempts = 0) => {
95
+ var _a, _b, _c, _d, _e, _f;
96
+ const target = this.elementRef.current;
97
+ if (!target) {
98
+ return; // Editor has been unmounted
99
+ }
100
+ if (!target.isConnected) {
101
+ // this is probably someone trying to help by rendering us offscreen
102
+ // but we can't do that because the editor iframe must be in the document
103
+ // in order to have state
104
+ // TODO: how will this do when we use web component?
105
+ if (attempts === 0) {
106
+ // we probably just need to wait for the current events to be processed
107
+ setTimeout(() => this.initialise(1), 1);
108
+ }
109
+ else if (attempts < 100) {
110
+ // wait for ten seconds, polling every tenth of a second
111
+ setTimeout(() => this.initialise(attempts + 1), 100);
112
+ }
113
+ else {
114
+ // give up, at this point it seems that more polling is unlikely to help
115
+ throw new Error('truerte can only be initialised when in a document');
116
+ }
117
+ return;
118
+ }
119
+ const truerte = (0, TrueRTE_1.getTrueRTE)(this.view);
120
+ if (!truerte) {
121
+ throw new Error('truerte should have been loaded into global scope');
122
+ }
123
+ const resolvedPlugins = (0, Utils_1.mergePlugins)((_a = this.props.init) === null || _a === void 0 ? void 0 : _a.plugins, this.props.plugins);
124
+ const hasExplicitIconConfig = ((_b = this.props.init) === null || _b === void 0 ? void 0 : _b.icons) !== undefined || ((_c = this.props.init) === null || _c === void 0 ? void 0 : _c.icons_url) !== undefined;
125
+ const resolvedIconPack = this.props.useLucideIcons === true && !hasExplicitIconConfig
126
+ ? 'truerte-lucide'
127
+ : (_d = this.props.init) === null || _d === void 0 ? void 0 : _d.icons;
128
+ const finalInit = Object.assign(Object.assign({}, this.props.init), { selector: undefined, target, readonly: this.props.disabled, inline: this.inline, plugins: resolvedPlugins, icons: resolvedIconPack, toolbar: (_e = this.props.toolbar) !== null && _e !== void 0 ? _e : (_f = this.props.init) === null || _f === void 0 ? void 0 : _f.toolbar, setup: (editor) => {
129
+ this.editor = editor;
130
+ this.assignEditorRef(this.props.editorRef, editor);
131
+ this.bindHandlers({});
132
+ // When running in inline mode the editor gets the initial value
133
+ // from the innerHTML of the element it is initialized on.
134
+ // However we don't want to take on the responsibility of sanitizing
135
+ // to remove XSS in the react integration so we have a chicken and egg
136
+ // problem... We avoid it by sneaking in a set content before the first
137
+ // "official" setContent and using TrueRTE to do the sanitization.
138
+ if (this.inline && !(0, Utils_1.isTextareaOrInput)(target)) {
139
+ editor.once('PostRender', (_evt) => {
140
+ editor.setContent(this.getInitialValue(), { no_events: true });
141
+ });
142
+ }
143
+ if (this.props.init && (0, Utils_1.isFunction)(this.props.init.setup)) {
144
+ this.props.init.setup(editor);
145
+ }
146
+ }, init_instance_callback: (editor) => {
147
+ var _a, _b;
148
+ // check for changes that happened since truerte.init() was called
149
+ const initialValue = this.getInitialValue();
150
+ this.currentContent = (_a = this.currentContent) !== null && _a !== void 0 ? _a : editor.getContent();
151
+ if (this.currentContent !== initialValue) {
152
+ this.currentContent = initialValue;
153
+ // same as resetContent in TrueRTE 5
154
+ editor.setContent(initialValue);
155
+ editor.undoManager.clear();
156
+ editor.undoManager.add();
157
+ editor.setDirty(false);
158
+ }
159
+ const disabled = (_b = this.props.disabled) !== null && _b !== void 0 ? _b : false;
160
+ (0, Utils_1.setMode)(this.editor, disabled ? 'readonly' : 'design');
161
+ // ensure existing init_instance_callback is called
162
+ if (this.props.init && (0, Utils_1.isFunction)(this.props.init.init_instance_callback)) {
163
+ this.props.init.init_instance_callback(editor);
164
+ }
165
+ } });
166
+ if (!this.inline) {
167
+ target.style.visibility = '';
168
+ }
169
+ if ((0, Utils_1.isTextareaOrInput)(target)) {
170
+ target.value = this.getInitialValue();
171
+ }
172
+ truerte.init(finalInit);
173
+ };
174
+ this.id = this.props.id || (0, Uuid_1.uuid)('truerte-react');
175
+ this.elementRef = React.createRef();
176
+ this.inline = (_c = (_a = this.props.inline) !== null && _a !== void 0 ? _a : (_b = this.props.init) === null || _b === void 0 ? void 0 : _b.inline) !== null && _c !== void 0 ? _c : false;
177
+ this.boundHandlers = {};
178
+ }
179
+ get view() {
180
+ var _a, _b;
181
+ return (_b = (_a = this.elementRef.current) === null || _a === void 0 ? void 0 : _a.ownerDocument.defaultView) !== null && _b !== void 0 ? _b : window;
182
+ }
183
+ componentDidUpdate(prevProps) {
184
+ var _a, _b, _c;
185
+ if (this.props.editorRef !== prevProps.editorRef) {
186
+ this.assignEditorRef(prevProps.editorRef, null);
187
+ this.assignEditorRef(this.props.editorRef, (_a = this.editor) !== null && _a !== void 0 ? _a : null);
188
+ }
189
+ if (this.rollbackTimer) {
190
+ clearTimeout(this.rollbackTimer);
191
+ this.rollbackTimer = undefined;
192
+ }
193
+ if (this.editor) {
194
+ this.bindHandlers(prevProps);
195
+ if (this.editor.initialized) {
196
+ this.currentContent = (_b = this.currentContent) !== null && _b !== void 0 ? _b : this.editor.getContent();
197
+ if (typeof this.props.initialValue === 'string' && this.props.initialValue !== prevProps.initialValue) {
198
+ // same as resetContent in TinyMCE 5 – TODO what does this mean for TrueRTE?
199
+ this.editor.setContent(this.props.initialValue);
200
+ this.editor.undoManager.clear();
201
+ this.editor.undoManager.add();
202
+ this.editor.setDirty(false);
203
+ }
204
+ else if (typeof this.props.value === 'string' && this.props.value !== this.currentContent) {
205
+ const localEditor = this.editor;
206
+ localEditor.undoManager.transact(() => {
207
+ // inline editors grab focus when restoring selection
208
+ // so we don't try to keep their selection unless they are currently focused
209
+ let cursor;
210
+ if (!this.inline || localEditor.hasFocus()) {
211
+ try {
212
+ // getBookmark throws exceptions when the editor has not been focused
213
+ // possibly only in inline mode but I'm not taking chances
214
+ cursor = localEditor.selection.getBookmark(3);
215
+ }
216
+ catch (e) { /* ignore */ }
217
+ }
218
+ const valueCursor = this.valueCursor;
219
+ localEditor.setContent(this.props.value);
220
+ if (!this.inline || localEditor.hasFocus()) {
221
+ for (const bookmark of [cursor, valueCursor]) {
222
+ if (bookmark) {
223
+ try {
224
+ localEditor.selection.moveToBookmark(bookmark);
225
+ this.valueCursor = bookmark;
226
+ break;
227
+ }
228
+ catch (e) { /* ignore */ }
229
+ }
230
+ }
231
+ }
232
+ });
233
+ }
234
+ if (this.props.disabled !== prevProps.disabled) {
235
+ const disabled = (_c = this.props.disabled) !== null && _c !== void 0 ? _c : false;
236
+ (0, Utils_1.setMode)(this.editor, disabled ? 'readonly' : 'design');
237
+ }
238
+ }
239
+ }
240
+ }
241
+ componentDidMount() {
242
+ var _a, _b, _c, _d, _e;
243
+ if ((0, TrueRTE_1.getTrueRTE)(this.view) !== null) {
244
+ this.initialise();
245
+ }
246
+ else if (Array.isArray(this.props.truerteScriptSrc) && this.props.truerteScriptSrc.length === 0) {
247
+ (_b = (_a = this.props).onScriptsLoadError) === null || _b === void 0 ? void 0 : _b.call(_a, new Error('No `truerte` global is present but the `truerteScriptSrc` prop was an empty array.'));
248
+ }
249
+ else if ((_c = this.elementRef.current) === null || _c === void 0 ? void 0 : _c.ownerDocument) {
250
+ const successHandler = () => {
251
+ var _a, _b;
252
+ (_b = (_a = this.props).onScriptsLoad) === null || _b === void 0 ? void 0 : _b.call(_a);
253
+ this.initialise();
254
+ };
255
+ const errorHandler = (err) => {
256
+ var _a, _b;
257
+ (_b = (_a = this.props).onScriptsLoadError) === null || _b === void 0 ? void 0 : _b.call(_a, err);
258
+ };
259
+ ScriptLoader2_1.ScriptLoader.loadList(this.elementRef.current.ownerDocument, this.getScriptSources(), (_e = (_d = this.props.scriptLoading) === null || _d === void 0 ? void 0 : _d.delay) !== null && _e !== void 0 ? _e : 0, successHandler, errorHandler);
260
+ }
261
+ }
262
+ componentWillUnmount() {
263
+ const editor = this.editor;
264
+ if (editor) {
265
+ editor.off(changeEvents, this.handleEditorChange);
266
+ editor.off(this.beforeInputEvent(), this.handleBeforeInput);
267
+ editor.off('keypress', this.handleEditorChangeSpecial);
268
+ editor.off('keydown', this.handleBeforeInputSpecial);
269
+ editor.off('NewBlock', this.handleEditorChange);
270
+ Object.keys(this.boundHandlers).forEach((eventName) => {
271
+ editor.off(eventName, this.boundHandlers[eventName]);
272
+ });
273
+ this.boundHandlers = {};
274
+ editor.remove();
275
+ this.editor = undefined;
276
+ }
277
+ this.assignEditorRef(this.props.editorRef, null);
278
+ }
279
+ render() {
280
+ return this.inline ? this.renderInline() : this.renderIframe();
281
+ }
282
+ getEditor() {
283
+ return this.editor;
284
+ }
285
+ beforeInputEvent() {
286
+ return (0, Utils_1.isBeforeInputEventAvailable)() ? 'beforeinput SelectionChange' : 'SelectionChange';
287
+ }
288
+ renderInline() {
289
+ const { tagName = 'div' } = this.props;
290
+ return React.createElement(tagName, {
291
+ ref: this.elementRef,
292
+ id: this.id,
293
+ tabIndex: this.props.tabIndex
294
+ });
295
+ }
296
+ renderIframe() {
297
+ return React.createElement('textarea', {
298
+ ref: this.elementRef,
299
+ style: { visibility: 'hidden' },
300
+ name: this.props.textareaName,
301
+ id: this.id,
302
+ tabIndex: this.props.tabIndex
303
+ });
304
+ }
305
+ getScriptSources() {
306
+ var _a, _b;
307
+ const async = (_a = this.props.scriptLoading) === null || _a === void 0 ? void 0 : _a.async;
308
+ const defer = (_b = this.props.scriptLoading) === null || _b === void 0 ? void 0 : _b.defer;
309
+ if (this.props.truerteScriptSrc !== undefined) {
310
+ if (typeof this.props.truerteScriptSrc === 'string') {
311
+ return [{ src: this.props.truerteScriptSrc, async, defer }];
312
+ }
313
+ }
314
+ // fallback to jsDelivr CDN when the truerteScriptSrc is not specified
315
+ // `cdnVersion` is in `defaultProps`, so it's always defined.
316
+ const cdnLink = `https://cdn.jsdelivr.net/npm/truerte@${this.props.cdnVersion}/truerte.min.js`;
317
+ return [{ src: cdnLink, async, defer }];
318
+ }
319
+ getInitialValue() {
320
+ if (typeof this.props.initialValue === 'string') {
321
+ return this.props.initialValue;
322
+ }
323
+ else if (typeof this.props.value === 'string') {
324
+ return this.props.value;
325
+ }
326
+ else {
327
+ return '';
328
+ }
329
+ }
330
+ bindHandlers(prevProps) {
331
+ if (this.editor !== undefined) {
332
+ // typescript chokes trying to understand the type of the lookup function
333
+ (0, Utils_1.configHandlers)(this.editor, prevProps, this.props, this.boundHandlers, (key) => this.props[key]);
334
+ // check if we should monitor editor changes
335
+ const isValueControlled = (p) => p.onEditorChange !== undefined || p.value !== undefined;
336
+ const wasControlled = isValueControlled(prevProps);
337
+ const nowControlled = isValueControlled(this.props);
338
+ if (!wasControlled && nowControlled) {
339
+ this.editor.on(changeEvents, this.handleEditorChange);
340
+ this.editor.on(this.beforeInputEvent(), this.handleBeforeInput);
341
+ this.editor.on('keydown', this.handleBeforeInputSpecial);
342
+ this.editor.on('keyup', this.handleEditorChangeSpecial);
343
+ this.editor.on('NewBlock', this.handleEditorChange);
344
+ }
345
+ else if (wasControlled && !nowControlled) {
346
+ this.editor.off(changeEvents, this.handleEditorChange);
347
+ this.editor.off(this.beforeInputEvent(), this.handleBeforeInput);
348
+ this.editor.off('keydown', this.handleBeforeInputSpecial);
349
+ this.editor.off('keyup', this.handleEditorChangeSpecial);
350
+ this.editor.off('NewBlock', this.handleEditorChange);
351
+ }
352
+ }
353
+ }
354
+ }
355
+ exports.Editor = Editor;
356
+ Editor.defaultProps = {
357
+ cdnVersion: '1',
358
+ };
@@ -0,0 +1,2 @@
1
+ import { Editor, EditorInstanceRef, IAllProps, IProps, InitOptions } from './components/Editor';
2
+ export { Editor, IAllProps, IProps, InitOptions, EditorInstanceRef };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Editor = void 0;
4
+ const Editor_1 = require("./components/Editor");
5
+ Object.defineProperty(exports, "Editor", { enumerable: true, get: function () { return Editor_1.Editor; } });
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Official TrueRTE React component
3
+ * Copyright (c) 2026 TrueRTE contributors
4
+ * Licensed under the MIT license (https://github.com/truerte/truerte-react/blob/main/LICENSE.TXT)
5
+ */
6
+ export declare const nativeEvents: readonly ["BeforePaste", "Blur", "Click", "CompositionEnd", "CompositionStart", "CompositionUpdate", "ContextMenu", "Copy", "Cut", "Dblclick", "Drag", "DragDrop", "DragEnd", "DragGesture", "DragOver", "Drop", "Focus", "FocusIn", "FocusOut", "Input", "KeyDown", "KeyPress", "KeyUp", "MouseDown", "MouseEnter", "MouseLeave", "MouseMove", "MouseOut", "MouseOver", "MouseUp", "Paste", "SelectionChange"];
7
+ export declare const customEvents: readonly ["Activate", "AddUndo", "BeforeAddUndo", "BeforeExecCommand", "BeforeGetContent", "BeforeRenderUI", "BeforeSetContent", "Change", "ClearUndos", "CommentChange", "Deactivate", "Dirty", "ExecCommand", "GetContent", "Hide", "IconsLoadError", "Init", "LanguageLoadError", "LoadContent", "ModelLoadError", "NodeChange", "ObjectResizeStart", "ObjectResized", "ObjectSelected", "PluginLoadError", "PostProcess", "PostRender", "PreProcess", "ProgressState", "Redo", "Remove", "Reset", "ResizeEditor", "SaveContent", "SetAttrib", "SetContent", "Show", "SkinLoadError", "Submit", "ThemeLoadError", "Undo", "VisualAid"];
8
+ export declare const validEvents: readonly ["BeforePaste", "Blur", "Click", "CompositionEnd", "CompositionStart", "CompositionUpdate", "ContextMenu", "Copy", "Cut", "Dblclick", "Drag", "DragDrop", "DragEnd", "DragGesture", "DragOver", "Drop", "Focus", "FocusIn", "FocusOut", "Input", "KeyDown", "KeyPress", "KeyUp", "MouseDown", "MouseEnter", "MouseLeave", "MouseMove", "MouseOut", "MouseOver", "MouseUp", "Paste", "SelectionChange", "Activate", "AddUndo", "BeforeAddUndo", "BeforeExecCommand", "BeforeGetContent", "BeforeRenderUI", "BeforeSetContent", "Change", "ClearUndos", "CommentChange", "Deactivate", "Dirty", "ExecCommand", "GetContent", "Hide", "IconsLoadError", "Init", "LanguageLoadError", "LoadContent", "ModelLoadError", "NodeChange", "ObjectResizeStart", "ObjectResized", "ObjectSelected", "PluginLoadError", "PostProcess", "PostRender", "PreProcess", "ProgressState", "Redo", "Remove", "Reset", "ResizeEditor", "SaveContent", "SetAttrib", "SetContent", "Show", "SkinLoadError", "Submit", "ThemeLoadError", "Undo", "VisualAid"];
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Official TrueRTE React component
3
+ * Copyright (c) 2026 TrueRTE contributors
4
+ * Licensed under the MIT license (https://github.com/truerte/truerte-react/blob/main/LICENSE.TXT)
5
+ */
6
+ export const nativeEvents = [
7
+ 'BeforePaste',
8
+ 'Blur',
9
+ 'Click',
10
+ 'CompositionEnd',
11
+ 'CompositionStart',
12
+ 'CompositionUpdate',
13
+ 'ContextMenu',
14
+ 'Copy',
15
+ 'Cut',
16
+ 'Dblclick',
17
+ 'Drag',
18
+ 'DragDrop',
19
+ 'DragEnd',
20
+ 'DragGesture',
21
+ 'DragOver',
22
+ 'Drop',
23
+ 'Focus',
24
+ 'FocusIn',
25
+ 'FocusOut',
26
+ 'Input',
27
+ 'KeyDown',
28
+ 'KeyPress',
29
+ 'KeyUp',
30
+ 'MouseDown',
31
+ 'MouseEnter',
32
+ 'MouseLeave',
33
+ 'MouseMove',
34
+ 'MouseOut',
35
+ 'MouseOver',
36
+ 'MouseUp',
37
+ 'Paste',
38
+ 'SelectionChange',
39
+ ];
40
+ export const customEvents = [
41
+ 'Activate',
42
+ 'AddUndo',
43
+ 'BeforeAddUndo',
44
+ 'BeforeExecCommand',
45
+ 'BeforeGetContent',
46
+ 'BeforeRenderUI',
47
+ 'BeforeSetContent',
48
+ 'Change',
49
+ 'ClearUndos',
50
+ 'CommentChange',
51
+ 'Deactivate',
52
+ 'Dirty',
53
+ 'ExecCommand',
54
+ 'GetContent',
55
+ 'Hide',
56
+ 'IconsLoadError',
57
+ 'Init',
58
+ 'LanguageLoadError',
59
+ 'LoadContent',
60
+ 'ModelLoadError',
61
+ 'NodeChange',
62
+ 'ObjectResizeStart',
63
+ 'ObjectResized',
64
+ 'ObjectSelected',
65
+ 'PluginLoadError',
66
+ 'PostProcess',
67
+ 'PostRender',
68
+ 'PreProcess',
69
+ 'ProgressState',
70
+ 'Redo',
71
+ 'Remove',
72
+ 'Reset',
73
+ 'ResizeEditor',
74
+ 'SaveContent',
75
+ 'SetAttrib',
76
+ 'SetContent',
77
+ 'Show',
78
+ 'SkinLoadError',
79
+ 'Submit',
80
+ 'ThemeLoadError',
81
+ 'Undo',
82
+ 'VisualAid',
83
+ ];
84
+ export const validEvents = [...nativeEvents, ...customEvents];