@lexical/devtools-core 0.14.5 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LexicalDevtoolsCore.dev.js +135 -108
- package/LexicalDevtoolsCore.dev.mjs +116 -90
- package/LexicalDevtoolsCore.js +2 -0
- package/LexicalDevtoolsCore.js.flow +34 -0
- package/LexicalDevtoolsCore.mjs +2 -0
- package/LexicalDevtoolsCore.node.mjs +2 -0
- package/LexicalDevtoolsCore.prod.js +21 -19
- package/LexicalDevtoolsCore.prod.mjs +3 -1
- package/generateContent.d.ts +4 -5
- package/package.json +7 -7
- package/useLexicalCommandsLog.d.ts +3 -1
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
6
7
|
*/
|
|
8
|
+
|
|
7
9
|
'use strict';
|
|
8
10
|
|
|
9
11
|
var html = require('@lexical/html');
|
|
@@ -11,7 +13,8 @@ var link = require('@lexical/link');
|
|
|
11
13
|
var mark = require('@lexical/mark');
|
|
12
14
|
var table = require('@lexical/table');
|
|
13
15
|
var lexical = require('lexical');
|
|
14
|
-
var
|
|
16
|
+
var react = require('react');
|
|
17
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
15
18
|
|
|
16
19
|
/**
|
|
17
20
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -20,6 +23,7 @@ var React = require('react');
|
|
|
20
23
|
* LICENSE file in the root directory of this source tree.
|
|
21
24
|
*
|
|
22
25
|
*/
|
|
26
|
+
|
|
23
27
|
const NON_SINGLE_WIDTH_CHARS_REPLACEMENT = Object.freeze({
|
|
24
28
|
'\t': '\\t',
|
|
25
29
|
'\n': '\\n'
|
|
@@ -37,7 +41,7 @@ const FORMAT_PREDICATES = [node => node.hasFormat('bold') && 'Bold', node => nod
|
|
|
37
41
|
const FORMAT_PREDICATES_PARAGRAPH = [node => node.hasTextFormat('bold') && 'Bold', node => node.hasTextFormat('code') && 'Code', node => node.hasTextFormat('italic') && 'Italic', node => node.hasTextFormat('strikethrough') && 'Strikethrough', node => node.hasTextFormat('subscript') && 'Subscript', node => node.hasTextFormat('superscript') && 'Superscript', node => node.hasTextFormat('underline') && 'Underline'];
|
|
38
42
|
const DETAIL_PREDICATES = [node => node.isDirectionless() && 'Directionless', node => node.isUnmergeable() && 'Unmergeable'];
|
|
39
43
|
const MODE_PREDICATES = [node => node.isToken() && 'Token', node => node.isSegmented() && 'Segmented'];
|
|
40
|
-
function generateContent(editor, commandsLog, exportDOM) {
|
|
44
|
+
function generateContent(editor, commandsLog, exportDOM, customPrintNode, obfuscateText = false) {
|
|
41
45
|
const editorState = editor.getEditorState();
|
|
42
46
|
const editorConfig = editor._config;
|
|
43
47
|
const compositionKey = editor._compositionKey;
|
|
@@ -57,9 +61,8 @@ function generateContent(editor, commandsLog, exportDOM) {
|
|
|
57
61
|
const nodeKeyDisplay = `(${nodeKey})`;
|
|
58
62
|
const typeDisplay = node.getType() || '';
|
|
59
63
|
const isSelected = node.isSelected();
|
|
60
|
-
|
|
61
|
-
res +=
|
|
62
|
-
res += printSelectedCharsLine({
|
|
64
|
+
res += `${isSelected ? SYMBOLS.selectedLine : ' '} ${indent.join(' ')} ${nodeKeyDisplay} ${typeDisplay} ${printNode(node, customPrintNode, obfuscateText)}\n`;
|
|
65
|
+
res += $printSelectedCharsLine({
|
|
63
66
|
indent,
|
|
64
67
|
isSelected,
|
|
65
68
|
node,
|
|
@@ -74,10 +77,11 @@ function generateContent(editor, commandsLog, exportDOM) {
|
|
|
74
77
|
res += '\n\n commands:';
|
|
75
78
|
if (commandsLog.length) {
|
|
76
79
|
for (const {
|
|
80
|
+
index,
|
|
77
81
|
type,
|
|
78
82
|
payload
|
|
79
83
|
} of commandsLog) {
|
|
80
|
-
res += `\n └ { type: ${type}, payload: ${payload instanceof Event ? payload.constructor.name : payload} }`;
|
|
84
|
+
res += `\n └ ${index}. { type: ${type}, payload: ${payload instanceof Event ? payload.constructor.name : payload} }`;
|
|
81
85
|
}
|
|
82
86
|
} else {
|
|
83
87
|
res += '\n └ None dispatched.';
|
|
@@ -121,22 +125,30 @@ function visitTree(currentNode, visitor, indent = []) {
|
|
|
121
125
|
}
|
|
122
126
|
});
|
|
123
127
|
}
|
|
124
|
-
function normalize(text) {
|
|
125
|
-
|
|
128
|
+
function normalize(text, obfuscateText = false) {
|
|
129
|
+
const textToPrint = Object.entries(NON_SINGLE_WIDTH_CHARS_REPLACEMENT).reduce((acc, [key, value]) => acc.replace(new RegExp(key, 'g'), String(value)), text);
|
|
130
|
+
if (obfuscateText) {
|
|
131
|
+
return textToPrint.replace(/[^\s]/g, '*');
|
|
132
|
+
}
|
|
133
|
+
return textToPrint;
|
|
126
134
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
135
|
+
function printNode(node, customPrintNode, obfuscateText = false) {
|
|
136
|
+
const customPrint = customPrintNode ? customPrintNode(node, obfuscateText) : undefined;
|
|
137
|
+
if (customPrint !== undefined && customPrint.length > 0) {
|
|
138
|
+
return customPrint;
|
|
139
|
+
}
|
|
130
140
|
if (lexical.$isTextNode(node)) {
|
|
131
141
|
const text = node.getTextContent();
|
|
132
|
-
const title = text.length === 0 ? '(empty)' : `"${normalize(text)}"`;
|
|
142
|
+
const title = text.length === 0 ? '(empty)' : `"${normalize(text, obfuscateText)}"`;
|
|
133
143
|
const properties = printAllTextNodeProperties(node);
|
|
134
144
|
return [title, properties.length !== 0 ? `{ ${properties} }` : null].filter(Boolean).join(' ').trim();
|
|
135
145
|
} else if (link.$isLinkNode(node)) {
|
|
136
146
|
const link = node.getURL();
|
|
137
|
-
const title = link.length === 0 ? '(empty)' : `"${normalize(link)}"`;
|
|
147
|
+
const title = link.length === 0 ? '(empty)' : `"${normalize(link, obfuscateText)}"`;
|
|
138
148
|
const properties = printAllLinkNodeProperties(node);
|
|
139
149
|
return [title, properties.length !== 0 ? `{ ${properties} }` : null].filter(Boolean).join(' ').trim();
|
|
150
|
+
} else if (mark.$isMarkNode(node)) {
|
|
151
|
+
return `ids: [ ${node.getIDs().join(', ')} ]`;
|
|
140
152
|
} else if (lexical.$isParagraphNode(node)) {
|
|
141
153
|
const formatText = printTextFormatProperties(node);
|
|
142
154
|
return formatText !== '' ? `{ ${formatText} }` : '';
|
|
@@ -202,7 +214,7 @@ function printTitleProperties(node) {
|
|
|
202
214
|
}
|
|
203
215
|
return str;
|
|
204
216
|
}
|
|
205
|
-
function printSelectedCharsLine({
|
|
217
|
+
function $printSelectedCharsLine({
|
|
206
218
|
indent,
|
|
207
219
|
isSelected,
|
|
208
220
|
node,
|
|
@@ -294,8 +306,9 @@ function $getSelectionStartEnd(node, selection) {
|
|
|
294
306
|
* LICENSE file in the root directory of this source tree.
|
|
295
307
|
*
|
|
296
308
|
*/
|
|
309
|
+
|
|
297
310
|
const LARGE_EDITOR_STATE_SIZE = 1000;
|
|
298
|
-
const TreeView = /*#__PURE__*/
|
|
311
|
+
const TreeView = /*#__PURE__*/react.forwardRef(function TreeViewWrapped({
|
|
299
312
|
treeTypeButtonClassName,
|
|
300
313
|
timeTravelButtonClassName,
|
|
301
314
|
timeTravelPanelSliderClassName,
|
|
@@ -307,18 +320,18 @@ const TreeView = /*#__PURE__*/React.forwardRef(function TreeViewWrapped({
|
|
|
307
320
|
setEditorReadOnly,
|
|
308
321
|
generateContent
|
|
309
322
|
}, ref) {
|
|
310
|
-
const [timeStampedEditorStates, setTimeStampedEditorStates] =
|
|
311
|
-
const [content, setContent] =
|
|
312
|
-
const [timeTravelEnabled, setTimeTravelEnabled] =
|
|
313
|
-
const [showExportDOM, setShowExportDOM] =
|
|
314
|
-
const playingIndexRef =
|
|
315
|
-
const inputRef =
|
|
316
|
-
const [isPlaying, setIsPlaying] =
|
|
317
|
-
const [isLimited, setIsLimited] =
|
|
318
|
-
const [showLimited, setShowLimited] =
|
|
319
|
-
const lastEditorStateRef =
|
|
320
|
-
const lastGenerationID =
|
|
321
|
-
const generateTree =
|
|
323
|
+
const [timeStampedEditorStates, setTimeStampedEditorStates] = react.useState([]);
|
|
324
|
+
const [content, setContent] = react.useState('');
|
|
325
|
+
const [timeTravelEnabled, setTimeTravelEnabled] = react.useState(false);
|
|
326
|
+
const [showExportDOM, setShowExportDOM] = react.useState(false);
|
|
327
|
+
const playingIndexRef = react.useRef(0);
|
|
328
|
+
const inputRef = react.useRef(null);
|
|
329
|
+
const [isPlaying, setIsPlaying] = react.useState(false);
|
|
330
|
+
const [isLimited, setIsLimited] = react.useState(false);
|
|
331
|
+
const [showLimited, setShowLimited] = react.useState(false);
|
|
332
|
+
const lastEditorStateRef = react.useRef();
|
|
333
|
+
const lastGenerationID = react.useRef(0);
|
|
334
|
+
const generateTree = react.useCallback(exportDOM => {
|
|
322
335
|
const myID = ++lastGenerationID.current;
|
|
323
336
|
generateContent(exportDOM).then(treeText => {
|
|
324
337
|
if (myID === lastGenerationID.current) {
|
|
@@ -330,7 +343,7 @@ const TreeView = /*#__PURE__*/React.forwardRef(function TreeViewWrapped({
|
|
|
330
343
|
}
|
|
331
344
|
});
|
|
332
345
|
}, [generateContent]);
|
|
333
|
-
|
|
346
|
+
react.useEffect(() => {
|
|
334
347
|
if (!showLimited && editorState._nodeMap.size > LARGE_EDITOR_STATE_SIZE) {
|
|
335
348
|
setIsLimited(true);
|
|
336
349
|
if (!showLimited) {
|
|
@@ -348,7 +361,7 @@ const TreeView = /*#__PURE__*/React.forwardRef(function TreeViewWrapped({
|
|
|
348
361
|
}
|
|
349
362
|
}, [editorState, generateTree, showExportDOM, showLimited, timeTravelEnabled]);
|
|
350
363
|
const totalEditorStates = timeStampedEditorStates.length;
|
|
351
|
-
|
|
364
|
+
react.useEffect(() => {
|
|
352
365
|
if (isPlaying) {
|
|
353
366
|
let timeoutId;
|
|
354
367
|
const play = () => {
|
|
@@ -381,82 +394,92 @@ const TreeView = /*#__PURE__*/React.forwardRef(function TreeViewWrapped({
|
|
|
381
394
|
generateTree(!showExportDOM);
|
|
382
395
|
setShowExportDOM(!showExportDOM);
|
|
383
396
|
};
|
|
384
|
-
return /*#__PURE__*/
|
|
385
|
-
className: viewClassName
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
397
|
+
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
398
|
+
className: viewClassName,
|
|
399
|
+
children: [!showLimited && isLimited ? /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
400
|
+
style: {
|
|
401
|
+
padding: 20
|
|
402
|
+
},
|
|
403
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
404
|
+
style: {
|
|
405
|
+
marginRight: 20
|
|
406
|
+
},
|
|
407
|
+
children: "Detected large EditorState, this can impact debugging performance."
|
|
408
|
+
}), /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
409
|
+
onClick: () => {
|
|
410
|
+
setShowLimited(true);
|
|
411
|
+
},
|
|
412
|
+
style: {
|
|
413
|
+
background: 'transparent',
|
|
414
|
+
border: '1px solid white',
|
|
415
|
+
color: 'white',
|
|
416
|
+
cursor: 'pointer',
|
|
417
|
+
padding: 5
|
|
418
|
+
},
|
|
419
|
+
children: "Show full tree"
|
|
420
|
+
})]
|
|
421
|
+
}) : null, !showLimited ? /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
422
|
+
onClick: () => handleExportModeToggleClick(),
|
|
423
|
+
className: treeTypeButtonClassName,
|
|
424
|
+
type: "button",
|
|
425
|
+
children: showExportDOM ? 'Tree' : 'Export DOM'
|
|
426
|
+
}) : null, !timeTravelEnabled && (showLimited || !isLimited) && totalEditorStates > 2 && /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
427
|
+
onClick: () => {
|
|
428
|
+
setEditorReadOnly(true);
|
|
429
|
+
playingIndexRef.current = totalEditorStates - 1;
|
|
430
|
+
setTimeTravelEnabled(true);
|
|
431
|
+
},
|
|
432
|
+
className: timeTravelButtonClassName,
|
|
433
|
+
type: "button",
|
|
434
|
+
children: "Time Travel"
|
|
435
|
+
}), (showLimited || !isLimited) && /*#__PURE__*/jsxRuntime.jsx("pre", {
|
|
436
|
+
ref: ref,
|
|
437
|
+
children: content
|
|
438
|
+
}), timeTravelEnabled && (showLimited || !isLimited) && /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
439
|
+
className: timeTravelPanelClassName,
|
|
440
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("button", {
|
|
441
|
+
className: timeTravelPanelButtonClassName,
|
|
442
|
+
onClick: () => {
|
|
443
|
+
if (playingIndexRef.current === totalEditorStates - 1) {
|
|
444
|
+
playingIndexRef.current = 1;
|
|
445
|
+
}
|
|
446
|
+
setIsPlaying(!isPlaying);
|
|
447
|
+
},
|
|
448
|
+
type: "button",
|
|
449
|
+
children: isPlaying ? 'Pause' : 'Play'
|
|
450
|
+
}), /*#__PURE__*/jsxRuntime.jsx("input", {
|
|
451
|
+
className: timeTravelPanelSliderClassName,
|
|
452
|
+
ref: inputRef,
|
|
453
|
+
onChange: event => {
|
|
454
|
+
const editorStateIndex = Number(event.target.value);
|
|
455
|
+
const timeStampedEditorState = timeStampedEditorStates[editorStateIndex];
|
|
456
|
+
if (timeStampedEditorState) {
|
|
457
|
+
playingIndexRef.current = editorStateIndex;
|
|
458
|
+
setEditorState(timeStampedEditorState[1]);
|
|
459
|
+
}
|
|
460
|
+
},
|
|
461
|
+
type: "range",
|
|
462
|
+
min: "1",
|
|
463
|
+
max: totalEditorStates - 1
|
|
464
|
+
}), /*#__PURE__*/jsxRuntime.jsx("button", {
|
|
465
|
+
className: timeTravelPanelButtonClassName,
|
|
466
|
+
onClick: () => {
|
|
467
|
+
setEditorReadOnly(false);
|
|
468
|
+
const index = timeStampedEditorStates.length - 1;
|
|
469
|
+
const timeStampedEditorState = timeStampedEditorStates[index];
|
|
470
|
+
setEditorState(timeStampedEditorState[1]);
|
|
471
|
+
const input = inputRef.current;
|
|
472
|
+
if (input !== null) {
|
|
473
|
+
input.value = String(index);
|
|
474
|
+
}
|
|
475
|
+
setTimeTravelEnabled(false);
|
|
476
|
+
setIsPlaying(false);
|
|
477
|
+
},
|
|
478
|
+
type: "button",
|
|
479
|
+
children: "Exit"
|
|
480
|
+
})]
|
|
481
|
+
})]
|
|
482
|
+
});
|
|
460
483
|
});
|
|
461
484
|
|
|
462
485
|
/**
|
|
@@ -466,13 +489,17 @@ const TreeView = /*#__PURE__*/React.forwardRef(function TreeViewWrapped({
|
|
|
466
489
|
* LICENSE file in the root directory of this source tree.
|
|
467
490
|
*
|
|
468
491
|
*/
|
|
492
|
+
|
|
469
493
|
function registerLexicalCommandLogger(editor, setLoggedCommands) {
|
|
470
494
|
const unregisterCommandListeners = new Set();
|
|
495
|
+
let i = 0;
|
|
471
496
|
for (const [command] of editor._commands) {
|
|
472
497
|
unregisterCommandListeners.add(editor.registerCommand(command, payload => {
|
|
473
498
|
setLoggedCommands(state => {
|
|
499
|
+
i += 1;
|
|
474
500
|
const newState = [...state];
|
|
475
501
|
newState.push({
|
|
502
|
+
index: i,
|
|
476
503
|
payload,
|
|
477
504
|
type: command.type ? command.type : 'UNKNOWN'
|
|
478
505
|
});
|
|
@@ -487,11 +514,11 @@ function registerLexicalCommandLogger(editor, setLoggedCommands) {
|
|
|
487
514
|
return () => unregisterCommandListeners.forEach(unregister => unregister());
|
|
488
515
|
}
|
|
489
516
|
function useLexicalCommandsLog(editor) {
|
|
490
|
-
const [loggedCommands, setLoggedCommands] =
|
|
491
|
-
|
|
517
|
+
const [loggedCommands, setLoggedCommands] = react.useState([]);
|
|
518
|
+
react.useEffect(() => {
|
|
492
519
|
return registerLexicalCommandLogger(editor, setLoggedCommands);
|
|
493
520
|
}, [editor]);
|
|
494
|
-
return
|
|
521
|
+
return react.useMemo(() => loggedCommands, [loggedCommands]);
|
|
495
522
|
}
|
|
496
523
|
|
|
497
524
|
exports.TreeView = TreeView;
|
|
@@ -3,14 +3,16 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
6
7
|
*/
|
|
8
|
+
|
|
7
9
|
import { $generateHtmlFromNodes } from '@lexical/html';
|
|
8
10
|
import { $isLinkNode } from '@lexical/link';
|
|
9
11
|
import { $isMarkNode } from '@lexical/mark';
|
|
10
12
|
import { $isTableSelection } from '@lexical/table';
|
|
11
13
|
import { $getSelection, $getRoot, $isRangeSelection, $isNodeSelection, $isElementNode, $isTextNode, $isParagraphNode, COMMAND_PRIORITY_CRITICAL } from 'lexical';
|
|
12
|
-
import * as React from 'react';
|
|
13
14
|
import { forwardRef, useState, useRef, useCallback, useEffect, useMemo } from 'react';
|
|
15
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
@@ -19,6 +21,7 @@ import { forwardRef, useState, useRef, useCallback, useEffect, useMemo } from 'r
|
|
|
19
21
|
* LICENSE file in the root directory of this source tree.
|
|
20
22
|
*
|
|
21
23
|
*/
|
|
24
|
+
|
|
22
25
|
const NON_SINGLE_WIDTH_CHARS_REPLACEMENT = Object.freeze({
|
|
23
26
|
'\t': '\\t',
|
|
24
27
|
'\n': '\\n'
|
|
@@ -36,7 +39,7 @@ const FORMAT_PREDICATES = [node => node.hasFormat('bold') && 'Bold', node => nod
|
|
|
36
39
|
const FORMAT_PREDICATES_PARAGRAPH = [node => node.hasTextFormat('bold') && 'Bold', node => node.hasTextFormat('code') && 'Code', node => node.hasTextFormat('italic') && 'Italic', node => node.hasTextFormat('strikethrough') && 'Strikethrough', node => node.hasTextFormat('subscript') && 'Subscript', node => node.hasTextFormat('superscript') && 'Superscript', node => node.hasTextFormat('underline') && 'Underline'];
|
|
37
40
|
const DETAIL_PREDICATES = [node => node.isDirectionless() && 'Directionless', node => node.isUnmergeable() && 'Unmergeable'];
|
|
38
41
|
const MODE_PREDICATES = [node => node.isToken() && 'Token', node => node.isSegmented() && 'Segmented'];
|
|
39
|
-
function generateContent(editor, commandsLog, exportDOM) {
|
|
42
|
+
function generateContent(editor, commandsLog, exportDOM, customPrintNode, obfuscateText = false) {
|
|
40
43
|
const editorState = editor.getEditorState();
|
|
41
44
|
const editorConfig = editor._config;
|
|
42
45
|
const compositionKey = editor._compositionKey;
|
|
@@ -56,9 +59,8 @@ function generateContent(editor, commandsLog, exportDOM) {
|
|
|
56
59
|
const nodeKeyDisplay = `(${nodeKey})`;
|
|
57
60
|
const typeDisplay = node.getType() || '';
|
|
58
61
|
const isSelected = node.isSelected();
|
|
59
|
-
|
|
60
|
-
res +=
|
|
61
|
-
res += printSelectedCharsLine({
|
|
62
|
+
res += `${isSelected ? SYMBOLS.selectedLine : ' '} ${indent.join(' ')} ${nodeKeyDisplay} ${typeDisplay} ${printNode(node, customPrintNode, obfuscateText)}\n`;
|
|
63
|
+
res += $printSelectedCharsLine({
|
|
62
64
|
indent,
|
|
63
65
|
isSelected,
|
|
64
66
|
node,
|
|
@@ -73,10 +75,11 @@ function generateContent(editor, commandsLog, exportDOM) {
|
|
|
73
75
|
res += '\n\n commands:';
|
|
74
76
|
if (commandsLog.length) {
|
|
75
77
|
for (const {
|
|
78
|
+
index,
|
|
76
79
|
type,
|
|
77
80
|
payload
|
|
78
81
|
} of commandsLog) {
|
|
79
|
-
res += `\n └ { type: ${type}, payload: ${payload instanceof Event ? payload.constructor.name : payload} }`;
|
|
82
|
+
res += `\n └ ${index}. { type: ${type}, payload: ${payload instanceof Event ? payload.constructor.name : payload} }`;
|
|
80
83
|
}
|
|
81
84
|
} else {
|
|
82
85
|
res += '\n └ None dispatched.';
|
|
@@ -120,22 +123,30 @@ function visitTree(currentNode, visitor, indent = []) {
|
|
|
120
123
|
}
|
|
121
124
|
});
|
|
122
125
|
}
|
|
123
|
-
function normalize(text) {
|
|
124
|
-
|
|
126
|
+
function normalize(text, obfuscateText = false) {
|
|
127
|
+
const textToPrint = Object.entries(NON_SINGLE_WIDTH_CHARS_REPLACEMENT).reduce((acc, [key, value]) => acc.replace(new RegExp(key, 'g'), String(value)), text);
|
|
128
|
+
if (obfuscateText) {
|
|
129
|
+
return textToPrint.replace(/[^\s]/g, '*');
|
|
130
|
+
}
|
|
131
|
+
return textToPrint;
|
|
125
132
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
133
|
+
function printNode(node, customPrintNode, obfuscateText = false) {
|
|
134
|
+
const customPrint = customPrintNode ? customPrintNode(node, obfuscateText) : undefined;
|
|
135
|
+
if (customPrint !== undefined && customPrint.length > 0) {
|
|
136
|
+
return customPrint;
|
|
137
|
+
}
|
|
129
138
|
if ($isTextNode(node)) {
|
|
130
139
|
const text = node.getTextContent();
|
|
131
|
-
const title = text.length === 0 ? '(empty)' : `"${normalize(text)}"`;
|
|
140
|
+
const title = text.length === 0 ? '(empty)' : `"${normalize(text, obfuscateText)}"`;
|
|
132
141
|
const properties = printAllTextNodeProperties(node);
|
|
133
142
|
return [title, properties.length !== 0 ? `{ ${properties} }` : null].filter(Boolean).join(' ').trim();
|
|
134
143
|
} else if ($isLinkNode(node)) {
|
|
135
144
|
const link = node.getURL();
|
|
136
|
-
const title = link.length === 0 ? '(empty)' : `"${normalize(link)}"`;
|
|
145
|
+
const title = link.length === 0 ? '(empty)' : `"${normalize(link, obfuscateText)}"`;
|
|
137
146
|
const properties = printAllLinkNodeProperties(node);
|
|
138
147
|
return [title, properties.length !== 0 ? `{ ${properties} }` : null].filter(Boolean).join(' ').trim();
|
|
148
|
+
} else if ($isMarkNode(node)) {
|
|
149
|
+
return `ids: [ ${node.getIDs().join(', ')} ]`;
|
|
139
150
|
} else if ($isParagraphNode(node)) {
|
|
140
151
|
const formatText = printTextFormatProperties(node);
|
|
141
152
|
return formatText !== '' ? `{ ${formatText} }` : '';
|
|
@@ -201,7 +212,7 @@ function printTitleProperties(node) {
|
|
|
201
212
|
}
|
|
202
213
|
return str;
|
|
203
214
|
}
|
|
204
|
-
function printSelectedCharsLine({
|
|
215
|
+
function $printSelectedCharsLine({
|
|
205
216
|
indent,
|
|
206
217
|
isSelected,
|
|
207
218
|
node,
|
|
@@ -293,6 +304,7 @@ function $getSelectionStartEnd(node, selection) {
|
|
|
293
304
|
* LICENSE file in the root directory of this source tree.
|
|
294
305
|
*
|
|
295
306
|
*/
|
|
307
|
+
|
|
296
308
|
const LARGE_EDITOR_STATE_SIZE = 1000;
|
|
297
309
|
const TreeView = /*#__PURE__*/forwardRef(function TreeViewWrapped({
|
|
298
310
|
treeTypeButtonClassName,
|
|
@@ -380,82 +392,92 @@ const TreeView = /*#__PURE__*/forwardRef(function TreeViewWrapped({
|
|
|
380
392
|
generateTree(!showExportDOM);
|
|
381
393
|
setShowExportDOM(!showExportDOM);
|
|
382
394
|
};
|
|
383
|
-
return /*#__PURE__*/
|
|
384
|
-
className: viewClassName
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
395
|
+
return /*#__PURE__*/jsxs("div", {
|
|
396
|
+
className: viewClassName,
|
|
397
|
+
children: [!showLimited && isLimited ? /*#__PURE__*/jsxs("div", {
|
|
398
|
+
style: {
|
|
399
|
+
padding: 20
|
|
400
|
+
},
|
|
401
|
+
children: [/*#__PURE__*/jsx("span", {
|
|
402
|
+
style: {
|
|
403
|
+
marginRight: 20
|
|
404
|
+
},
|
|
405
|
+
children: "Detected large EditorState, this can impact debugging performance."
|
|
406
|
+
}), /*#__PURE__*/jsx("button", {
|
|
407
|
+
onClick: () => {
|
|
408
|
+
setShowLimited(true);
|
|
409
|
+
},
|
|
410
|
+
style: {
|
|
411
|
+
background: 'transparent',
|
|
412
|
+
border: '1px solid white',
|
|
413
|
+
color: 'white',
|
|
414
|
+
cursor: 'pointer',
|
|
415
|
+
padding: 5
|
|
416
|
+
},
|
|
417
|
+
children: "Show full tree"
|
|
418
|
+
})]
|
|
419
|
+
}) : null, !showLimited ? /*#__PURE__*/jsx("button", {
|
|
420
|
+
onClick: () => handleExportModeToggleClick(),
|
|
421
|
+
className: treeTypeButtonClassName,
|
|
422
|
+
type: "button",
|
|
423
|
+
children: showExportDOM ? 'Tree' : 'Export DOM'
|
|
424
|
+
}) : null, !timeTravelEnabled && (showLimited || !isLimited) && totalEditorStates > 2 && /*#__PURE__*/jsx("button", {
|
|
425
|
+
onClick: () => {
|
|
426
|
+
setEditorReadOnly(true);
|
|
427
|
+
playingIndexRef.current = totalEditorStates - 1;
|
|
428
|
+
setTimeTravelEnabled(true);
|
|
429
|
+
},
|
|
430
|
+
className: timeTravelButtonClassName,
|
|
431
|
+
type: "button",
|
|
432
|
+
children: "Time Travel"
|
|
433
|
+
}), (showLimited || !isLimited) && /*#__PURE__*/jsx("pre", {
|
|
434
|
+
ref: ref,
|
|
435
|
+
children: content
|
|
436
|
+
}), timeTravelEnabled && (showLimited || !isLimited) && /*#__PURE__*/jsxs("div", {
|
|
437
|
+
className: timeTravelPanelClassName,
|
|
438
|
+
children: [/*#__PURE__*/jsx("button", {
|
|
439
|
+
className: timeTravelPanelButtonClassName,
|
|
440
|
+
onClick: () => {
|
|
441
|
+
if (playingIndexRef.current === totalEditorStates - 1) {
|
|
442
|
+
playingIndexRef.current = 1;
|
|
443
|
+
}
|
|
444
|
+
setIsPlaying(!isPlaying);
|
|
445
|
+
},
|
|
446
|
+
type: "button",
|
|
447
|
+
children: isPlaying ? 'Pause' : 'Play'
|
|
448
|
+
}), /*#__PURE__*/jsx("input", {
|
|
449
|
+
className: timeTravelPanelSliderClassName,
|
|
450
|
+
ref: inputRef,
|
|
451
|
+
onChange: event => {
|
|
452
|
+
const editorStateIndex = Number(event.target.value);
|
|
453
|
+
const timeStampedEditorState = timeStampedEditorStates[editorStateIndex];
|
|
454
|
+
if (timeStampedEditorState) {
|
|
455
|
+
playingIndexRef.current = editorStateIndex;
|
|
456
|
+
setEditorState(timeStampedEditorState[1]);
|
|
457
|
+
}
|
|
458
|
+
},
|
|
459
|
+
type: "range",
|
|
460
|
+
min: "1",
|
|
461
|
+
max: totalEditorStates - 1
|
|
462
|
+
}), /*#__PURE__*/jsx("button", {
|
|
463
|
+
className: timeTravelPanelButtonClassName,
|
|
464
|
+
onClick: () => {
|
|
465
|
+
setEditorReadOnly(false);
|
|
466
|
+
const index = timeStampedEditorStates.length - 1;
|
|
467
|
+
const timeStampedEditorState = timeStampedEditorStates[index];
|
|
468
|
+
setEditorState(timeStampedEditorState[1]);
|
|
469
|
+
const input = inputRef.current;
|
|
470
|
+
if (input !== null) {
|
|
471
|
+
input.value = String(index);
|
|
472
|
+
}
|
|
473
|
+
setTimeTravelEnabled(false);
|
|
474
|
+
setIsPlaying(false);
|
|
475
|
+
},
|
|
476
|
+
type: "button",
|
|
477
|
+
children: "Exit"
|
|
478
|
+
})]
|
|
479
|
+
})]
|
|
480
|
+
});
|
|
459
481
|
});
|
|
460
482
|
|
|
461
483
|
/**
|
|
@@ -465,13 +487,17 @@ const TreeView = /*#__PURE__*/forwardRef(function TreeViewWrapped({
|
|
|
465
487
|
* LICENSE file in the root directory of this source tree.
|
|
466
488
|
*
|
|
467
489
|
*/
|
|
490
|
+
|
|
468
491
|
function registerLexicalCommandLogger(editor, setLoggedCommands) {
|
|
469
492
|
const unregisterCommandListeners = new Set();
|
|
493
|
+
let i = 0;
|
|
470
494
|
for (const [command] of editor._commands) {
|
|
471
495
|
unregisterCommandListeners.add(editor.registerCommand(command, payload => {
|
|
472
496
|
setLoggedCommands(state => {
|
|
497
|
+
i += 1;
|
|
473
498
|
const newState = [...state];
|
|
474
499
|
newState.push({
|
|
500
|
+
index: i,
|
|
475
501
|
payload,
|
|
476
502
|
type: command.type ? command.type : 'UNKNOWN'
|
|
477
503
|
});
|
package/LexicalDevtoolsCore.js
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
6
7
|
*/
|
|
8
|
+
|
|
7
9
|
'use strict'
|
|
8
10
|
const LexicalDevtoolsCore = process.env.NODE_ENV === 'development' ? require('./LexicalDevtoolsCore.dev.js') : require('./LexicalDevtoolsCore.prod.js');
|
|
9
11
|
module.exports = LexicalDevtoolsCore;
|
|
@@ -6,3 +6,37 @@
|
|
|
6
6
|
*
|
|
7
7
|
* @flow strict
|
|
8
8
|
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* LexicalDevtoolsCore
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import type {
|
|
15
|
+
LexicalCommand,
|
|
16
|
+
LexicalEditor,
|
|
17
|
+
LexicalNode,
|
|
18
|
+
} from 'lexical';
|
|
19
|
+
|
|
20
|
+
export type LexicalCommandLog = $ReadOnlyArray<
|
|
21
|
+
{index: number} | LexicalCommand<mixed> | {payload: mixed}
|
|
22
|
+
>;
|
|
23
|
+
export type CustomPrintNodeFn = (node: LexicalNode, obfuscateText?: boolean) => string;
|
|
24
|
+
|
|
25
|
+
declare export function generateContent(
|
|
26
|
+
editor: LexicalEditor,
|
|
27
|
+
commandsLog: $ReadOnlyArray<LexicalCommandLog>,
|
|
28
|
+
exportDOM: boolean,
|
|
29
|
+
customPrintNode?: CustomPrintNodeFn,
|
|
30
|
+
obfuscateText?: boolean,
|
|
31
|
+
): string;
|
|
32
|
+
|
|
33
|
+
declare export function registerLexicalCommandLogger(
|
|
34
|
+
editor: LexicalEditor,
|
|
35
|
+
setLoggedCommands: (
|
|
36
|
+
v: (oldValue: LexicalCommandLog) => LexicalCommandLog,
|
|
37
|
+
) => void,
|
|
38
|
+
): () => void;
|
|
39
|
+
|
|
40
|
+
declare export function useLexicalCommandsLog(
|
|
41
|
+
editor: LexicalEditor,
|
|
42
|
+
): LexicalCommandLog;
|
package/LexicalDevtoolsCore.mjs
CHANGED
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
6
7
|
*/
|
|
8
|
+
|
|
7
9
|
import * as modDev from './LexicalDevtoolsCore.dev.mjs';
|
|
8
10
|
import * as modProd from './LexicalDevtoolsCore.prod.mjs';
|
|
9
11
|
const mod = process.env.NODE_ENV === 'development' ? modDev : modProd;
|
|
@@ -3,7 +3,9 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
6
7
|
*/
|
|
8
|
+
|
|
7
9
|
const mod = await (process.env.NODE_ENV === 'development' ? import('./LexicalDevtoolsCore.dev.mjs') : import('./LexicalDevtoolsCore.prod.mjs'));
|
|
8
10
|
export const TreeView = mod.TreeView;
|
|
9
11
|
export const generateContent = mod.generateContent;
|
|
@@ -3,23 +3,25 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
function
|
|
12
|
-
function
|
|
13
|
-
(a=
|
|
14
|
-
function
|
|
15
|
-
function
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
null
|
|
8
|
+
|
|
9
|
+
'use strict';var k=require("@lexical/html"),t=require("@lexical/link"),u=require("@lexical/mark"),w=require("@lexical/table"),L=require("lexical"),M=require("react"),N=require("react/jsx-runtime");
|
|
10
|
+
let O=Object.freeze({"\t":"\\t","\n":"\\n"}),P=new RegExp(Object.keys(O).join("|"),"g"),Q=Object.freeze({ancestorHasNextSibling:"|",ancestorIsLastChild:" ",hasNextSibling:"\u251c",isLastChild:"\u2514",selectedChar:"^",selectedLine:">"}),aa=[a=>a.hasFormat("bold")&&"Bold",a=>a.hasFormat("code")&&"Code",a=>a.hasFormat("italic")&&"Italic",a=>a.hasFormat("strikethrough")&&"Strikethrough",a=>a.hasFormat("subscript")&&"Subscript",a=>a.hasFormat("superscript")&&"Superscript",a=>a.hasFormat("underline")&&
|
|
11
|
+
"Underline"],ba=[a=>a.hasTextFormat("bold")&&"Bold",a=>a.hasTextFormat("code")&&"Code",a=>a.hasTextFormat("italic")&&"Italic",a=>a.hasTextFormat("strikethrough")&&"Strikethrough",a=>a.hasTextFormat("subscript")&&"Subscript",a=>a.hasTextFormat("superscript")&&"Superscript",a=>a.hasTextFormat("underline")&&"Underline"],ca=[a=>a.isDirectionless()&&"Directionless",a=>a.isUnmergeable()&&"Unmergeable"],da=[a=>a.isToken()&&"Token",a=>a.isSegmented()&&"Segmented"];
|
|
12
|
+
function ea(a){let b="";var c=V(a);b+=`: range ${""!==c?`{ ${c} }`:""} ${""!==a.style?`{ style: ${a.style} } `:""}`;c=a.anchor;a=a.focus;let e=c.offset,d=a.offset;b+=`\n \u251c anchor { key: ${c.key}, offset: ${null===e?"null":e}, type: ${c.type} }`;return b+=`\n \u2514 focus { key: ${a.key}, offset: ${null===d?"null":d}, type: ${a.type} }`}function fa(a){return L.$isNodeSelection(a)?`: node\n \u2514 [${Array.from(a._nodes).join(", ")}]`:""}
|
|
13
|
+
function W(a,b,c=[]){a=a.getChildren();let e=a.length;a.forEach((d,l)=>{b(d,c.concat(l===e-1?Q.isLastChild:Q.hasNextSibling));L.$isElementNode(d)&&W(d,b,c.concat(l===e-1?Q.ancestorIsLastChild:Q.ancestorHasNextSibling))})}function X(a,b=!1){a=Object.entries(O).reduce((c,[e,d])=>c.replace(new RegExp(e,"g"),String(d)),a);return b?a.replace(/[^\s]/g,"*"):a}
|
|
14
|
+
function ha(a,b,c=!1){b=b?b(a,c):void 0;if(void 0!==b&&0<b.length)return b;if(L.$isTextNode(a))return b=a.getTextContent(),c=0===b.length?"(empty)":`"${X(b,c)}"`,a=[V(a),ia(a),ja(a)].filter(Boolean).join(", "),[c,0!==a.length?`{ ${a} }`:null].filter(Boolean).join(" ").trim();if(t.$isLinkNode(a)){b=a.getURL();c=0===b.length?"(empty)":`"${X(b,c)}"`;b=a.getTarget();null!=b&&(b="target: "+b);var e=Boolean;var d=a.getRel();null!=d&&(d="rel: "+d);a=a.getTitle();null!=a&&(a="title: "+a);a=[b,d,a].filter(e).join(", ");
|
|
15
|
+
return[c,0!==a.length?`{ ${a} }`:null].filter(Boolean).join(" ").trim()}return u.$isMarkNode(a)?`ids: [ ${a.getIDs().join(", ")} ]`:L.$isParagraphNode(a)?(a=ka(a),""!==a?`{ ${a} }`:""):""}function ka(a){let b=ba.map(c=>c(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==b&&(b="format: "+b);return b}function ia(a){let b=ca.map(c=>c(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==b&&(b="detail: "+b);return b}
|
|
16
|
+
function ja(a){let b=da.map(c=>c(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==b&&(b="mode: "+b);return b}function V(a){let b=aa.map(c=>c(a)).filter(Boolean).join(", ").toLocaleLowerCase();""!==b&&(b="format: "+b);return b}
|
|
17
|
+
function la({indent:a,isSelected:b,node:c,nodeKeyDisplay:e,selection:d,typeDisplay:l}){if(!L.$isTextNode(c)||!L.$isRangeSelection(d)||!b||L.$isElementNode(c))return"";b=d.anchor;var f=d.focus;if(""===c.getTextContent()||b.getNode()===d.focus.getNode()&&b.offset===f.offset)return"";b=d.getStartEndPoints();if(L.$isNodeSelection(d)||null===b)c=[-1,-1];else{var [p,r]=b;f=c.getTextContent();var m=f.length;b=d=-1;if("text"===p.type&&"text"===r.type){let n=p.getNode(),x=r.getNode();n===x&&c===n&&p.offset!==
|
|
18
|
+
r.offset?[d,b]=p.offset<r.offset?[p.offset,r.offset]:[r.offset,p.offset]:c===n?[d,b]=n.isBefore(x)?[p.offset,m]:[0,p.offset]:c===x?[d,b]=x.isBefore(n)?[r.offset,m]:[0,r.offset]:[d,b]=[0,m]}c=(f.slice(0,d).match(P)||[]).length;f=(f.slice(d,b).match(P)||[]).length;c=[d+c,b+c+f]}let [h,g]=c;if(h===g)return"";c=a[a.length-1]===Q.hasNextSibling?Q.ancestorHasNextSibling:Q.ancestorIsLastChild;a=[...a.slice(0,a.length-1),c];c=Array(h+1).fill(" ");d=Array(g-h).fill(Q.selectedChar);e=Array(e.length+(l.length+
|
|
19
|
+
3)).fill(" ");return[Q.selectedLine,a.join(" "),[...e,...c,...d].join("")].join(" ")+"\n"}function Y(a,b){let c=Array(b++ +1).join(" "),e=Array(b-1).join(" "),d;for(let l=0;l<a.children.length;l++)d=document.createTextNode("\n"+c),a.insertBefore(d,a.children[l]),Y(a.children[l],b),a.lastElementChild===a.children[l]&&(d=document.createTextNode("\n"+e),a.appendChild(d));return a}
|
|
20
|
+
let pa=M.forwardRef(function({treeTypeButtonClassName:a,timeTravelButtonClassName:b,timeTravelPanelSliderClassName:c,timeTravelPanelButtonClassName:e,viewClassName:d,timeTravelPanelClassName:l,editorState:f,setEditorState:p,setEditorReadOnly:r,generateContent:m},h){const [g,n]=M.useState([]),[x,D]=M.useState(""),[A,R]=M.useState(!1),[E,ma]=M.useState(!1),B=M.useRef(0),H=M.useRef(null),[F,I]=M.useState(!1),[G,na]=M.useState(!1),[y,oa]=M.useState(!1),S=M.useRef(),J=M.useRef(0),K=M.useCallback(q=>{const v=
|
|
21
|
+
++J.current;m(q).then(z=>{v===J.current&&D(z)}).catch(z=>{v===J.current&&D(`Error rendering tree: ${z.message}\n\nStack:\n${z.stack}`)})},[m]);M.useEffect(()=>{if(!y&&1E3<f._nodeMap.size&&(na(!0),!y))return;S.current!==f&&(S.current=f,K(E),A||n(q=>[...q,[Date.now(),f]]))},[f,K,E,y,A]);const C=g.length;M.useEffect(()=>{if(F){let q;const v=()=>{const z=B.current;z===C-1?I(!1):q=setTimeout(()=>{B.current++;const T=B.current,U=H.current;null!==U&&(U.value=String(T));p(g[T][1]);v()},g[z+1][0]-g[z][0])};
|
|
22
|
+
v();return()=>{clearTimeout(q)}}},[g,F,C,p]);return N.jsxs("div",{className:d,children:[!y&&G?N.jsxs("div",{style:{padding:20},children:[N.jsx("span",{style:{marginRight:20},children:"Detected large EditorState, this can impact debugging performance."}),N.jsx("button",{onClick:()=>{oa(!0)},style:{background:"transparent",border:"1px solid white",color:"white",cursor:"pointer",padding:5},children:"Show full tree"})]}):null,y?null:N.jsx("button",{onClick:()=>{K(!E);ma(!E)},className:a,type:"button",
|
|
23
|
+
children:E?"Tree":"Export DOM"}),!A&&(y||!G)&&2<C&&N.jsx("button",{onClick:()=>{r(!0);B.current=C-1;R(!0)},className:b,type:"button",children:"Time Travel"}),(y||!G)&&N.jsx("pre",{ref:h,children:x}),A&&(y||!G)&&N.jsxs("div",{className:l,children:[N.jsx("button",{className:e,onClick:()=>{B.current===C-1&&(B.current=1);I(!F)},type:"button",children:F?"Pause":"Play"}),N.jsx("input",{className:c,ref:H,onChange:q=>{q=Number(q.target.value);const v=g[q];v&&(B.current=q,p(v[1]))},type:"range",min:"1",max:C-
|
|
24
|
+
1}),N.jsx("button",{className:e,onClick:()=>{r(!1);const q=g.length-1;p(g[q][1]);const v=H.current;null!==v&&(v.value=String(q));R(!1);I(!1)},type:"button",children:"Exit"})]})]})});function Z(a,b){let c=new Set,e=0;for(let [d]of a._commands)c.add(a.registerCommand(d,l=>{b(f=>{e+=1;f=[...f];f.push({index:e,payload:l,type:d.type?d.type:"UNKNOWN"});10<f.length&&f.shift();return f});return!1},L.COMMAND_PRIORITY_CRITICAL));return()=>c.forEach(d=>d())}exports.TreeView=pa;
|
|
25
|
+
exports.generateContent=function(a,b,c,e,d=!1){let l=a.getEditorState(),f=a._config,p=a._compositionKey,r=a._editable;if(c){let h="";l.read(()=>{var g=k.$generateHtmlFromNodes(a);let n=document.createElement("div");n.innerHTML=g.trim();h=Y(n,0).innerHTML});return h}let m=" root\n";c=l.read(()=>{const h=L.$getSelection();W(L.$getRoot(),(g,n)=>{const x=`(${g.getKey()})`,D=g.getType()||"",A=g.isSelected();m+=`${A?Q.selectedLine:" "} ${n.join(" ")} ${x} ${D} ${ha(g,e,d)}\n`;m+=la({indent:n,isSelected:A,
|
|
26
|
+
node:g,nodeKeyDisplay:x,selection:h,typeDisplay:D})});return null===h?": null":L.$isRangeSelection(h)?ea(h):w.$isTableSelection(h)?`: table\n \u2514 { table: ${h.tableKey}, anchorCell: ${h.anchor.key}, focusCell: ${h.focus.key} }`:fa(h)});m+="\n selection"+c;m+="\n\n commands:";if(b.length)for(let {index:h,type:g,payload:n}of b)m+=`\n \u2514 ${h}. { type: ${g}, payload: ${n instanceof Event?n.constructor.name:n} }`;else m+="\n \u2514 None dispatched.";m+="\n\n editor:";m+=`\n \u2514 namespace ${f.namespace}`;
|
|
27
|
+
null!==p&&(m+=`\n \u2514 compositionKey ${p}`);return m+=`\n \u2514 editable ${String(r)}`};exports.registerLexicalCommandLogger=Z;exports.useLexicalCommandsLog=function(a){let [b,c]=M.useState([]);M.useEffect(()=>Z(a,c),[a]);return M.useMemo(()=>b,[b])}
|
|
@@ -3,5 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the MIT license found in the
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
6
7
|
*/
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
import{$generateHtmlFromNodes as e}from"@lexical/html";import{$isLinkNode as t}from"@lexical/link";import{$isMarkNode as n}from"@lexical/mark";import{$isTableSelection as r}from"@lexical/table";import{$getSelection as o,$getRoot as i,$isRangeSelection as l,$isNodeSelection as s,$isElementNode as a,$isTextNode as c,$isParagraphNode as u,COMMAND_PRIORITY_CRITICAL as f}from"lexical";import{forwardRef as d,useState as m,useRef as h,useCallback as g,useEffect as p,useMemo as y}from"react";import{jsxs as b,jsx as x}from"react/jsx-runtime";const C=Object.freeze({"\t":"\\t","\n":"\\n"}),$=new RegExp(Object.keys(C).join("|"),"g"),N=Object.freeze({ancestorHasNextSibling:"|",ancestorIsLastChild:" ",hasNextSibling:"├",isLastChild:"└",selectedChar:"^",selectedLine:">"}),S=[e=>e.hasFormat("bold")&&"Bold",e=>e.hasFormat("code")&&"Code",e=>e.hasFormat("italic")&&"Italic",e=>e.hasFormat("strikethrough")&&"Strikethrough",e=>e.hasFormat("subscript")&&"Subscript",e=>e.hasFormat("superscript")&&"Superscript",e=>e.hasFormat("underline")&&"Underline"],T=[e=>e.hasTextFormat("bold")&&"Bold",e=>e.hasTextFormat("code")&&"Code",e=>e.hasTextFormat("italic")&&"Italic",e=>e.hasTextFormat("strikethrough")&&"Strikethrough",e=>e.hasTextFormat("subscript")&&"Subscript",e=>e.hasTextFormat("superscript")&&"Superscript",e=>e.hasTextFormat("underline")&&"Underline"],k=[e=>e.isDirectionless()&&"Directionless",e=>e.isUnmergeable()&&"Unmergeable"],j=[e=>e.isToken()&&"Token",e=>e.isSegmented()&&"Segmented"];function L(f,d,m,h,g=!1){const p=f.getEditorState(),y=f._config,b=f._compositionKey,x=f._editable;if(m){let t="";return p.read((()=>{t=function(e){const t=document.createElement("div");return t.innerHTML=e.trim(),A(t,0).innerHTML}(e(f))})),t}let C=" root\n";const S=p.read((()=>{const e=o();return v(i(),((r,o)=>{const i=`(${r.getKey()})`,f=r.getType()||"",d=r.isSelected();C+=`${d?N.selectedLine:" "} ${o.join(" ")} ${i} ${f} ${function(e,r,o=!1){const i=r?r(e,o):void 0;if(void 0!==i&&i.length>0)return i;if(c(e)){const t=e.getTextContent(),n=0===t.length?"(empty)":`"${B(t,o)}"`,r=function(e){return[F(e),E(e),w(e)].filter(Boolean).join(", ")}(e);return[n,0!==r.length?`{ ${r} }`:null].filter(Boolean).join(" ").trim()}if(t(e)){const t=e.getURL(),n=0===t.length?"(empty)":`"${B(t,o)}"`,r=function(e){return[D(e),K(e),O(e)].filter(Boolean).join(", ")}(e);return[n,0!==r.length?`{ ${r} }`:null].filter(Boolean).join(" ").trim()}if(n(e))return`ids: [ ${e.getIDs().join(", ")} ]`;if(u(e)){const t=function(e){let t=T.map((t=>t(e))).filter(Boolean).join(", ").toLocaleLowerCase();""!==t&&(t="format: "+t);return t}(e);return""!==t?`{ ${t} }`:""}return""}(r,h,g)}\n`,C+=function({indent:e,isSelected:t,node:n,nodeKeyDisplay:r,selection:o,typeDisplay:i}){if(!c(n)||!l(o)||!t||a(n))return"";const u=o.anchor,f=o.focus;if(""===n.getTextContent()||u.getNode()===o.focus.getNode()&&u.offset===f.offset)return"";const[d,m]=function(e,t){const n=t.getStartEndPoints();if(s(t)||null===n)return[-1,-1];const[r,o]=n,i=e.getTextContent(),l=i.length;let a=-1,c=-1;if("text"===r.type&&"text"===o.type){const t=r.getNode(),n=o.getNode();t===n&&e===t&&r.offset!==o.offset?[a,c]=r.offset<o.offset?[r.offset,o.offset]:[o.offset,r.offset]:[a,c]=e===t?t.isBefore(n)?[r.offset,l]:[0,r.offset]:e===n?n.isBefore(t)?[o.offset,l]:[0,o.offset]:[0,l]}const u=(i.slice(0,a).match($)||[]).length,f=(i.slice(a,c).match($)||[]).length;return[a+u,c+u+f]}(n,o);if(d===m)return"";const h=e[e.length-1]===N.hasNextSibling?N.ancestorHasNextSibling:N.ancestorIsLastChild,g=[...e.slice(0,e.length-1),h],p=Array(d+1).fill(" "),y=Array(m-d).fill(N.selectedChar),b=i.length+3,x=Array(r.length+b).fill(" ");return[N.selectedLine,g.join(" "),[...x,...p,...y].join("")].join(" ")+"\n"}({indent:o,isSelected:d,node:r,nodeKeyDisplay:i,selection:e,typeDisplay:f})})),null===e?": null":l(e)?function(e){let t="";const n=F(e);t+=`: range ${""!==n?`{ ${n} }`:""} ${""!==e.style?`{ style: ${e.style} } `:""}`;const r=e.anchor,o=e.focus,i=r.offset,l=o.offset;return t+=`\n ├ anchor { key: ${r.key}, offset: ${null===i?"null":i}, type: ${r.type} }`,t+=`\n └ focus { key: ${o.key}, offset: ${null===l?"null":l}, type: ${o.type} }`,t}(e):r(e)?function(e){return`: table\n └ { table: ${e.tableKey}, anchorCell: ${e.anchor.key}, focusCell: ${e.focus.key} }`}(e):function(e){if(!s(e))return"";return`: node\n └ [${Array.from(e._nodes).join(", ")}]`}(e)}));if(C+="\n selection"+S,C+="\n\n commands:",d.length)for(const{index:e,type:t,payload:n}of d)C+=`\n └ ${e}. { type: ${t}, payload: ${n instanceof Event?n.constructor.name:n} }`;else C+="\n └ None dispatched.";return C+="\n\n editor:",C+=`\n └ namespace ${y.namespace}`,null!==b&&(C+=`\n └ compositionKey ${b}`),C+=`\n └ editable ${String(x)}`,C}function v(e,t,n=[]){const r=e.getChildren(),o=r.length;r.forEach(((e,r)=>{t(e,n.concat(r===o-1?N.isLastChild:N.hasNextSibling)),a(e)&&v(e,t,n.concat(r===o-1?N.ancestorIsLastChild:N.ancestorHasNextSibling))}))}function B(e,t=!1){const n=Object.entries(C).reduce(((e,[t,n])=>e.replace(new RegExp(t,"g"),String(n))),e);return t?n.replace(/[^\s]/g,"*"):n}function E(e){let t=k.map((t=>t(e))).filter(Boolean).join(", ").toLocaleLowerCase();return""!==t&&(t="detail: "+t),t}function w(e){let t=j.map((t=>t(e))).filter(Boolean).join(", ").toLocaleLowerCase();return""!==t&&(t="mode: "+t),t}function F(e){let t=S.map((t=>t(e))).filter(Boolean).join(", ").toLocaleLowerCase();return""!==t&&(t="format: "+t),t}function D(e){let t=e.getTarget();return null!=t&&(t="target: "+t),t}function K(e){let t=e.getRel();return null!=t&&(t="rel: "+t),t}function O(e){let t=e.getTitle();return null!=t&&(t="title: "+t),t}function A(e,t){const n=new Array(1+t++).join(" "),r=new Array(t-1).join(" ");let o;for(let i=0;i<e.children.length;i++)o=document.createTextNode("\n"+n),e.insertBefore(o,e.children[i]),A(e.children[i],t),e.lastElementChild===e.children[i]&&(o=document.createTextNode("\n"+r),e.appendChild(o));return e}const I=d((function({treeTypeButtonClassName:e,timeTravelButtonClassName:t,timeTravelPanelSliderClassName:n,timeTravelPanelButtonClassName:r,viewClassName:o,timeTravelPanelClassName:i,editorState:l,setEditorState:s,setEditorReadOnly:a,generateContent:c},u){const[f,d]=m([]),[y,C]=m(""),[$,N]=m(!1),[S,T]=m(!1),k=h(0),j=h(null),[L,v]=m(!1),[B,E]=m(!1),[w,F]=m(!1),D=h(),K=h(0),O=g((e=>{const t=++K.current;c(e).then((e=>{t===K.current&&C(e)})).catch((e=>{t===K.current&&C(`Error rendering tree: ${e.message}\n\nStack:\n${e.stack}`)}))}),[c]);p((()=>{!w&&l._nodeMap.size>1e3&&(E(!0),!w)||D.current!==l&&(D.current=l,O(S),$||d((e=>[...e,[Date.now(),l]])))}),[l,O,S,w,$]);const A=f.length;p((()=>{if(L){let e;const t=()=>{const n=k.current;if(n===A-1)return void v(!1);const r=f[n][0],o=f[n+1][0];e=setTimeout((()=>{k.current++;const e=k.current,n=j.current;null!==n&&(n.value=String(e)),s(f[e][1]),t()}),o-r)};return t(),()=>{clearTimeout(e)}}}),[f,L,A,s]);return b("div",{className:o,children:[!w&&B?b("div",{style:{padding:20},children:[x("span",{style:{marginRight:20},children:"Detected large EditorState, this can impact debugging performance."}),x("button",{onClick:()=>{F(!0)},style:{background:"transparent",border:"1px solid white",color:"white",cursor:"pointer",padding:5},children:"Show full tree"})]}):null,w?null:x("button",{onClick:()=>(O(!S),void T(!S)),className:e,type:"button",children:S?"Tree":"Export DOM"}),!$&&(w||!B)&&A>2&&x("button",{onClick:()=>{a(!0),k.current=A-1,N(!0)},className:t,type:"button",children:"Time Travel"}),(w||!B)&&x("pre",{ref:u,children:y}),$&&(w||!B)&&b("div",{className:i,children:[x("button",{className:r,onClick:()=>{k.current===A-1&&(k.current=1),v(!L)},type:"button",children:L?"Pause":"Play"}),x("input",{className:n,ref:j,onChange:e=>{const t=Number(e.target.value),n=f[t];n&&(k.current=t,s(n[1]))},type:"range",min:"1",max:A-1}),x("button",{className:r,onClick:()=>{a(!1);const e=f.length-1,t=f[e];s(t[1]);const n=j.current;null!==n&&(n.value=String(e)),N(!1),v(!1)},type:"button",children:"Exit"})]})]})}));function P(e,t){const n=new Set;let r=0;for(const[o]of e._commands)n.add(e.registerCommand(o,(e=>(t((t=>{r+=1;const n=[...t];return n.push({index:r,payload:e,type:o.type?o.type:"UNKNOWN"}),n.length>10&&n.shift(),n})),!1)),f));return()=>n.forEach((e=>e()))}function R(e){const[t,n]=m([]);return p((()=>P(e,n)),[e]),y((()=>t),[t])}export{I as TreeView,L as generateContent,P as registerLexicalCommandLogger,R as useLexicalCommandsLog};
|
package/generateContent.d.ts
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*
|
|
7
7
|
*/
|
|
8
|
-
import type { LexicalEditor } from 'lexical';
|
|
9
|
-
import {
|
|
10
|
-
export
|
|
11
|
-
|
|
12
|
-
}>, exportDOM: boolean): string;
|
|
8
|
+
import type { LexicalEditor, LexicalNode } from 'lexical';
|
|
9
|
+
import { LexicalCommandLog } from './useLexicalCommandsLog';
|
|
10
|
+
export type CustomPrintNodeFn = (node: LexicalNode, obfuscateText?: boolean) => string;
|
|
11
|
+
export declare function generateContent(editor: LexicalEditor, commandsLog: LexicalCommandLog, exportDOM: boolean, customPrintNode?: CustomPrintNodeFn, obfuscateText?: boolean): string;
|
package/package.json
CHANGED
|
@@ -8,16 +8,16 @@
|
|
|
8
8
|
"utils"
|
|
9
9
|
],
|
|
10
10
|
"license": "MIT",
|
|
11
|
-
"version": "0.
|
|
11
|
+
"version": "0.16.0",
|
|
12
12
|
"main": "LexicalDevtoolsCore.js",
|
|
13
13
|
"types": "index.d.ts",
|
|
14
14
|
"dependencies": {
|
|
15
|
-
"@lexical/html": "0.
|
|
16
|
-
"@lexical/link": "0.
|
|
17
|
-
"@lexical/mark": "0.
|
|
18
|
-
"@lexical/table": "0.
|
|
19
|
-
"@lexical/utils": "0.
|
|
20
|
-
"lexical": "0.
|
|
15
|
+
"@lexical/html": "0.16.0",
|
|
16
|
+
"@lexical/link": "0.16.0",
|
|
17
|
+
"@lexical/mark": "0.16.0",
|
|
18
|
+
"@lexical/table": "0.16.0",
|
|
19
|
+
"@lexical/utils": "0.16.0",
|
|
20
|
+
"lexical": "0.16.0"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {
|
|
23
23
|
"react": ">=17.x",
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import type { LexicalEditor } from 'lexical';
|
|
9
9
|
import { LexicalCommand } from 'lexical';
|
|
10
|
-
export type LexicalCommandLog = ReadonlyArray<
|
|
10
|
+
export type LexicalCommandLog = ReadonlyArray<{
|
|
11
|
+
index: number;
|
|
12
|
+
} & LexicalCommand<unknown> & {
|
|
11
13
|
payload: unknown;
|
|
12
14
|
}>;
|
|
13
15
|
export declare function registerLexicalCommandLogger(editor: LexicalEditor, setLoggedCommands: (v: (oldValue: LexicalCommandLog) => LexicalCommandLog) => void): () => void;
|