@bayonai/rich-text-editor 0.1.2 → 1.0.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/BEHAVIOR.md +396 -0
- package/CHANGELOG.md +22 -0
- package/README.md +25 -6
- package/dist/core/blockTree.d.ts +14 -0
- package/dist/core/blockTree.js +126 -0
- package/dist/core/blockTypes.d.ts +6 -0
- package/dist/core/blockTypes.js +5 -0
- package/dist/core/exportImport.d.ts +59 -0
- package/dist/core/exportImport.js +51 -0
- package/dist/core/features.d.ts +59 -0
- package/dist/core/features.js +57 -0
- package/dist/core/imageBlockDiagnostics.d.ts +4 -0
- package/dist/core/imageBlockDiagnostics.js +19 -0
- package/dist/core/proFeatures.d.ts +60 -0
- package/dist/core/proFeatures.js +64 -0
- package/dist/{richText.d.ts → core/richText.d.ts} +2 -0
- package/dist/core/richText.js +566 -0
- package/dist/core/types.d.ts +78 -0
- package/dist/index.d.ts +14 -8
- package/dist/index.js +8 -5
- package/dist/react/editor/RichTextBody.d.ts +28 -0
- package/dist/react/editor/RichTextBody.js +131 -0
- package/dist/react/editor/RichTextEditor.d.ts +138 -0
- package/dist/react/editor/RichTextEditor.js +2925 -0
- package/dist/react/editor/RichTextRenderedBlock.d.ts +20 -0
- package/dist/react/editor/RichTextRenderedBlock.js +162 -0
- package/dist/react/editor/RichTextRenderer.d.ts +13 -0
- package/dist/react/editor/RichTextRenderer.js +16 -0
- package/dist/react/{RichTextTitleInput.d.ts → editor/RichTextTitleInput.d.ts} +11 -1
- package/dist/react/{RichTextTitleInput.js → editor/RichTextTitleInput.js} +17 -2
- package/dist/react/editor/blockActions.d.ts +48 -0
- package/dist/react/editor/blockActions.js +495 -0
- package/dist/react/editor/editorHistory.d.ts +55 -0
- package/dist/react/editor/editorHistory.js +111 -0
- package/dist/react/{editorNavigation.d.ts → editor/editorNavigation.d.ts} +2 -0
- package/dist/react/{editorNavigation.js → editor/editorNavigation.js} +16 -0
- package/dist/react/editor/editorOperations.d.ts +10 -0
- package/dist/react/editor/editorOperations.js +3 -0
- package/dist/react/editor/editorSelection.d.ts +3 -0
- package/dist/react/editor/editorSelection.js +215 -0
- package/dist/react/{editorShortcuts.d.ts → editor/editorShortcuts.d.ts} +10 -0
- package/dist/react/{editorShortcuts.js → editor/editorShortcuts.js} +17 -1
- package/dist/react/{RichTextIcons.d.ts → icons/RichTextIcons.d.ts} +3 -0
- package/dist/react/{RichTextIcons.js → icons/RichTextIcons.js} +9 -0
- package/dist/react/index.d.ts +12 -9
- package/dist/react/index.js +7 -6
- package/dist/react/{EditorSessionProvider.d.ts → session/EditorSessionProvider.d.ts} +2 -2
- package/dist/react/{EditorSessionProvider.js → session/EditorSessionProvider.js} +3 -3
- package/dist/react/{UnsavedChangesDialog.js → session/UnsavedChangesDialog.js} +1 -1
- package/dist/react/styles/RichTextStyles.js +1362 -0
- package/dist/react/{BlockActionTool.d.ts → tools/BlockActionTool.d.ts} +1 -1
- package/dist/react/{BlockActionTool.js → tools/BlockActionTool.js} +6 -2
- package/dist/react/tools/LinkCreationInput.d.ts +9 -0
- package/dist/react/tools/LinkCreationInput.js +38 -0
- package/dist/react/{SelectionFormatToolbar.d.ts → tools/SelectionFormatToolbar.d.ts} +3 -2
- package/dist/react/{SelectionFormatToolbar.js → tools/SelectionFormatToolbar.js} +3 -3
- package/dist/react/tools/SpecialBlockOption.d.ts +9 -0
- package/dist/react/tools/SpecialBlockOption.js +8 -0
- package/dist/react/tools/SpecialBlockTool.d.ts +91 -0
- package/dist/react/tools/SpecialBlockTool.js +125 -0
- package/dist/react/{TranscriptionControl.d.ts → tools/TranscriptionControl.d.ts} +9 -0
- package/dist/react/{TranscriptionControl.js → tools/TranscriptionControl.js} +70 -9
- package/dist/react/tools/blockActionToolState.d.ts +41 -0
- package/dist/react/tools/blockActionToolState.js +177 -0
- package/dist/react/tools/imageBlockDiagnostics.d.ts +2 -0
- package/dist/react/tools/imageBlockDiagnostics.js +12 -0
- package/dist/{session.d.ts → session/session.d.ts} +1 -1
- package/dist-cjs/core/blockTree.js +137 -0
- package/dist-cjs/core/blockTypes.js +9 -0
- package/dist-cjs/core/exportImport.js +56 -0
- package/dist-cjs/core/features.js +62 -0
- package/dist-cjs/core/proFeatures.js +70 -0
- package/dist-cjs/core/richText.js +578 -0
- package/dist-cjs/index.js +22 -6
- package/dist-cjs/react/editor/RichTextBody.js +134 -0
- package/dist-cjs/react/editor/RichTextEditor.js +2956 -0
- package/dist-cjs/react/editor/RichTextRenderedBlock.js +166 -0
- package/dist-cjs/react/editor/RichTextRenderer.js +20 -0
- package/dist-cjs/react/{RichTextTitleInput.js → editor/RichTextTitleInput.js} +18 -2
- package/dist-cjs/react/editor/blockActions.js +518 -0
- package/dist-cjs/react/editor/editorHistory.js +120 -0
- package/dist-cjs/react/{editorNavigation.js → editor/editorNavigation.js} +17 -0
- package/dist-cjs/react/editor/editorOperations.js +6 -0
- package/dist-cjs/react/editor/editorSelection.js +219 -0
- package/dist-cjs/react/{editorShortcuts.js → editor/editorShortcuts.js} +17 -1
- package/dist-cjs/react/{RichTextIcons.js → icons/RichTextIcons.js} +12 -0
- package/dist-cjs/react/index.js +9 -7
- package/dist-cjs/react/{EditorSessionProvider.js → session/EditorSessionProvider.js} +3 -3
- package/dist-cjs/react/{UnsavedChangesDialog.js → session/UnsavedChangesDialog.js} +1 -1
- package/dist-cjs/react/styles/RichTextStyles.js +1365 -0
- package/dist-cjs/react/{BlockActionTool.js → tools/BlockActionTool.js} +6 -2
- package/dist-cjs/react/tools/LinkCreationInput.js +41 -0
- package/dist-cjs/react/{SelectionFormatToolbar.js → tools/SelectionFormatToolbar.js} +3 -3
- package/dist-cjs/react/tools/SpecialBlockOption.js +11 -0
- package/dist-cjs/react/tools/SpecialBlockTool.js +129 -0
- package/dist-cjs/react/{TranscriptionControl.js → tools/TranscriptionControl.js} +71 -9
- package/dist-cjs/react/tools/blockActionToolState.js +186 -0
- package/package.json +3 -2
- package/dist/react/RichTextBody.d.ts +0 -18
- package/dist/react/RichTextBody.js +0 -66
- package/dist/react/RichTextEditor.d.ts +0 -45
- package/dist/react/RichTextEditor.js +0 -1096
- package/dist/react/RichTextRenderedBlock.d.ts +0 -4
- package/dist/react/RichTextRenderedBlock.js +0 -36
- package/dist/react/RichTextRenderer.d.ts +0 -4
- package/dist/react/RichTextRenderer.js +0 -8
- package/dist/react/RichTextStyles.js +0 -719
- package/dist/react/SpecialBlockOption.d.ts +0 -7
- package/dist/react/SpecialBlockOption.js +0 -7
- package/dist/react/SpecialBlockTool.d.ts +0 -42
- package/dist/react/SpecialBlockTool.js +0 -50
- package/dist/react/blockActionToolState.d.ts +0 -18
- package/dist/react/blockActionToolState.js +0 -53
- package/dist/react/blockActions.d.ts +0 -8
- package/dist/react/blockActions.js +0 -111
- package/dist/richText.js +0 -297
- package/dist/types.d.ts +0 -34
- package/dist-cjs/react/RichTextBody.js +0 -69
- package/dist-cjs/react/RichTextEditor.js +0 -1108
- package/dist-cjs/react/RichTextRenderedBlock.js +0 -39
- package/dist-cjs/react/RichTextRenderer.js +0 -11
- package/dist-cjs/react/RichTextStyles.js +0 -722
- package/dist-cjs/react/SpecialBlockOption.js +0 -10
- package/dist-cjs/react/SpecialBlockTool.js +0 -54
- package/dist-cjs/react/blockActionToolState.js +0 -58
- package/dist-cjs/react/blockActions.js +0 -119
- package/dist-cjs/richText.js +0 -307
- /package/dist/{types.js → core/types.js} +0 -0
- /package/dist/{writingStats.d.ts → core/writingStats.d.ts} +0 -0
- /package/dist/{writingStats.js → core/writingStats.js} +0 -0
- /package/dist/react/{RichTextDocumentSurface.d.ts → editor/RichTextDocumentSurface.d.ts} +0 -0
- /package/dist/react/{RichTextDocumentSurface.js → editor/RichTextDocumentSurface.js} +0 -0
- /package/dist/react/{UnsavedChangesDialog.d.ts → session/UnsavedChangesDialog.d.ts} +0 -0
- /package/dist/react/{RichTextStyles.d.ts → styles/RichTextStyles.d.ts} +0 -0
- /package/dist/react/{richTextBlockStyles.d.ts → styles/richTextBlockStyles.d.ts} +0 -0
- /package/dist/react/{richTextBlockStyles.js → styles/richTextBlockStyles.js} +0 -0
- /package/dist/react/{specialBlockStyles.d.ts → styles/specialBlockStyles.d.ts} +0 -0
- /package/dist/react/{specialBlockStyles.js → styles/specialBlockStyles.js} +0 -0
- /package/dist/{saveControl.d.ts → session/saveControl.d.ts} +0 -0
- /package/dist/{saveControl.js → session/saveControl.js} +0 -0
- /package/dist/{session.js → session/session.js} +0 -0
- /package/dist/{sessionRegistry.d.ts → session/sessionRegistry.d.ts} +0 -0
- /package/dist/{sessionRegistry.js → session/sessionRegistry.js} +0 -0
- /package/dist-cjs/{types.js → core/types.js} +0 -0
- /package/dist-cjs/{writingStats.js → core/writingStats.js} +0 -0
- /package/dist-cjs/react/{RichTextDocumentSurface.js → editor/RichTextDocumentSurface.js} +0 -0
- /package/dist-cjs/react/{richTextBlockStyles.js → styles/richTextBlockStyles.js} +0 -0
- /package/dist-cjs/react/{specialBlockStyles.js → styles/specialBlockStyles.js} +0 -0
- /package/dist-cjs/{saveControl.js → session/saveControl.js} +0 -0
- /package/dist-cjs/{session.js → session/session.js} +0 -0
- /package/dist-cjs/{sessionRegistry.js → session/sessionRegistry.js} +0 -0
|
@@ -0,0 +1,518 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isBlockActionTarget = isBlockActionTarget;
|
|
4
|
+
exports.reorderBlock = reorderBlock;
|
|
5
|
+
exports.deleteBlockById = deleteBlockById;
|
|
6
|
+
exports.indentBlock = indentBlock;
|
|
7
|
+
exports.outdentBlock = outdentBlock;
|
|
8
|
+
exports.setToggleCollapsed = setToggleCollapsed;
|
|
9
|
+
exports.splitTreeRowBlock = splitTreeRowBlock;
|
|
10
|
+
exports.splitTextBlock = splitTextBlock;
|
|
11
|
+
exports.insertBlocksAfterBlock = insertBlocksAfterBlock;
|
|
12
|
+
exports.replaceBlockWithBlocks = replaceBlockWithBlocks;
|
|
13
|
+
exports.insertBlocksInsideBlock = insertBlocksInsideBlock;
|
|
14
|
+
exports.getBlockActionBlocks = getBlockActionBlocks;
|
|
15
|
+
exports.convertCheckboxBlockToParagraph = convertCheckboxBlockToParagraph;
|
|
16
|
+
exports.convertTreeRowBlockToParagraph = convertTreeRowBlockToParagraph;
|
|
17
|
+
exports.blockToClipboardText = blockToClipboardText;
|
|
18
|
+
exports.blockActionToClipboardText = blockActionToClipboardText;
|
|
19
|
+
exports.getBlockDeletionFocusTarget = getBlockDeletionFocusTarget;
|
|
20
|
+
exports.getForwardDeleteFocusTarget = getForwardDeleteFocusTarget;
|
|
21
|
+
exports.getToggleContentBackspaceDeletionFocusTarget = getToggleContentBackspaceDeletionFocusTarget;
|
|
22
|
+
exports.isFirstToggleContentBlock = isFirstToggleContentBlock;
|
|
23
|
+
exports.isRootBlockAfterToggle = isRootBlockAfterToggle;
|
|
24
|
+
const blockTypes_1 = require("../../core/blockTypes");
|
|
25
|
+
const blockTree_1 = require("../../core/blockTree");
|
|
26
|
+
const richText_1 = require("../../core/richText");
|
|
27
|
+
function isBlockActionTarget(_block) {
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
function reorderBlock(blocks, draggedBlockId, targetBlockId, placement = "before") {
|
|
31
|
+
if (draggedBlockId === targetBlockId) {
|
|
32
|
+
return (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
33
|
+
}
|
|
34
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
35
|
+
const draggedPath = (0, blockTree_1.findBlockPath)(sanitizedBlocks, draggedBlockId);
|
|
36
|
+
const targetPath = (0, blockTree_1.findBlockPath)(sanitizedBlocks, targetBlockId);
|
|
37
|
+
if (!draggedPath || !targetPath || (0, blockTree_1.pathContains)(draggedPath, targetPath)) {
|
|
38
|
+
return sanitizedBlocks;
|
|
39
|
+
}
|
|
40
|
+
const removed = (0, blockTree_1.removeBlockAtPath)(sanitizedBlocks, draggedPath);
|
|
41
|
+
if (!removed) {
|
|
42
|
+
return sanitizedBlocks;
|
|
43
|
+
}
|
|
44
|
+
const remainingTargetPath = (0, blockTree_1.findBlockPath)(removed.blocks, targetBlockId);
|
|
45
|
+
if (!remainingTargetPath) {
|
|
46
|
+
return sanitizedBlocks;
|
|
47
|
+
}
|
|
48
|
+
if (placement === "inside") {
|
|
49
|
+
const target = (0, blockTree_1.getBlockAtPath)(removed.blocks, remainingTargetPath);
|
|
50
|
+
if (!(0, blockTypes_1.isNestableRichTextBlock)(target)) {
|
|
51
|
+
const targetIndex = remainingTargetPath[remainingTargetPath.length - 1];
|
|
52
|
+
if (targetIndex === undefined) {
|
|
53
|
+
return sanitizedBlocks;
|
|
54
|
+
}
|
|
55
|
+
return (0, blockTree_1.insertBlockAtPath)(removed.blocks, remainingTargetPath.slice(0, -1), targetIndex + 1, [removed.block]);
|
|
56
|
+
}
|
|
57
|
+
return (0, blockTree_1.updateBlockAtPath)(removed.blocks, remainingTargetPath, (current) => {
|
|
58
|
+
return (0, blockTypes_1.isNestableRichTextBlock)(current)
|
|
59
|
+
? (0, blockTree_1.withNestableBlockChildren)(current, [
|
|
60
|
+
...(current.children ?? []),
|
|
61
|
+
removed.block,
|
|
62
|
+
])
|
|
63
|
+
: current;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
const targetIndex = remainingTargetPath[remainingTargetPath.length - 1];
|
|
67
|
+
if (targetIndex === undefined) {
|
|
68
|
+
return sanitizedBlocks;
|
|
69
|
+
}
|
|
70
|
+
return (0, blockTree_1.insertBlockAtPath)(removed.blocks, remainingTargetPath.slice(0, -1), placement === "after" ? targetIndex + 1 : targetIndex, [removed.block]);
|
|
71
|
+
}
|
|
72
|
+
function deleteBlockById(blocks, blockId) {
|
|
73
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
74
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
75
|
+
if (!path) {
|
|
76
|
+
return sanitizedBlocks;
|
|
77
|
+
}
|
|
78
|
+
const removed = (0, blockTree_1.removeBlockAtPath)(sanitizedBlocks, path);
|
|
79
|
+
const remainingBlocks = removed?.blocks ?? sanitizedBlocks;
|
|
80
|
+
return remainingBlocks.length > 0
|
|
81
|
+
? remainingBlocks
|
|
82
|
+
: [{ id: "block-empty", markdown: "", type: "paragraph" }];
|
|
83
|
+
}
|
|
84
|
+
function indentBlock(blocks, blockId) {
|
|
85
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
86
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
87
|
+
if (!path || path.length === 0) {
|
|
88
|
+
return sanitizedBlocks;
|
|
89
|
+
}
|
|
90
|
+
const index = path[path.length - 1];
|
|
91
|
+
if (index === undefined || index <= 0) {
|
|
92
|
+
return sanitizedBlocks;
|
|
93
|
+
}
|
|
94
|
+
const block = (0, blockTree_1.getBlockAtPath)(sanitizedBlocks, path);
|
|
95
|
+
const parentPath = path.slice(0, -1);
|
|
96
|
+
const previousSiblingPath = [...parentPath, index - 1];
|
|
97
|
+
const previousSibling = (0, blockTree_1.getBlockAtPath)(sanitizedBlocks, previousSiblingPath);
|
|
98
|
+
if (!block ||
|
|
99
|
+
!(0, blockTypes_1.isNestableRichTextBlock)(block) ||
|
|
100
|
+
!(0, blockTypes_1.isNestableRichTextBlock)(previousSibling)) {
|
|
101
|
+
return sanitizedBlocks;
|
|
102
|
+
}
|
|
103
|
+
const removed = (0, blockTree_1.removeBlockAtPath)(sanitizedBlocks, path);
|
|
104
|
+
if (!removed) {
|
|
105
|
+
return sanitizedBlocks;
|
|
106
|
+
}
|
|
107
|
+
const targetPath = (0, blockTree_1.findBlockPath)(removed.blocks, previousSibling.id);
|
|
108
|
+
if (!targetPath) {
|
|
109
|
+
return sanitizedBlocks;
|
|
110
|
+
}
|
|
111
|
+
return (0, blockTree_1.updateBlockAtPath)(removed.blocks, targetPath, (target) => {
|
|
112
|
+
if (!(0, blockTypes_1.isNestableRichTextBlock)(target)) {
|
|
113
|
+
return target;
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
...target,
|
|
117
|
+
children: [...(target.children ?? []), removed.block],
|
|
118
|
+
};
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function outdentBlock(blocks, blockId) {
|
|
122
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
123
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
124
|
+
if (!path || path.length < 2) {
|
|
125
|
+
return sanitizedBlocks;
|
|
126
|
+
}
|
|
127
|
+
const block = (0, blockTree_1.getBlockAtPath)(sanitizedBlocks, path);
|
|
128
|
+
const parentPath = path.slice(0, -1);
|
|
129
|
+
const blockIndex = path[path.length - 1];
|
|
130
|
+
const siblingBlocks = (0, blockTree_1.getBlocksAtPath)(sanitizedBlocks, parentPath);
|
|
131
|
+
if (!block || blockIndex === undefined || !siblingBlocks) {
|
|
132
|
+
return sanitizedBlocks;
|
|
133
|
+
}
|
|
134
|
+
const followingSiblings = siblingBlocks.slice(blockIndex + 1);
|
|
135
|
+
const removedFollowingSiblings = followingSiblings.reduce((nextBlocks, sibling) => {
|
|
136
|
+
const siblingPath = (0, blockTree_1.findBlockPath)(nextBlocks, sibling.id);
|
|
137
|
+
const removedSibling = siblingPath
|
|
138
|
+
? (0, blockTree_1.removeBlockAtPath)(nextBlocks, siblingPath)
|
|
139
|
+
: null;
|
|
140
|
+
return removedSibling?.blocks ?? nextBlocks;
|
|
141
|
+
}, sanitizedBlocks);
|
|
142
|
+
const promotedBlock = (0, blockTree_1.withBlockChildren)(block, [
|
|
143
|
+
...((0, blockTypes_1.isNestableRichTextBlock)(block) ? (block.children ?? []) : []),
|
|
144
|
+
...followingSiblings,
|
|
145
|
+
]);
|
|
146
|
+
const removed = (0, blockTree_1.removeBlockAtPath)(removedFollowingSiblings, path);
|
|
147
|
+
if (!removed) {
|
|
148
|
+
return sanitizedBlocks;
|
|
149
|
+
}
|
|
150
|
+
const grandParentPath = parentPath.slice(0, -1);
|
|
151
|
+
const parentIndex = parentPath[parentPath.length - 1];
|
|
152
|
+
if (parentIndex === undefined) {
|
|
153
|
+
return sanitizedBlocks;
|
|
154
|
+
}
|
|
155
|
+
return (0, blockTree_1.insertBlockAtPath)(removed.blocks, grandParentPath, parentIndex + 1, [
|
|
156
|
+
promotedBlock,
|
|
157
|
+
]);
|
|
158
|
+
}
|
|
159
|
+
function setToggleCollapsed(blocks, blockId, collapsed) {
|
|
160
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
161
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
162
|
+
if (!path) {
|
|
163
|
+
return sanitizedBlocks;
|
|
164
|
+
}
|
|
165
|
+
return (0, blockTree_1.updateBlockAtPath)(sanitizedBlocks, path, (block) => {
|
|
166
|
+
return block.type === "toggle" ? { ...block, collapsed } : block;
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
function splitTreeRowBlock(blocks, blockId, split) {
|
|
170
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
171
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
172
|
+
if (!path) {
|
|
173
|
+
return sanitizedBlocks;
|
|
174
|
+
}
|
|
175
|
+
const block = (0, blockTree_1.getBlockAtPath)(sanitizedBlocks, path);
|
|
176
|
+
if (!(0, blockTypes_1.isNestableRichTextBlock)(block)) {
|
|
177
|
+
return sanitizedBlocks;
|
|
178
|
+
}
|
|
179
|
+
const nextBlock = (0, blockTree_1.withBlockChildren)(getSplitTreeRowNextBlock(block, split), block.children ?? []);
|
|
180
|
+
const updatedBlocks = (0, blockTree_1.updateBlockAtPath)(sanitizedBlocks, path, (current) => {
|
|
181
|
+
return (0, blockTypes_1.isNestableRichTextBlock)(current)
|
|
182
|
+
? (0, blockTree_1.withBlockChildren)({
|
|
183
|
+
...current,
|
|
184
|
+
markdown: split.beforeMarkdown,
|
|
185
|
+
}, [])
|
|
186
|
+
: current;
|
|
187
|
+
});
|
|
188
|
+
const blockIndex = path[path.length - 1];
|
|
189
|
+
if (blockIndex === undefined) {
|
|
190
|
+
return sanitizedBlocks;
|
|
191
|
+
}
|
|
192
|
+
return (0, blockTree_1.insertBlockAtPath)(updatedBlocks, path.slice(0, -1), blockIndex + 1, [
|
|
193
|
+
nextBlock,
|
|
194
|
+
]);
|
|
195
|
+
}
|
|
196
|
+
function splitTextBlock(blocks, blockId, split) {
|
|
197
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
198
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
199
|
+
if (!path) {
|
|
200
|
+
return sanitizedBlocks;
|
|
201
|
+
}
|
|
202
|
+
const block = (0, blockTree_1.getBlockAtPath)(sanitizedBlocks, path);
|
|
203
|
+
if (!block || !isSplittableTextBlock(block)) {
|
|
204
|
+
return sanitizedBlocks;
|
|
205
|
+
}
|
|
206
|
+
const updatedBlocks = (0, blockTree_1.updateBlockAtPath)(sanitizedBlocks, path, (current) => {
|
|
207
|
+
return current.id === blockId && "markdown" in current
|
|
208
|
+
? { ...current, markdown: split.beforeMarkdown }
|
|
209
|
+
: current;
|
|
210
|
+
});
|
|
211
|
+
const blockIndex = path[path.length - 1];
|
|
212
|
+
if (blockIndex === undefined) {
|
|
213
|
+
return sanitizedBlocks;
|
|
214
|
+
}
|
|
215
|
+
return (0, blockTree_1.insertBlockAtPath)(updatedBlocks, path.slice(0, -1), blockIndex + 1, [
|
|
216
|
+
{
|
|
217
|
+
id: split.nextBlockId,
|
|
218
|
+
markdown: split.afterMarkdown,
|
|
219
|
+
type: getSplitTextBlockNextType(block.type, split.afterMarkdown),
|
|
220
|
+
},
|
|
221
|
+
]);
|
|
222
|
+
}
|
|
223
|
+
function getSplitTextBlockNextType(blockType, afterMarkdown) {
|
|
224
|
+
return blockType === "heading" && afterMarkdown.trim().length === 0
|
|
225
|
+
? "paragraph"
|
|
226
|
+
: blockType;
|
|
227
|
+
}
|
|
228
|
+
function isSplittableTextBlock(block) {
|
|
229
|
+
return (block?.type === "paragraph" ||
|
|
230
|
+
block?.type === "heading" ||
|
|
231
|
+
block?.type === "quote");
|
|
232
|
+
}
|
|
233
|
+
function insertBlocksAfterBlock(blocks, blockId, insertedBlocks) {
|
|
234
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
235
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
236
|
+
if (!path || insertedBlocks.length === 0) {
|
|
237
|
+
return sanitizedBlocks;
|
|
238
|
+
}
|
|
239
|
+
const blockIndex = path[path.length - 1];
|
|
240
|
+
if (blockIndex === undefined) {
|
|
241
|
+
return sanitizedBlocks;
|
|
242
|
+
}
|
|
243
|
+
return (0, blockTree_1.insertBlockAtPath)(sanitizedBlocks, path.slice(0, -1), blockIndex + 1, (0, richText_1.sanitizeRichTextBlocks)(insertedBlocks));
|
|
244
|
+
}
|
|
245
|
+
function replaceBlockWithBlocks(blocks, blockId, replacementBlocks) {
|
|
246
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
247
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
248
|
+
if (!path || replacementBlocks.length === 0) {
|
|
249
|
+
return sanitizedBlocks;
|
|
250
|
+
}
|
|
251
|
+
const blockIndex = path[path.length - 1];
|
|
252
|
+
if (blockIndex === undefined) {
|
|
253
|
+
return sanitizedBlocks;
|
|
254
|
+
}
|
|
255
|
+
const removed = (0, blockTree_1.removeBlockAtPath)(sanitizedBlocks, path);
|
|
256
|
+
if (!removed) {
|
|
257
|
+
return sanitizedBlocks;
|
|
258
|
+
}
|
|
259
|
+
return (0, blockTree_1.insertBlockAtPath)(removed.blocks, path.slice(0, -1), blockIndex, (0, richText_1.sanitizeRichTextBlocks)(replacementBlocks));
|
|
260
|
+
}
|
|
261
|
+
function insertBlocksInsideBlock(blocks, blockId, insertedBlocks) {
|
|
262
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
263
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
264
|
+
if (!path || insertedBlocks.length === 0) {
|
|
265
|
+
return sanitizedBlocks;
|
|
266
|
+
}
|
|
267
|
+
return (0, blockTree_1.updateBlockAtPath)(sanitizedBlocks, path, (block) => {
|
|
268
|
+
return (0, blockTypes_1.isNestableRichTextBlock)(block)
|
|
269
|
+
? (0, blockTree_1.withNestableBlockChildren)(block, [
|
|
270
|
+
...(block.children ?? []),
|
|
271
|
+
...(0, richText_1.sanitizeRichTextBlocks)(insertedBlocks),
|
|
272
|
+
])
|
|
273
|
+
: block;
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
function getBlockActionBlocks(blocks, blockId) {
|
|
277
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
278
|
+
const range = getActionBlockRange(sanitizedBlocks, blockId);
|
|
279
|
+
if (range) {
|
|
280
|
+
return sanitizedBlocks.slice(range.start, range.end);
|
|
281
|
+
}
|
|
282
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
283
|
+
const block = path ? (0, blockTree_1.getBlockAtPath)(sanitizedBlocks, path) : null;
|
|
284
|
+
return block ? [block] : [];
|
|
285
|
+
}
|
|
286
|
+
function convertCheckboxBlockToParagraph(blocks, blockId) {
|
|
287
|
+
return convertTreeRowBlockToParagraph(blocks, blockId, (block) => block.markdown, { convertNonEmpty: true });
|
|
288
|
+
}
|
|
289
|
+
function convertTreeRowBlockToParagraph(blocks, blockId, markdown, options = {}) {
|
|
290
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
291
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
292
|
+
if (!path) {
|
|
293
|
+
return sanitizedBlocks;
|
|
294
|
+
}
|
|
295
|
+
return (0, blockTree_1.updateBlockAtPath)(sanitizedBlocks, path, (block) => {
|
|
296
|
+
if (!(0, blockTypes_1.isNestableRichTextBlock)(block)) {
|
|
297
|
+
return block;
|
|
298
|
+
}
|
|
299
|
+
if (!options.convertNonEmpty && block.markdown.trim().length > 0) {
|
|
300
|
+
return block;
|
|
301
|
+
}
|
|
302
|
+
return {
|
|
303
|
+
id: block.id,
|
|
304
|
+
markdown: typeof markdown === "function" ? markdown(block) : markdown,
|
|
305
|
+
type: "paragraph",
|
|
306
|
+
};
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
function blockToClipboardText(block) {
|
|
310
|
+
return blockToClipboardTextAtDepth(block, 0);
|
|
311
|
+
}
|
|
312
|
+
function blockToClipboardTextAtDepth(block, depth) {
|
|
313
|
+
const indent = " ".repeat(depth);
|
|
314
|
+
if (block.type === "bullet") {
|
|
315
|
+
const text = (0, richText_1.richTextBlocksToPlainText)([{ ...block, children: [] }]);
|
|
316
|
+
const line = text ? `${indent}- ${text}` : "";
|
|
317
|
+
return [
|
|
318
|
+
line,
|
|
319
|
+
...(block.children ?? []).map((child) => blockToClipboardTextAtDepth(child, depth + 1)),
|
|
320
|
+
]
|
|
321
|
+
.filter((text) => text.trim())
|
|
322
|
+
.join("\n");
|
|
323
|
+
}
|
|
324
|
+
if (block.type === "ordered") {
|
|
325
|
+
const text = (0, richText_1.richTextBlocksToPlainText)([{ ...block, children: [] }]);
|
|
326
|
+
const line = text ? `${indent}1. ${text}` : "";
|
|
327
|
+
return [
|
|
328
|
+
line,
|
|
329
|
+
...(block.children ?? []).map((child) => blockToClipboardTextAtDepth(child, depth + 1)),
|
|
330
|
+
]
|
|
331
|
+
.filter((text) => text.trim())
|
|
332
|
+
.join("\n");
|
|
333
|
+
}
|
|
334
|
+
if (block.type === "checkbox") {
|
|
335
|
+
const text = (0, richText_1.richTextBlocksToPlainText)([{ ...block, children: [] }]);
|
|
336
|
+
const line = text ? `${indent}[${block.checked ? "x" : " "}] ${text}` : "";
|
|
337
|
+
return [
|
|
338
|
+
line,
|
|
339
|
+
...(block.children ?? []).map((child) => blockToClipboardTextAtDepth(child, depth + 1)),
|
|
340
|
+
]
|
|
341
|
+
.filter((value) => value.trim())
|
|
342
|
+
.join("\n");
|
|
343
|
+
}
|
|
344
|
+
if (block.type === "toggle") {
|
|
345
|
+
const text = (0, richText_1.richTextBlocksToPlainText)([{ ...block, children: [] }]);
|
|
346
|
+
const line = text ? `${indent}> ${text}` : "";
|
|
347
|
+
return [
|
|
348
|
+
line,
|
|
349
|
+
...block.children.map((child) => blockToClipboardTextAtDepth(child, depth + 1)),
|
|
350
|
+
]
|
|
351
|
+
.filter((value) => value.trim())
|
|
352
|
+
.join("\n");
|
|
353
|
+
}
|
|
354
|
+
if (block.type === "image") {
|
|
355
|
+
return (0, richText_1.richTextBlocksToPlainText)([{ ...block, uploadProgress: 0 }]);
|
|
356
|
+
}
|
|
357
|
+
return (0, richText_1.richTextBlocksToPlainText)([block]);
|
|
358
|
+
}
|
|
359
|
+
function blockActionToClipboardText(blocks, blockId) {
|
|
360
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
361
|
+
const range = getActionBlockRange(sanitizedBlocks, blockId);
|
|
362
|
+
if (range) {
|
|
363
|
+
return sanitizedBlocks
|
|
364
|
+
.slice(range.start, range.end)
|
|
365
|
+
.map(blockToClipboardText)
|
|
366
|
+
.filter((text) => text.trim())
|
|
367
|
+
.join("\n");
|
|
368
|
+
}
|
|
369
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
370
|
+
const block = path ? (0, blockTree_1.getBlockAtPath)(sanitizedBlocks, path) : null;
|
|
371
|
+
return block ? blockToClipboardText(block) : "";
|
|
372
|
+
}
|
|
373
|
+
function getBlockDeletionFocusTarget(blocks, blockId) {
|
|
374
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
375
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
376
|
+
if (!path) {
|
|
377
|
+
return undefined;
|
|
378
|
+
}
|
|
379
|
+
const index = path[path.length - 1];
|
|
380
|
+
const parentPath = path.slice(0, -1);
|
|
381
|
+
const siblings = (0, blockTree_1.getBlocksAtPath)(sanitizedBlocks, parentPath);
|
|
382
|
+
if (index === undefined || !siblings) {
|
|
383
|
+
return undefined;
|
|
384
|
+
}
|
|
385
|
+
const previousBlockId = siblings[index - 1]?.id;
|
|
386
|
+
if (previousBlockId) {
|
|
387
|
+
return { blockId: previousBlockId, position: "end" };
|
|
388
|
+
}
|
|
389
|
+
const nextBlockId = siblings[index + 1]?.id;
|
|
390
|
+
if (nextBlockId) {
|
|
391
|
+
return { blockId: nextBlockId, position: "start" };
|
|
392
|
+
}
|
|
393
|
+
if (parentPath.length > 0) {
|
|
394
|
+
const parent = (0, blockTree_1.getBlockAtPath)(sanitizedBlocks, parentPath);
|
|
395
|
+
if (parent) {
|
|
396
|
+
return { blockId: parent.id, position: "end" };
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return {
|
|
400
|
+
blockId: "block-empty",
|
|
401
|
+
position: "start",
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
function getForwardDeleteFocusTarget(blocks, blockId) {
|
|
405
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
406
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
407
|
+
if (!path) {
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
410
|
+
for (let depth = path.length - 1; depth >= 0; depth -= 1) {
|
|
411
|
+
const parentPath = path.slice(0, depth);
|
|
412
|
+
const index = path[depth];
|
|
413
|
+
const siblings = (0, blockTree_1.getBlocksAtPath)(sanitizedBlocks, parentPath);
|
|
414
|
+
const nextBlock = index === undefined ? undefined : siblings?.[index + 1];
|
|
415
|
+
if (nextBlock) {
|
|
416
|
+
return { blockId: nextBlock.id, position: "start" };
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
return undefined;
|
|
420
|
+
}
|
|
421
|
+
function getToggleContentBackspaceDeletionFocusTarget(blocks, blockId) {
|
|
422
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
423
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
424
|
+
if (!path) {
|
|
425
|
+
return undefined;
|
|
426
|
+
}
|
|
427
|
+
const index = path[path.length - 1];
|
|
428
|
+
const parentPath = path.slice(0, -1);
|
|
429
|
+
const parent = (0, blockTree_1.getBlockAtPath)(sanitizedBlocks, parentPath);
|
|
430
|
+
const siblings = (0, blockTree_1.getBlocksAtPath)(sanitizedBlocks, parentPath);
|
|
431
|
+
if (index === undefined ||
|
|
432
|
+
index <= 0 ||
|
|
433
|
+
parent?.type !== "toggle" ||
|
|
434
|
+
!siblings) {
|
|
435
|
+
return undefined;
|
|
436
|
+
}
|
|
437
|
+
const previousSibling = siblings[index - 1];
|
|
438
|
+
return previousSibling
|
|
439
|
+
? { blockId: previousSibling.id, position: "end" }
|
|
440
|
+
: undefined;
|
|
441
|
+
}
|
|
442
|
+
function isFirstToggleContentBlock(blocks, blockId) {
|
|
443
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
444
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
445
|
+
if (!path) {
|
|
446
|
+
return false;
|
|
447
|
+
}
|
|
448
|
+
const index = path[path.length - 1];
|
|
449
|
+
const parent = (0, blockTree_1.getBlockAtPath)(sanitizedBlocks, path.slice(0, -1));
|
|
450
|
+
return index === 0 && parent?.type === "toggle";
|
|
451
|
+
}
|
|
452
|
+
function isRootBlockAfterToggle(blocks, blockId) {
|
|
453
|
+
const sanitizedBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
454
|
+
const path = (0, blockTree_1.findBlockPath)(sanitizedBlocks, blockId);
|
|
455
|
+
if (!path) {
|
|
456
|
+
return false;
|
|
457
|
+
}
|
|
458
|
+
const index = path[path.length - 1];
|
|
459
|
+
const parentPath = path.slice(0, -1);
|
|
460
|
+
const siblings = (0, blockTree_1.getBlocksAtPath)(sanitizedBlocks, parentPath);
|
|
461
|
+
if (parentPath.length !== 0 ||
|
|
462
|
+
index === undefined ||
|
|
463
|
+
index <= 0 ||
|
|
464
|
+
!siblings) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
return siblings[index - 1]?.type === "toggle";
|
|
468
|
+
}
|
|
469
|
+
function getSingleBlockRange(blocks, blockId) {
|
|
470
|
+
const index = blocks.findIndex((block) => {
|
|
471
|
+
return block.id === blockId;
|
|
472
|
+
});
|
|
473
|
+
return index === -1 ? null : { end: index + 1, start: index };
|
|
474
|
+
}
|
|
475
|
+
function getActionBlockRange(blocks, blockId) {
|
|
476
|
+
const index = blocks.findIndex((block) => {
|
|
477
|
+
return block.id === blockId;
|
|
478
|
+
});
|
|
479
|
+
if (index === -1) {
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
if (blocks[index]?.type !== "checkbox") {
|
|
483
|
+
return { end: index + 1, start: index };
|
|
484
|
+
}
|
|
485
|
+
let start = index;
|
|
486
|
+
let end = index + 1;
|
|
487
|
+
while (start > 0 && blocks[start - 1]?.type === "checkbox") {
|
|
488
|
+
start -= 1;
|
|
489
|
+
}
|
|
490
|
+
while (end < blocks.length && blocks[end]?.type === "checkbox") {
|
|
491
|
+
end += 1;
|
|
492
|
+
}
|
|
493
|
+
return { end, start };
|
|
494
|
+
}
|
|
495
|
+
function getSplitTreeRowNextBlock(block, split) {
|
|
496
|
+
if (block.type === "checkbox") {
|
|
497
|
+
return {
|
|
498
|
+
checked: false,
|
|
499
|
+
id: split.nextBlockId,
|
|
500
|
+
markdown: split.afterMarkdown,
|
|
501
|
+
type: "checkbox",
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
if (block.type === "toggle") {
|
|
505
|
+
return {
|
|
506
|
+
children: [],
|
|
507
|
+
collapsed: false,
|
|
508
|
+
id: split.nextBlockId,
|
|
509
|
+
markdown: split.afterMarkdown,
|
|
510
|
+
type: "toggle",
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
return {
|
|
514
|
+
id: split.nextBlockId,
|
|
515
|
+
markdown: split.afterMarkdown,
|
|
516
|
+
type: block.type,
|
|
517
|
+
};
|
|
518
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createRichTextHistory = createRichTextHistory;
|
|
4
|
+
exports.commitRichTextHistory = commitRichTextHistory;
|
|
5
|
+
exports.canUndoRichTextHistory = canUndoRichTextHistory;
|
|
6
|
+
exports.canRedoRichTextHistory = canRedoRichTextHistory;
|
|
7
|
+
exports.undoRichTextHistory = undoRichTextHistory;
|
|
8
|
+
exports.redoRichTextHistory = redoRichTextHistory;
|
|
9
|
+
exports.createRichTextHistorySnapshot = createRichTextHistorySnapshot;
|
|
10
|
+
const session_1 = require("../../session/session");
|
|
11
|
+
const DEFAULT_HISTORY_DEPTH = 100;
|
|
12
|
+
const TYPING_COALESCE_MS = 1000;
|
|
13
|
+
function createRichTextHistory({ document, maxDepth = DEFAULT_HISTORY_DEPTH, selection = null, timestamp = Date.now(), }) {
|
|
14
|
+
return {
|
|
15
|
+
future: [],
|
|
16
|
+
maxDepth,
|
|
17
|
+
past: [],
|
|
18
|
+
present: {
|
|
19
|
+
document,
|
|
20
|
+
label: "typing",
|
|
21
|
+
selection,
|
|
22
|
+
timestamp,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function commitRichTextHistory(history, commit) {
|
|
27
|
+
const timestamp = commit.timestamp ?? Date.now();
|
|
28
|
+
const nextEntry = {
|
|
29
|
+
document: commit.document,
|
|
30
|
+
label: commit.label,
|
|
31
|
+
metadata: commit.metadata,
|
|
32
|
+
selection: commit.selection,
|
|
33
|
+
timestamp,
|
|
34
|
+
};
|
|
35
|
+
if (areDocumentsEqual(history.present.document, nextEntry.document)) {
|
|
36
|
+
return history;
|
|
37
|
+
}
|
|
38
|
+
if (shouldCoalesceHistoryEntry(history.present, nextEntry)) {
|
|
39
|
+
return {
|
|
40
|
+
...history,
|
|
41
|
+
future: [],
|
|
42
|
+
present: nextEntry,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
...history,
|
|
47
|
+
future: [],
|
|
48
|
+
past: [...history.past, history.present].slice(-history.maxDepth),
|
|
49
|
+
present: nextEntry,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function canUndoRichTextHistory(history) {
|
|
53
|
+
return history.past.length > 0;
|
|
54
|
+
}
|
|
55
|
+
function canRedoRichTextHistory(history) {
|
|
56
|
+
return history.future.length > 0;
|
|
57
|
+
}
|
|
58
|
+
function undoRichTextHistory(history) {
|
|
59
|
+
const previous = history.past[history.past.length - 1];
|
|
60
|
+
if (!previous) {
|
|
61
|
+
return { entry: history.present, history };
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
entry: previous,
|
|
65
|
+
history: {
|
|
66
|
+
...history,
|
|
67
|
+
future: [history.present, ...history.future],
|
|
68
|
+
past: history.past.slice(0, -1),
|
|
69
|
+
present: previous,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function redoRichTextHistory(history) {
|
|
74
|
+
const next = history.future[0];
|
|
75
|
+
if (!next) {
|
|
76
|
+
return { entry: history.present, history };
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
entry: next,
|
|
80
|
+
history: {
|
|
81
|
+
...history,
|
|
82
|
+
future: history.future.slice(1),
|
|
83
|
+
past: [...history.past, history.present].slice(-history.maxDepth),
|
|
84
|
+
present: next,
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
function createRichTextHistorySnapshot(history) {
|
|
89
|
+
const entries = [...history.past, history.present, ...history.future].map((entry, index) => ({
|
|
90
|
+
id: `history-${index}-${entry.timestamp}`,
|
|
91
|
+
label: entry.label,
|
|
92
|
+
...(entry.metadata ? { metadata: entry.metadata } : {}),
|
|
93
|
+
timestamp: entry.timestamp,
|
|
94
|
+
}));
|
|
95
|
+
return {
|
|
96
|
+
canRedo: canRedoRichTextHistory(history),
|
|
97
|
+
canUndo: canUndoRichTextHistory(history),
|
|
98
|
+
currentIndex: history.past.length,
|
|
99
|
+
entries,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function shouldCoalesceHistoryEntry(previous, next) {
|
|
103
|
+
if (previous.label !== next.label) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
if (next.label !== "typing" && next.label !== "title") {
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
if (next.timestamp - previous.timestamp > TYPING_COALESCE_MS) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
if (next.label === "title") {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
return (previous.selection?.blockId !== undefined &&
|
|
116
|
+
previous.selection.blockId === next.selection?.blockId);
|
|
117
|
+
}
|
|
118
|
+
function areDocumentsEqual(left, right) {
|
|
119
|
+
return (0, session_1.canonicalSerialize)(left) === (0, session_1.canonicalSerialize)(right);
|
|
120
|
+
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.isCursorOnFirstLine = isCursorOnFirstLine;
|
|
4
4
|
exports.isSelectAllShortcut = isSelectAllShortcut;
|
|
5
5
|
exports.getEditorKeyboardShortcut = getEditorKeyboardShortcut;
|
|
6
|
+
exports.getEditorHistoryShortcut = getEditorHistoryShortcut;
|
|
6
7
|
exports.getCodeBlockSelectionTarget = getCodeBlockSelectionTarget;
|
|
7
8
|
function isCursorOnFirstLine(value, selectionStart) {
|
|
8
9
|
return !value.slice(0, selectionStart).includes("\n");
|
|
@@ -29,6 +30,22 @@ function getEditorKeyboardShortcut(event) {
|
|
|
29
30
|
}
|
|
30
31
|
return null;
|
|
31
32
|
}
|
|
33
|
+
function getEditorHistoryShortcut(event) {
|
|
34
|
+
if (!(event.ctrlKey || event.metaKey) || event.altKey) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const key = event.key.toLowerCase();
|
|
38
|
+
if (key === "z" && event.shiftKey) {
|
|
39
|
+
return "redo";
|
|
40
|
+
}
|
|
41
|
+
if (key === "z" && !event.shiftKey) {
|
|
42
|
+
return "undo";
|
|
43
|
+
}
|
|
44
|
+
if (key === "y" && !event.shiftKey) {
|
|
45
|
+
return "redo";
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
32
49
|
function getCodeBlockSelectionTarget(root, selection) {
|
|
33
50
|
if (!selection || selection.rangeCount === 0) {
|
|
34
51
|
return null;
|