@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.
Files changed (151) hide show
  1. package/BEHAVIOR.md +396 -0
  2. package/CHANGELOG.md +22 -0
  3. package/README.md +25 -6
  4. package/dist/core/blockTree.d.ts +14 -0
  5. package/dist/core/blockTree.js +126 -0
  6. package/dist/core/blockTypes.d.ts +6 -0
  7. package/dist/core/blockTypes.js +5 -0
  8. package/dist/core/exportImport.d.ts +59 -0
  9. package/dist/core/exportImport.js +51 -0
  10. package/dist/core/features.d.ts +59 -0
  11. package/dist/core/features.js +57 -0
  12. package/dist/core/imageBlockDiagnostics.d.ts +4 -0
  13. package/dist/core/imageBlockDiagnostics.js +19 -0
  14. package/dist/core/proFeatures.d.ts +60 -0
  15. package/dist/core/proFeatures.js +64 -0
  16. package/dist/{richText.d.ts → core/richText.d.ts} +2 -0
  17. package/dist/core/richText.js +566 -0
  18. package/dist/core/types.d.ts +78 -0
  19. package/dist/index.d.ts +14 -8
  20. package/dist/index.js +8 -5
  21. package/dist/react/editor/RichTextBody.d.ts +28 -0
  22. package/dist/react/editor/RichTextBody.js +131 -0
  23. package/dist/react/editor/RichTextEditor.d.ts +138 -0
  24. package/dist/react/editor/RichTextEditor.js +2925 -0
  25. package/dist/react/editor/RichTextRenderedBlock.d.ts +20 -0
  26. package/dist/react/editor/RichTextRenderedBlock.js +162 -0
  27. package/dist/react/editor/RichTextRenderer.d.ts +13 -0
  28. package/dist/react/editor/RichTextRenderer.js +16 -0
  29. package/dist/react/{RichTextTitleInput.d.ts → editor/RichTextTitleInput.d.ts} +11 -1
  30. package/dist/react/{RichTextTitleInput.js → editor/RichTextTitleInput.js} +17 -2
  31. package/dist/react/editor/blockActions.d.ts +48 -0
  32. package/dist/react/editor/blockActions.js +495 -0
  33. package/dist/react/editor/editorHistory.d.ts +55 -0
  34. package/dist/react/editor/editorHistory.js +111 -0
  35. package/dist/react/{editorNavigation.d.ts → editor/editorNavigation.d.ts} +2 -0
  36. package/dist/react/{editorNavigation.js → editor/editorNavigation.js} +16 -0
  37. package/dist/react/editor/editorOperations.d.ts +10 -0
  38. package/dist/react/editor/editorOperations.js +3 -0
  39. package/dist/react/editor/editorSelection.d.ts +3 -0
  40. package/dist/react/editor/editorSelection.js +215 -0
  41. package/dist/react/{editorShortcuts.d.ts → editor/editorShortcuts.d.ts} +10 -0
  42. package/dist/react/{editorShortcuts.js → editor/editorShortcuts.js} +17 -1
  43. package/dist/react/{RichTextIcons.d.ts → icons/RichTextIcons.d.ts} +3 -0
  44. package/dist/react/{RichTextIcons.js → icons/RichTextIcons.js} +9 -0
  45. package/dist/react/index.d.ts +12 -9
  46. package/dist/react/index.js +7 -6
  47. package/dist/react/{EditorSessionProvider.d.ts → session/EditorSessionProvider.d.ts} +2 -2
  48. package/dist/react/{EditorSessionProvider.js → session/EditorSessionProvider.js} +3 -3
  49. package/dist/react/{UnsavedChangesDialog.js → session/UnsavedChangesDialog.js} +1 -1
  50. package/dist/react/styles/RichTextStyles.js +1362 -0
  51. package/dist/react/{BlockActionTool.d.ts → tools/BlockActionTool.d.ts} +1 -1
  52. package/dist/react/{BlockActionTool.js → tools/BlockActionTool.js} +6 -2
  53. package/dist/react/tools/LinkCreationInput.d.ts +9 -0
  54. package/dist/react/tools/LinkCreationInput.js +38 -0
  55. package/dist/react/{SelectionFormatToolbar.d.ts → tools/SelectionFormatToolbar.d.ts} +3 -2
  56. package/dist/react/{SelectionFormatToolbar.js → tools/SelectionFormatToolbar.js} +3 -3
  57. package/dist/react/tools/SpecialBlockOption.d.ts +9 -0
  58. package/dist/react/tools/SpecialBlockOption.js +8 -0
  59. package/dist/react/tools/SpecialBlockTool.d.ts +91 -0
  60. package/dist/react/tools/SpecialBlockTool.js +125 -0
  61. package/dist/react/{TranscriptionControl.d.ts → tools/TranscriptionControl.d.ts} +9 -0
  62. package/dist/react/{TranscriptionControl.js → tools/TranscriptionControl.js} +70 -9
  63. package/dist/react/tools/blockActionToolState.d.ts +41 -0
  64. package/dist/react/tools/blockActionToolState.js +177 -0
  65. package/dist/react/tools/imageBlockDiagnostics.d.ts +2 -0
  66. package/dist/react/tools/imageBlockDiagnostics.js +12 -0
  67. package/dist/{session.d.ts → session/session.d.ts} +1 -1
  68. package/dist-cjs/core/blockTree.js +137 -0
  69. package/dist-cjs/core/blockTypes.js +9 -0
  70. package/dist-cjs/core/exportImport.js +56 -0
  71. package/dist-cjs/core/features.js +62 -0
  72. package/dist-cjs/core/proFeatures.js +70 -0
  73. package/dist-cjs/core/richText.js +578 -0
  74. package/dist-cjs/index.js +22 -6
  75. package/dist-cjs/react/editor/RichTextBody.js +134 -0
  76. package/dist-cjs/react/editor/RichTextEditor.js +2956 -0
  77. package/dist-cjs/react/editor/RichTextRenderedBlock.js +166 -0
  78. package/dist-cjs/react/editor/RichTextRenderer.js +20 -0
  79. package/dist-cjs/react/{RichTextTitleInput.js → editor/RichTextTitleInput.js} +18 -2
  80. package/dist-cjs/react/editor/blockActions.js +518 -0
  81. package/dist-cjs/react/editor/editorHistory.js +120 -0
  82. package/dist-cjs/react/{editorNavigation.js → editor/editorNavigation.js} +17 -0
  83. package/dist-cjs/react/editor/editorOperations.js +6 -0
  84. package/dist-cjs/react/editor/editorSelection.js +219 -0
  85. package/dist-cjs/react/{editorShortcuts.js → editor/editorShortcuts.js} +17 -1
  86. package/dist-cjs/react/{RichTextIcons.js → icons/RichTextIcons.js} +12 -0
  87. package/dist-cjs/react/index.js +9 -7
  88. package/dist-cjs/react/{EditorSessionProvider.js → session/EditorSessionProvider.js} +3 -3
  89. package/dist-cjs/react/{UnsavedChangesDialog.js → session/UnsavedChangesDialog.js} +1 -1
  90. package/dist-cjs/react/styles/RichTextStyles.js +1365 -0
  91. package/dist-cjs/react/{BlockActionTool.js → tools/BlockActionTool.js} +6 -2
  92. package/dist-cjs/react/tools/LinkCreationInput.js +41 -0
  93. package/dist-cjs/react/{SelectionFormatToolbar.js → tools/SelectionFormatToolbar.js} +3 -3
  94. package/dist-cjs/react/tools/SpecialBlockOption.js +11 -0
  95. package/dist-cjs/react/tools/SpecialBlockTool.js +129 -0
  96. package/dist-cjs/react/{TranscriptionControl.js → tools/TranscriptionControl.js} +71 -9
  97. package/dist-cjs/react/tools/blockActionToolState.js +186 -0
  98. package/package.json +3 -2
  99. package/dist/react/RichTextBody.d.ts +0 -18
  100. package/dist/react/RichTextBody.js +0 -66
  101. package/dist/react/RichTextEditor.d.ts +0 -45
  102. package/dist/react/RichTextEditor.js +0 -1096
  103. package/dist/react/RichTextRenderedBlock.d.ts +0 -4
  104. package/dist/react/RichTextRenderedBlock.js +0 -36
  105. package/dist/react/RichTextRenderer.d.ts +0 -4
  106. package/dist/react/RichTextRenderer.js +0 -8
  107. package/dist/react/RichTextStyles.js +0 -719
  108. package/dist/react/SpecialBlockOption.d.ts +0 -7
  109. package/dist/react/SpecialBlockOption.js +0 -7
  110. package/dist/react/SpecialBlockTool.d.ts +0 -42
  111. package/dist/react/SpecialBlockTool.js +0 -50
  112. package/dist/react/blockActionToolState.d.ts +0 -18
  113. package/dist/react/blockActionToolState.js +0 -53
  114. package/dist/react/blockActions.d.ts +0 -8
  115. package/dist/react/blockActions.js +0 -111
  116. package/dist/richText.js +0 -297
  117. package/dist/types.d.ts +0 -34
  118. package/dist-cjs/react/RichTextBody.js +0 -69
  119. package/dist-cjs/react/RichTextEditor.js +0 -1108
  120. package/dist-cjs/react/RichTextRenderedBlock.js +0 -39
  121. package/dist-cjs/react/RichTextRenderer.js +0 -11
  122. package/dist-cjs/react/RichTextStyles.js +0 -722
  123. package/dist-cjs/react/SpecialBlockOption.js +0 -10
  124. package/dist-cjs/react/SpecialBlockTool.js +0 -54
  125. package/dist-cjs/react/blockActionToolState.js +0 -58
  126. package/dist-cjs/react/blockActions.js +0 -119
  127. package/dist-cjs/richText.js +0 -307
  128. /package/dist/{types.js → core/types.js} +0 -0
  129. /package/dist/{writingStats.d.ts → core/writingStats.d.ts} +0 -0
  130. /package/dist/{writingStats.js → core/writingStats.js} +0 -0
  131. /package/dist/react/{RichTextDocumentSurface.d.ts → editor/RichTextDocumentSurface.d.ts} +0 -0
  132. /package/dist/react/{RichTextDocumentSurface.js → editor/RichTextDocumentSurface.js} +0 -0
  133. /package/dist/react/{UnsavedChangesDialog.d.ts → session/UnsavedChangesDialog.d.ts} +0 -0
  134. /package/dist/react/{RichTextStyles.d.ts → styles/RichTextStyles.d.ts} +0 -0
  135. /package/dist/react/{richTextBlockStyles.d.ts → styles/richTextBlockStyles.d.ts} +0 -0
  136. /package/dist/react/{richTextBlockStyles.js → styles/richTextBlockStyles.js} +0 -0
  137. /package/dist/react/{specialBlockStyles.d.ts → styles/specialBlockStyles.d.ts} +0 -0
  138. /package/dist/react/{specialBlockStyles.js → styles/specialBlockStyles.js} +0 -0
  139. /package/dist/{saveControl.d.ts → session/saveControl.d.ts} +0 -0
  140. /package/dist/{saveControl.js → session/saveControl.js} +0 -0
  141. /package/dist/{session.js → session/session.js} +0 -0
  142. /package/dist/{sessionRegistry.d.ts → session/sessionRegistry.d.ts} +0 -0
  143. /package/dist/{sessionRegistry.js → session/sessionRegistry.js} +0 -0
  144. /package/dist-cjs/{types.js → core/types.js} +0 -0
  145. /package/dist-cjs/{writingStats.js → core/writingStats.js} +0 -0
  146. /package/dist-cjs/react/{RichTextDocumentSurface.js → editor/RichTextDocumentSurface.js} +0 -0
  147. /package/dist-cjs/react/{richTextBlockStyles.js → styles/richTextBlockStyles.js} +0 -0
  148. /package/dist-cjs/react/{specialBlockStyles.js → styles/specialBlockStyles.js} +0 -0
  149. /package/dist-cjs/{saveControl.js → session/saveControl.js} +0 -0
  150. /package/dist-cjs/{session.js → session/session.js} +0 -0
  151. /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;
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createEditorOperation = createEditorOperation;
4
+ function createEditorOperation(operation) {
5
+ return operation;
6
+ }