@ekz/lexical-rich-text 0.40.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/EkzLexicalRichText.dev.js +854 -0
- package/EkzLexicalRichText.dev.mjs +843 -0
- package/EkzLexicalRichText.js +11 -0
- package/EkzLexicalRichText.mjs +21 -0
- package/EkzLexicalRichText.node.mjs +19 -0
- package/EkzLexicalRichText.prod.js +9 -0
- package/EkzLexicalRichText.prod.mjs +9 -0
- package/LICENSE +21 -0
- package/LexicalRichText.js.flow +72 -0
- package/README.md +5 -0
- package/index.d.ts +59 -0
- package/package.json +44 -0
|
@@ -0,0 +1,854 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
var lexicalClipboard = require('@ekz/lexical-clipboard');
|
|
12
|
+
var lexicalDragon = require('@ekz/lexical-dragon');
|
|
13
|
+
var lexicalSelection = require('@ekz/lexical-selection');
|
|
14
|
+
var lexicalUtils = require('@ekz/lexical-utils');
|
|
15
|
+
var lexical = require('@ekz/lexical');
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
19
|
+
*
|
|
20
|
+
* This source code is licensed under the MIT license found in the
|
|
21
|
+
* LICENSE file in the root directory of this source tree.
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
function caretFromPoint(x, y) {
|
|
26
|
+
if (typeof document.caretRangeFromPoint !== 'undefined') {
|
|
27
|
+
const range = document.caretRangeFromPoint(x, y);
|
|
28
|
+
if (range === null) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
node: range.startContainer,
|
|
33
|
+
offset: range.startOffset
|
|
34
|
+
};
|
|
35
|
+
// @ts-ignore
|
|
36
|
+
} else if (document.caretPositionFromPoint !== 'undefined') {
|
|
37
|
+
// @ts-ignore FF - no types
|
|
38
|
+
const range = document.caretPositionFromPoint(x, y);
|
|
39
|
+
if (range === null) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
node: range.offsetNode,
|
|
44
|
+
offset: range.offset
|
|
45
|
+
};
|
|
46
|
+
} else {
|
|
47
|
+
// Gracefully handle IE
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
54
|
+
*
|
|
55
|
+
* This source code is licensed under the MIT license found in the
|
|
56
|
+
* LICENSE file in the root directory of this source tree.
|
|
57
|
+
*
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
const CAN_USE_DOM = typeof window !== 'undefined' && typeof window.document !== 'undefined' && typeof window.document.createElement !== 'undefined';
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
64
|
+
*
|
|
65
|
+
* This source code is licensed under the MIT license found in the
|
|
66
|
+
* LICENSE file in the root directory of this source tree.
|
|
67
|
+
*
|
|
68
|
+
*/
|
|
69
|
+
|
|
70
|
+
const documentMode = CAN_USE_DOM && 'documentMode' in document ? document.documentMode : null;
|
|
71
|
+
const IS_APPLE = CAN_USE_DOM && /Mac|iPod|iPhone|iPad/.test(navigator.platform);
|
|
72
|
+
const CAN_USE_BEFORE_INPUT = CAN_USE_DOM && 'InputEvent' in window && !documentMode ? 'getTargetRanges' in new window.InputEvent('input') : false;
|
|
73
|
+
const IS_SAFARI = CAN_USE_DOM && /Version\/[\d.]+.*Safari/.test(navigator.userAgent);
|
|
74
|
+
const IS_IOS = CAN_USE_DOM && /iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream;
|
|
75
|
+
|
|
76
|
+
// Keep these in case we need to use them in the future.
|
|
77
|
+
// export const IS_WINDOWS: boolean = CAN_USE_DOM && /Win/.test(navigator.platform);
|
|
78
|
+
const IS_CHROME = CAN_USE_DOM && /^(?=.*Chrome).*/i.test(navigator.userAgent);
|
|
79
|
+
const IS_APPLE_WEBKIT = CAN_USE_DOM && /AppleWebKit\/[\d.]+/.test(navigator.userAgent) && IS_APPLE && !IS_CHROME;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
83
|
+
*
|
|
84
|
+
* This source code is licensed under the MIT license found in the
|
|
85
|
+
* LICENSE file in the root directory of this source tree.
|
|
86
|
+
*
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
const DRAG_DROP_PASTE = lexical.createCommand('DRAG_DROP_PASTE_FILE');
|
|
90
|
+
/** @noInheritDoc */
|
|
91
|
+
class QuoteNode extends lexical.ElementNode {
|
|
92
|
+
static getType() {
|
|
93
|
+
return 'quote';
|
|
94
|
+
}
|
|
95
|
+
static clone(node) {
|
|
96
|
+
return new QuoteNode(node.__key);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// View
|
|
100
|
+
|
|
101
|
+
createDOM(config) {
|
|
102
|
+
const element = document.createElement('blockquote');
|
|
103
|
+
lexicalUtils.addClassNamesToElement(element, config.theme.quote);
|
|
104
|
+
return element;
|
|
105
|
+
}
|
|
106
|
+
updateDOM(prevNode, dom) {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
static importDOM() {
|
|
110
|
+
return {
|
|
111
|
+
blockquote: node => ({
|
|
112
|
+
conversion: $convertBlockquoteElement,
|
|
113
|
+
priority: 0
|
|
114
|
+
})
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
exportDOM(editor) {
|
|
118
|
+
const {
|
|
119
|
+
element
|
|
120
|
+
} = super.exportDOM(editor);
|
|
121
|
+
if (lexicalUtils.isHTMLElement(element)) {
|
|
122
|
+
if (this.isEmpty()) {
|
|
123
|
+
element.append(document.createElement('br'));
|
|
124
|
+
}
|
|
125
|
+
const formatType = this.getFormatType();
|
|
126
|
+
if (formatType) {
|
|
127
|
+
element.style.textAlign = formatType;
|
|
128
|
+
}
|
|
129
|
+
const direction = this.getDirection();
|
|
130
|
+
if (direction) {
|
|
131
|
+
element.dir = direction;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
element
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
static importJSON(serializedNode) {
|
|
139
|
+
return $createQuoteNode().updateFromJSON(serializedNode);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Mutation
|
|
143
|
+
|
|
144
|
+
insertNewAfter(_, restoreSelection) {
|
|
145
|
+
const newBlock = lexical.$createParagraphNode();
|
|
146
|
+
const direction = this.getDirection();
|
|
147
|
+
newBlock.setDirection(direction);
|
|
148
|
+
this.insertAfter(newBlock, restoreSelection);
|
|
149
|
+
return newBlock;
|
|
150
|
+
}
|
|
151
|
+
collapseAtStart() {
|
|
152
|
+
const paragraph = lexical.$createParagraphNode();
|
|
153
|
+
const children = this.getChildren();
|
|
154
|
+
children.forEach(child => paragraph.append(child));
|
|
155
|
+
this.replace(paragraph);
|
|
156
|
+
return true;
|
|
157
|
+
}
|
|
158
|
+
canMergeWhenEmpty() {
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function $createQuoteNode() {
|
|
163
|
+
return lexical.$applyNodeReplacement(new QuoteNode());
|
|
164
|
+
}
|
|
165
|
+
function $isQuoteNode(node) {
|
|
166
|
+
return node instanceof QuoteNode;
|
|
167
|
+
}
|
|
168
|
+
/** @noInheritDoc */
|
|
169
|
+
class HeadingNode extends lexical.ElementNode {
|
|
170
|
+
/** @internal */
|
|
171
|
+
__tag;
|
|
172
|
+
static getType() {
|
|
173
|
+
return 'heading';
|
|
174
|
+
}
|
|
175
|
+
static clone(node) {
|
|
176
|
+
return new HeadingNode(node.__tag, node.__key);
|
|
177
|
+
}
|
|
178
|
+
constructor(tag, key) {
|
|
179
|
+
super(key);
|
|
180
|
+
this.__tag = tag;
|
|
181
|
+
}
|
|
182
|
+
getTag() {
|
|
183
|
+
return this.__tag;
|
|
184
|
+
}
|
|
185
|
+
setTag(tag) {
|
|
186
|
+
const self = this.getWritable();
|
|
187
|
+
this.__tag = tag;
|
|
188
|
+
return self;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// View
|
|
192
|
+
|
|
193
|
+
createDOM(config) {
|
|
194
|
+
const tag = this.__tag;
|
|
195
|
+
const element = document.createElement(tag);
|
|
196
|
+
const theme = config.theme;
|
|
197
|
+
const classNames = theme.heading;
|
|
198
|
+
if (classNames !== undefined) {
|
|
199
|
+
const className = classNames[tag];
|
|
200
|
+
lexicalUtils.addClassNamesToElement(element, className);
|
|
201
|
+
}
|
|
202
|
+
return element;
|
|
203
|
+
}
|
|
204
|
+
updateDOM(prevNode, dom, config) {
|
|
205
|
+
return prevNode.__tag !== this.__tag;
|
|
206
|
+
}
|
|
207
|
+
static importDOM() {
|
|
208
|
+
return {
|
|
209
|
+
h1: node => ({
|
|
210
|
+
conversion: $convertHeadingElement,
|
|
211
|
+
priority: 0
|
|
212
|
+
}),
|
|
213
|
+
h2: node => ({
|
|
214
|
+
conversion: $convertHeadingElement,
|
|
215
|
+
priority: 0
|
|
216
|
+
}),
|
|
217
|
+
h3: node => ({
|
|
218
|
+
conversion: $convertHeadingElement,
|
|
219
|
+
priority: 0
|
|
220
|
+
}),
|
|
221
|
+
h4: node => ({
|
|
222
|
+
conversion: $convertHeadingElement,
|
|
223
|
+
priority: 0
|
|
224
|
+
}),
|
|
225
|
+
h5: node => ({
|
|
226
|
+
conversion: $convertHeadingElement,
|
|
227
|
+
priority: 0
|
|
228
|
+
}),
|
|
229
|
+
h6: node => ({
|
|
230
|
+
conversion: $convertHeadingElement,
|
|
231
|
+
priority: 0
|
|
232
|
+
}),
|
|
233
|
+
p: node => {
|
|
234
|
+
// domNode is a <p> since we matched it by nodeName
|
|
235
|
+
const paragraph = node;
|
|
236
|
+
const firstChild = paragraph.firstChild;
|
|
237
|
+
if (firstChild !== null && isGoogleDocsTitle(firstChild)) {
|
|
238
|
+
return {
|
|
239
|
+
conversion: () => ({
|
|
240
|
+
node: null
|
|
241
|
+
}),
|
|
242
|
+
priority: 3
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
return null;
|
|
246
|
+
},
|
|
247
|
+
span: node => {
|
|
248
|
+
if (isGoogleDocsTitle(node)) {
|
|
249
|
+
return {
|
|
250
|
+
conversion: domNode => {
|
|
251
|
+
return {
|
|
252
|
+
node: $createHeadingNode('h1')
|
|
253
|
+
};
|
|
254
|
+
},
|
|
255
|
+
priority: 3
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
exportDOM(editor) {
|
|
263
|
+
const {
|
|
264
|
+
element
|
|
265
|
+
} = super.exportDOM(editor);
|
|
266
|
+
if (lexicalUtils.isHTMLElement(element)) {
|
|
267
|
+
if (this.isEmpty()) {
|
|
268
|
+
element.append(document.createElement('br'));
|
|
269
|
+
}
|
|
270
|
+
const formatType = this.getFormatType();
|
|
271
|
+
if (formatType) {
|
|
272
|
+
element.style.textAlign = formatType;
|
|
273
|
+
}
|
|
274
|
+
const direction = this.getDirection();
|
|
275
|
+
if (direction) {
|
|
276
|
+
element.dir = direction;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return {
|
|
280
|
+
element
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
static importJSON(serializedNode) {
|
|
284
|
+
return $createHeadingNode(serializedNode.tag).updateFromJSON(serializedNode);
|
|
285
|
+
}
|
|
286
|
+
updateFromJSON(serializedNode) {
|
|
287
|
+
return super.updateFromJSON(serializedNode).setTag(serializedNode.tag);
|
|
288
|
+
}
|
|
289
|
+
exportJSON() {
|
|
290
|
+
return {
|
|
291
|
+
...super.exportJSON(),
|
|
292
|
+
tag: this.getTag()
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Mutation
|
|
297
|
+
insertNewAfter(selection, restoreSelection = true) {
|
|
298
|
+
const anchorOffet = selection ? selection.anchor.offset : 0;
|
|
299
|
+
const lastDesc = this.getLastDescendant();
|
|
300
|
+
const isAtEnd = !lastDesc || selection && selection.anchor.key === lastDesc.getKey() && anchorOffet === lastDesc.getTextContentSize();
|
|
301
|
+
const newElement = isAtEnd || !selection ? lexical.$createParagraphNode() : $createHeadingNode(this.getTag());
|
|
302
|
+
const direction = this.getDirection();
|
|
303
|
+
newElement.setDirection(direction);
|
|
304
|
+
this.insertAfter(newElement, restoreSelection);
|
|
305
|
+
if (anchorOffet === 0 && !this.isEmpty() && selection) {
|
|
306
|
+
const paragraph = lexical.$createParagraphNode();
|
|
307
|
+
paragraph.select();
|
|
308
|
+
this.replace(paragraph, true);
|
|
309
|
+
}
|
|
310
|
+
return newElement;
|
|
311
|
+
}
|
|
312
|
+
collapseAtStart() {
|
|
313
|
+
const newElement = !this.isEmpty() ? $createHeadingNode(this.getTag()) : lexical.$createParagraphNode();
|
|
314
|
+
const children = this.getChildren();
|
|
315
|
+
children.forEach(child => newElement.append(child));
|
|
316
|
+
this.replace(newElement);
|
|
317
|
+
return true;
|
|
318
|
+
}
|
|
319
|
+
extractWithChild() {
|
|
320
|
+
return true;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
function isGoogleDocsTitle(domNode) {
|
|
324
|
+
if (domNode.nodeName.toLowerCase() === 'span') {
|
|
325
|
+
return domNode.style.fontSize === '26pt';
|
|
326
|
+
}
|
|
327
|
+
return false;
|
|
328
|
+
}
|
|
329
|
+
function $convertHeadingElement(element) {
|
|
330
|
+
const nodeName = element.nodeName.toLowerCase();
|
|
331
|
+
let node = null;
|
|
332
|
+
if (nodeName === 'h1' || nodeName === 'h2' || nodeName === 'h3' || nodeName === 'h4' || nodeName === 'h5' || nodeName === 'h6') {
|
|
333
|
+
node = $createHeadingNode(nodeName);
|
|
334
|
+
if (element.style !== null) {
|
|
335
|
+
lexical.setNodeIndentFromDOM(element, node);
|
|
336
|
+
node.setFormat(element.style.textAlign);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
node
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
function $convertBlockquoteElement(element) {
|
|
344
|
+
const node = $createQuoteNode();
|
|
345
|
+
if (element.style !== null) {
|
|
346
|
+
node.setFormat(element.style.textAlign);
|
|
347
|
+
lexical.setNodeIndentFromDOM(element, node);
|
|
348
|
+
}
|
|
349
|
+
return {
|
|
350
|
+
node
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
function $createHeadingNode(headingTag = 'h1') {
|
|
354
|
+
return lexical.$applyNodeReplacement(new HeadingNode(headingTag));
|
|
355
|
+
}
|
|
356
|
+
function $isHeadingNode(node) {
|
|
357
|
+
return node instanceof HeadingNode;
|
|
358
|
+
}
|
|
359
|
+
function onPasteForRichText(event, editor) {
|
|
360
|
+
event.preventDefault();
|
|
361
|
+
editor.update(() => {
|
|
362
|
+
const selection = lexical.$getSelection();
|
|
363
|
+
const clipboardData = lexicalUtils.objectKlassEquals(event, InputEvent) || lexicalUtils.objectKlassEquals(event, KeyboardEvent) ? null : event.clipboardData;
|
|
364
|
+
if (clipboardData != null && selection !== null) {
|
|
365
|
+
lexicalClipboard.$insertDataTransferForRichText(clipboardData, selection, editor);
|
|
366
|
+
}
|
|
367
|
+
}, {
|
|
368
|
+
tag: lexical.PASTE_TAG
|
|
369
|
+
});
|
|
370
|
+
}
|
|
371
|
+
async function onCutForRichText(event, editor) {
|
|
372
|
+
await lexicalClipboard.copyToClipboard(editor, lexicalUtils.objectKlassEquals(event, ClipboardEvent) ? event : null);
|
|
373
|
+
editor.update(() => {
|
|
374
|
+
const selection = lexical.$getSelection();
|
|
375
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
376
|
+
selection.removeText();
|
|
377
|
+
} else if (lexical.$isNodeSelection(selection)) {
|
|
378
|
+
selection.getNodes().forEach(node => node.remove());
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Clipboard may contain files that we aren't allowed to read. While the event is arguably useless,
|
|
384
|
+
// in certain occasions, we want to know whether it was a file transfer, as opposed to text. We
|
|
385
|
+
// control this with the first boolean flag.
|
|
386
|
+
function eventFiles(event) {
|
|
387
|
+
let dataTransfer = null;
|
|
388
|
+
if (lexicalUtils.objectKlassEquals(event, DragEvent)) {
|
|
389
|
+
dataTransfer = event.dataTransfer;
|
|
390
|
+
} else if (lexicalUtils.objectKlassEquals(event, ClipboardEvent)) {
|
|
391
|
+
dataTransfer = event.clipboardData;
|
|
392
|
+
}
|
|
393
|
+
if (dataTransfer === null) {
|
|
394
|
+
return [false, [], false];
|
|
395
|
+
}
|
|
396
|
+
const types = dataTransfer.types;
|
|
397
|
+
const hasFiles = types.includes('Files');
|
|
398
|
+
const hasContent = types.includes('text/html') || types.includes('text/plain');
|
|
399
|
+
return [hasFiles, Array.from(dataTransfer.files), hasContent];
|
|
400
|
+
}
|
|
401
|
+
function $handleIndentAndOutdent(indentOrOutdent) {
|
|
402
|
+
const selection = lexical.$getSelection();
|
|
403
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
404
|
+
return false;
|
|
405
|
+
}
|
|
406
|
+
const alreadyHandled = new Set();
|
|
407
|
+
const nodes = selection.getNodes();
|
|
408
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
409
|
+
const node = nodes[i];
|
|
410
|
+
const key = node.getKey();
|
|
411
|
+
if (alreadyHandled.has(key)) {
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
const parentBlock = lexicalUtils.$findMatchingParent(node, parentNode => lexical.$isElementNode(parentNode) && !parentNode.isInline());
|
|
415
|
+
if (parentBlock === null) {
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
const parentKey = parentBlock.getKey();
|
|
419
|
+
if (parentBlock.canIndent() && !alreadyHandled.has(parentKey)) {
|
|
420
|
+
alreadyHandled.add(parentKey);
|
|
421
|
+
indentOrOutdent(parentBlock);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return alreadyHandled.size > 0;
|
|
425
|
+
}
|
|
426
|
+
function $isTargetWithinDecorator(target) {
|
|
427
|
+
const node = lexical.$getNearestNodeFromDOMNode(target);
|
|
428
|
+
return lexical.$isDecoratorNode(node);
|
|
429
|
+
}
|
|
430
|
+
function $isSelectionAtEndOfRoot(selection) {
|
|
431
|
+
const focus = selection.focus;
|
|
432
|
+
return focus.key === 'root' && focus.offset === lexical.$getRoot().getChildrenSize();
|
|
433
|
+
}
|
|
434
|
+
function $isSelectionCollapsedAtFrontOfIndentedBlock(selection) {
|
|
435
|
+
if (!selection.isCollapsed()) {
|
|
436
|
+
return false;
|
|
437
|
+
}
|
|
438
|
+
const {
|
|
439
|
+
anchor
|
|
440
|
+
} = selection;
|
|
441
|
+
if (anchor.offset !== 0) {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
const anchorNode = anchor.getNode();
|
|
445
|
+
if (lexical.$isRootNode(anchorNode)) {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
const element = lexicalUtils.$getNearestBlockElementAncestorOrThrow(anchorNode);
|
|
449
|
+
return element.getIndent() > 0 && (element.is(anchorNode) || anchorNode.is(element.getFirstDescendant()));
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Resets the capitalization of the selection to default.
|
|
454
|
+
* Called when the user presses space, tab, or enter key.
|
|
455
|
+
* @param selection The selection to reset the capitalization of.
|
|
456
|
+
*/
|
|
457
|
+
function $resetCapitalization(selection) {
|
|
458
|
+
for (const format of ['lowercase', 'uppercase', 'capitalize']) {
|
|
459
|
+
if (selection.hasFormat(format)) {
|
|
460
|
+
selection.toggleFormat(format);
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
function registerRichText(editor) {
|
|
465
|
+
const removeListener = lexicalUtils.mergeRegister(editor.registerCommand(lexical.CLICK_COMMAND, payload => {
|
|
466
|
+
const selection = lexical.$getSelection();
|
|
467
|
+
if (lexical.$isNodeSelection(selection)) {
|
|
468
|
+
selection.clear();
|
|
469
|
+
return true;
|
|
470
|
+
}
|
|
471
|
+
return false;
|
|
472
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.DELETE_CHARACTER_COMMAND, isBackward => {
|
|
473
|
+
const selection = lexical.$getSelection();
|
|
474
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
475
|
+
selection.deleteCharacter(isBackward);
|
|
476
|
+
return true;
|
|
477
|
+
} else if (lexical.$isNodeSelection(selection)) {
|
|
478
|
+
selection.deleteNodes();
|
|
479
|
+
return true;
|
|
480
|
+
}
|
|
481
|
+
return false;
|
|
482
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.DELETE_WORD_COMMAND, isBackward => {
|
|
483
|
+
const selection = lexical.$getSelection();
|
|
484
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
485
|
+
return false;
|
|
486
|
+
}
|
|
487
|
+
selection.deleteWord(isBackward);
|
|
488
|
+
return true;
|
|
489
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.DELETE_LINE_COMMAND, isBackward => {
|
|
490
|
+
const selection = lexical.$getSelection();
|
|
491
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
492
|
+
return false;
|
|
493
|
+
}
|
|
494
|
+
selection.deleteLine(isBackward);
|
|
495
|
+
return true;
|
|
496
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.CONTROLLED_TEXT_INSERTION_COMMAND, eventOrText => {
|
|
497
|
+
const selection = lexical.$getSelection();
|
|
498
|
+
if (typeof eventOrText === 'string') {
|
|
499
|
+
if (selection !== null) {
|
|
500
|
+
selection.insertText(eventOrText);
|
|
501
|
+
}
|
|
502
|
+
} else {
|
|
503
|
+
if (selection === null) {
|
|
504
|
+
return false;
|
|
505
|
+
}
|
|
506
|
+
const dataTransfer = eventOrText.dataTransfer;
|
|
507
|
+
if (dataTransfer != null) {
|
|
508
|
+
lexicalClipboard.$insertDataTransferForRichText(dataTransfer, selection, editor);
|
|
509
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
|
510
|
+
const data = eventOrText.data;
|
|
511
|
+
if (data) {
|
|
512
|
+
selection.insertText(data);
|
|
513
|
+
}
|
|
514
|
+
return true;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
return true;
|
|
518
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.REMOVE_TEXT_COMMAND, () => {
|
|
519
|
+
const selection = lexical.$getSelection();
|
|
520
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
521
|
+
return false;
|
|
522
|
+
}
|
|
523
|
+
selection.removeText();
|
|
524
|
+
return true;
|
|
525
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.FORMAT_TEXT_COMMAND, format => {
|
|
526
|
+
const selection = lexical.$getSelection();
|
|
527
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
528
|
+
return false;
|
|
529
|
+
}
|
|
530
|
+
selection.formatText(format);
|
|
531
|
+
return true;
|
|
532
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.FORMAT_ELEMENT_COMMAND, format => {
|
|
533
|
+
const selection = lexical.$getSelection();
|
|
534
|
+
if (!lexical.$isRangeSelection(selection) && !lexical.$isNodeSelection(selection)) {
|
|
535
|
+
return false;
|
|
536
|
+
}
|
|
537
|
+
const nodes = selection.getNodes();
|
|
538
|
+
for (const node of nodes) {
|
|
539
|
+
const element = lexicalUtils.$findMatchingParent(node, parentNode => lexical.$isElementNode(parentNode) && !parentNode.isInline());
|
|
540
|
+
if (element !== null) {
|
|
541
|
+
element.setFormat(format);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
return true;
|
|
545
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.INSERT_LINE_BREAK_COMMAND, selectStart => {
|
|
546
|
+
const selection = lexical.$getSelection();
|
|
547
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
548
|
+
return false;
|
|
549
|
+
}
|
|
550
|
+
selection.insertLineBreak(selectStart);
|
|
551
|
+
return true;
|
|
552
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.INSERT_PARAGRAPH_COMMAND, () => {
|
|
553
|
+
const selection = lexical.$getSelection();
|
|
554
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
557
|
+
selection.insertParagraph();
|
|
558
|
+
return true;
|
|
559
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.INSERT_TAB_COMMAND, () => {
|
|
560
|
+
lexical.$insertNodes([lexical.$createTabNode()]);
|
|
561
|
+
return true;
|
|
562
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.INDENT_CONTENT_COMMAND, () => {
|
|
563
|
+
return $handleIndentAndOutdent(block => {
|
|
564
|
+
const indent = block.getIndent();
|
|
565
|
+
block.setIndent(indent + 1);
|
|
566
|
+
});
|
|
567
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.OUTDENT_CONTENT_COMMAND, () => {
|
|
568
|
+
return $handleIndentAndOutdent(block => {
|
|
569
|
+
const indent = block.getIndent();
|
|
570
|
+
if (indent > 0) {
|
|
571
|
+
block.setIndent(Math.max(0, indent - 1));
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.KEY_ARROW_UP_COMMAND, event => {
|
|
575
|
+
const selection = lexical.$getSelection();
|
|
576
|
+
if (lexical.$isNodeSelection(selection)) {
|
|
577
|
+
// If selection is on a node, let's try and move selection
|
|
578
|
+
// back to being a range selection.
|
|
579
|
+
const nodes = selection.getNodes();
|
|
580
|
+
if (nodes.length > 0) {
|
|
581
|
+
event.preventDefault();
|
|
582
|
+
nodes[0].selectPrevious();
|
|
583
|
+
return true;
|
|
584
|
+
}
|
|
585
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
|
586
|
+
const possibleNode = lexical.$getAdjacentNode(selection.focus, true);
|
|
587
|
+
if (!event.shiftKey && lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated() && !possibleNode.isInline()) {
|
|
588
|
+
possibleNode.selectPrevious();
|
|
589
|
+
event.preventDefault();
|
|
590
|
+
return true;
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return false;
|
|
594
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.KEY_ARROW_DOWN_COMMAND, event => {
|
|
595
|
+
const selection = lexical.$getSelection();
|
|
596
|
+
if (lexical.$isNodeSelection(selection)) {
|
|
597
|
+
// If selection is on a node, let's try and move selection
|
|
598
|
+
// back to being a range selection.
|
|
599
|
+
const nodes = selection.getNodes();
|
|
600
|
+
if (nodes.length > 0) {
|
|
601
|
+
event.preventDefault();
|
|
602
|
+
nodes[0].selectNext(0, 0);
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
} else if (lexical.$isRangeSelection(selection)) {
|
|
606
|
+
if ($isSelectionAtEndOfRoot(selection)) {
|
|
607
|
+
event.preventDefault();
|
|
608
|
+
return true;
|
|
609
|
+
}
|
|
610
|
+
const possibleNode = lexical.$getAdjacentNode(selection.focus, false);
|
|
611
|
+
if (!event.shiftKey && lexical.$isDecoratorNode(possibleNode) && !possibleNode.isIsolated() && !possibleNode.isInline()) {
|
|
612
|
+
possibleNode.selectNext();
|
|
613
|
+
event.preventDefault();
|
|
614
|
+
return true;
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
return false;
|
|
618
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.KEY_ARROW_LEFT_COMMAND, event => {
|
|
619
|
+
const selection = lexical.$getSelection();
|
|
620
|
+
if (lexical.$isNodeSelection(selection)) {
|
|
621
|
+
// If selection is on a node, let's try and move selection
|
|
622
|
+
// back to being a range selection.
|
|
623
|
+
const nodes = selection.getNodes();
|
|
624
|
+
if (nodes.length > 0) {
|
|
625
|
+
event.preventDefault();
|
|
626
|
+
if (lexicalSelection.$isParentRTL(nodes[0])) {
|
|
627
|
+
nodes[0].selectNext(0, 0);
|
|
628
|
+
} else {
|
|
629
|
+
nodes[0].selectPrevious();
|
|
630
|
+
}
|
|
631
|
+
return true;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
635
|
+
return false;
|
|
636
|
+
}
|
|
637
|
+
if (lexicalSelection.$shouldOverrideDefaultCharacterSelection(selection, true)) {
|
|
638
|
+
const isHoldingShift = event.shiftKey;
|
|
639
|
+
event.preventDefault();
|
|
640
|
+
lexicalSelection.$moveCharacter(selection, isHoldingShift, true);
|
|
641
|
+
return true;
|
|
642
|
+
}
|
|
643
|
+
return false;
|
|
644
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.KEY_ARROW_RIGHT_COMMAND, event => {
|
|
645
|
+
const selection = lexical.$getSelection();
|
|
646
|
+
if (lexical.$isNodeSelection(selection)) {
|
|
647
|
+
// If selection is on a node, let's try and move selection
|
|
648
|
+
// back to being a range selection.
|
|
649
|
+
const nodes = selection.getNodes();
|
|
650
|
+
if (nodes.length > 0) {
|
|
651
|
+
event.preventDefault();
|
|
652
|
+
if (lexicalSelection.$isParentRTL(nodes[0])) {
|
|
653
|
+
nodes[0].selectPrevious();
|
|
654
|
+
} else {
|
|
655
|
+
nodes[0].selectNext(0, 0);
|
|
656
|
+
}
|
|
657
|
+
return true;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
661
|
+
return false;
|
|
662
|
+
}
|
|
663
|
+
const isHoldingShift = event.shiftKey;
|
|
664
|
+
if (lexicalSelection.$shouldOverrideDefaultCharacterSelection(selection, false)) {
|
|
665
|
+
event.preventDefault();
|
|
666
|
+
lexicalSelection.$moveCharacter(selection, isHoldingShift, false);
|
|
667
|
+
return true;
|
|
668
|
+
}
|
|
669
|
+
return false;
|
|
670
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.KEY_BACKSPACE_COMMAND, event => {
|
|
671
|
+
if ($isTargetWithinDecorator(event.target)) {
|
|
672
|
+
return false;
|
|
673
|
+
}
|
|
674
|
+
const selection = lexical.$getSelection();
|
|
675
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
676
|
+
if ($isSelectionCollapsedAtFrontOfIndentedBlock(selection)) {
|
|
677
|
+
event.preventDefault();
|
|
678
|
+
return editor.dispatchCommand(lexical.OUTDENT_CONTENT_COMMAND, undefined);
|
|
679
|
+
}
|
|
680
|
+
// Exception handling for iOS native behavior instead of Lexical's behavior when using Korean on iOS devices.
|
|
681
|
+
// more details - https://github.com/facebook/lexical/issues/5841
|
|
682
|
+
if (IS_IOS && navigator.language === 'ko-KR') {
|
|
683
|
+
return false;
|
|
684
|
+
}
|
|
685
|
+
} else if (!lexical.$isNodeSelection(selection)) {
|
|
686
|
+
return false;
|
|
687
|
+
}
|
|
688
|
+
event.preventDefault();
|
|
689
|
+
return editor.dispatchCommand(lexical.DELETE_CHARACTER_COMMAND, true);
|
|
690
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.KEY_DELETE_COMMAND, event => {
|
|
691
|
+
if ($isTargetWithinDecorator(event.target)) {
|
|
692
|
+
return false;
|
|
693
|
+
}
|
|
694
|
+
const selection = lexical.$getSelection();
|
|
695
|
+
if (!(lexical.$isRangeSelection(selection) || lexical.$isNodeSelection(selection))) {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
698
|
+
event.preventDefault();
|
|
699
|
+
return editor.dispatchCommand(lexical.DELETE_CHARACTER_COMMAND, false);
|
|
700
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.KEY_ENTER_COMMAND, event => {
|
|
701
|
+
const selection = lexical.$getSelection();
|
|
702
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
703
|
+
return false;
|
|
704
|
+
}
|
|
705
|
+
$resetCapitalization(selection);
|
|
706
|
+
if (event !== null) {
|
|
707
|
+
// If we have beforeinput, then we can avoid blocking
|
|
708
|
+
// the default behavior. This ensures that the iOS can
|
|
709
|
+
// intercept that we're actually inserting a paragraph,
|
|
710
|
+
// and autocomplete, autocapitalize etc work as intended.
|
|
711
|
+
// This can also cause a strange performance issue in
|
|
712
|
+
// Safari, where there is a noticeable pause due to
|
|
713
|
+
// preventing the key down of enter.
|
|
714
|
+
if ((IS_IOS || IS_SAFARI || IS_APPLE_WEBKIT) && CAN_USE_BEFORE_INPUT) {
|
|
715
|
+
return false;
|
|
716
|
+
}
|
|
717
|
+
event.preventDefault();
|
|
718
|
+
if (event.shiftKey) {
|
|
719
|
+
return editor.dispatchCommand(lexical.INSERT_LINE_BREAK_COMMAND, false);
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
return editor.dispatchCommand(lexical.INSERT_PARAGRAPH_COMMAND, undefined);
|
|
723
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.KEY_ESCAPE_COMMAND, () => {
|
|
724
|
+
const selection = lexical.$getSelection();
|
|
725
|
+
if (!lexical.$isRangeSelection(selection)) {
|
|
726
|
+
return false;
|
|
727
|
+
}
|
|
728
|
+
editor.blur();
|
|
729
|
+
return true;
|
|
730
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.DROP_COMMAND, event => {
|
|
731
|
+
const [, files] = eventFiles(event);
|
|
732
|
+
if (files.length > 0) {
|
|
733
|
+
const x = event.clientX;
|
|
734
|
+
const y = event.clientY;
|
|
735
|
+
const eventRange = caretFromPoint(x, y);
|
|
736
|
+
if (eventRange !== null) {
|
|
737
|
+
const {
|
|
738
|
+
offset: domOffset,
|
|
739
|
+
node: domNode
|
|
740
|
+
} = eventRange;
|
|
741
|
+
const node = lexical.$getNearestNodeFromDOMNode(domNode);
|
|
742
|
+
if (node !== null) {
|
|
743
|
+
const selection = lexical.$createRangeSelection();
|
|
744
|
+
if (lexical.$isTextNode(node)) {
|
|
745
|
+
selection.anchor.set(node.getKey(), domOffset, 'text');
|
|
746
|
+
selection.focus.set(node.getKey(), domOffset, 'text');
|
|
747
|
+
} else {
|
|
748
|
+
const parentKey = node.getParentOrThrow().getKey();
|
|
749
|
+
const offset = node.getIndexWithinParent() + 1;
|
|
750
|
+
selection.anchor.set(parentKey, offset, 'element');
|
|
751
|
+
selection.focus.set(parentKey, offset, 'element');
|
|
752
|
+
}
|
|
753
|
+
const normalizedSelection = lexical.$normalizeSelection__EXPERIMENTAL(selection);
|
|
754
|
+
lexical.$setSelection(normalizedSelection);
|
|
755
|
+
}
|
|
756
|
+
editor.dispatchCommand(DRAG_DROP_PASTE, files);
|
|
757
|
+
}
|
|
758
|
+
event.preventDefault();
|
|
759
|
+
return true;
|
|
760
|
+
}
|
|
761
|
+
const selection = lexical.$getSelection();
|
|
762
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
763
|
+
return true;
|
|
764
|
+
}
|
|
765
|
+
return false;
|
|
766
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.DRAGSTART_COMMAND, event => {
|
|
767
|
+
const [isFileTransfer] = eventFiles(event);
|
|
768
|
+
const selection = lexical.$getSelection();
|
|
769
|
+
if (isFileTransfer && !lexical.$isRangeSelection(selection)) {
|
|
770
|
+
return false;
|
|
771
|
+
}
|
|
772
|
+
return true;
|
|
773
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.DRAGOVER_COMMAND, event => {
|
|
774
|
+
const [isFileTransfer] = eventFiles(event);
|
|
775
|
+
const selection = lexical.$getSelection();
|
|
776
|
+
if (isFileTransfer && !lexical.$isRangeSelection(selection)) {
|
|
777
|
+
return false;
|
|
778
|
+
}
|
|
779
|
+
const x = event.clientX;
|
|
780
|
+
const y = event.clientY;
|
|
781
|
+
const eventRange = caretFromPoint(x, y);
|
|
782
|
+
if (eventRange !== null) {
|
|
783
|
+
const node = lexical.$getNearestNodeFromDOMNode(eventRange.node);
|
|
784
|
+
if (lexical.$isDecoratorNode(node)) {
|
|
785
|
+
// Show browser caret as the user is dragging the media across the screen. Won't work
|
|
786
|
+
// for DecoratorNode nor it's relevant.
|
|
787
|
+
event.preventDefault();
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return true;
|
|
791
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.SELECT_ALL_COMMAND, () => {
|
|
792
|
+
lexical.$selectAll();
|
|
793
|
+
return true;
|
|
794
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.COPY_COMMAND, event => {
|
|
795
|
+
lexicalClipboard.copyToClipboard(editor, lexicalUtils.objectKlassEquals(event, ClipboardEvent) ? event : null);
|
|
796
|
+
return true;
|
|
797
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.CUT_COMMAND, event => {
|
|
798
|
+
onCutForRichText(event, editor);
|
|
799
|
+
return true;
|
|
800
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.PASTE_COMMAND, event => {
|
|
801
|
+
const [, files, hasTextContent] = eventFiles(event);
|
|
802
|
+
if (files.length > 0 && !hasTextContent) {
|
|
803
|
+
editor.dispatchCommand(DRAG_DROP_PASTE, files);
|
|
804
|
+
return true;
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
// if inputs then paste within the input ignore creating a new node on paste event
|
|
808
|
+
if (lexical.isDOMNode(event.target) && lexical.isSelectionCapturedInDecoratorInput(event.target)) {
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
const selection = lexical.$getSelection();
|
|
812
|
+
if (selection !== null) {
|
|
813
|
+
onPasteForRichText(event, editor);
|
|
814
|
+
return true;
|
|
815
|
+
}
|
|
816
|
+
return false;
|
|
817
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.KEY_SPACE_COMMAND, _ => {
|
|
818
|
+
const selection = lexical.$getSelection();
|
|
819
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
820
|
+
$resetCapitalization(selection);
|
|
821
|
+
}
|
|
822
|
+
return false;
|
|
823
|
+
}, lexical.COMMAND_PRIORITY_EDITOR), editor.registerCommand(lexical.KEY_TAB_COMMAND, _ => {
|
|
824
|
+
const selection = lexical.$getSelection();
|
|
825
|
+
if (lexical.$isRangeSelection(selection)) {
|
|
826
|
+
$resetCapitalization(selection);
|
|
827
|
+
}
|
|
828
|
+
return false;
|
|
829
|
+
}, lexical.COMMAND_PRIORITY_EDITOR));
|
|
830
|
+
return removeListener;
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* An extension to register \@ekz/lexical-rich-text behavior and nodes
|
|
835
|
+
* ({@link HeadingNode}, {@link QuoteNode})
|
|
836
|
+
*/
|
|
837
|
+
const RichTextExtension = lexical.defineExtension({
|
|
838
|
+
conflictsWith: ['@ekz/lexical-plain-text'],
|
|
839
|
+
dependencies: [lexicalDragon.DragonExtension],
|
|
840
|
+
name: '@ekz/lexical-rich-text',
|
|
841
|
+
nodes: () => [HeadingNode, QuoteNode],
|
|
842
|
+
register: registerRichText
|
|
843
|
+
});
|
|
844
|
+
|
|
845
|
+
exports.$createHeadingNode = $createHeadingNode;
|
|
846
|
+
exports.$createQuoteNode = $createQuoteNode;
|
|
847
|
+
exports.$isHeadingNode = $isHeadingNode;
|
|
848
|
+
exports.$isQuoteNode = $isQuoteNode;
|
|
849
|
+
exports.DRAG_DROP_PASTE = DRAG_DROP_PASTE;
|
|
850
|
+
exports.HeadingNode = HeadingNode;
|
|
851
|
+
exports.QuoteNode = QuoteNode;
|
|
852
|
+
exports.RichTextExtension = RichTextExtension;
|
|
853
|
+
exports.eventFiles = eventFiles;
|
|
854
|
+
exports.registerRichText = registerRichText;
|