@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,10 @@
|
|
|
1
|
+
import type { RichTextBlock, RichTextSelectionSnapshot } from "../../core/types";
|
|
2
|
+
export type { RichTextSelectionSnapshot } from "../../core/types";
|
|
3
|
+
export type RichTextEditorOperationKind = "delete" | "indent" | "insert" | "outdent" | "reorder" | "toggle" | "update";
|
|
4
|
+
export type RichTextEditorOperation = {
|
|
5
|
+
kind: RichTextEditorOperationKind;
|
|
6
|
+
nextContentBlocks: RichTextBlock[];
|
|
7
|
+
previousContentBlocks: RichTextBlock[];
|
|
8
|
+
selection: RichTextSelectionSnapshot;
|
|
9
|
+
};
|
|
10
|
+
export declare function createEditorOperation(operation: RichTextEditorOperation): RichTextEditorOperation;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { RichTextSelectionSnapshot } from "../../core/types";
|
|
2
|
+
export declare function captureRichTextSelection(body: HTMLElement | null, selection?: Selection | null): RichTextSelectionSnapshot | null;
|
|
3
|
+
export declare function restoreRichTextSelection(body: HTMLElement, snapshot: RichTextSelectionSnapshot | null): boolean;
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
export function captureRichTextSelection(body, selection = getCurrentSelection()) {
|
|
2
|
+
if (!body || !selection || selection.rangeCount === 0) {
|
|
3
|
+
return null;
|
|
4
|
+
}
|
|
5
|
+
const range = selection.getRangeAt(0);
|
|
6
|
+
if (!body.contains(range.startContainer)) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
const activeBlock = getSelectionBlock(range.startContainer, body);
|
|
10
|
+
const blockId = activeBlock?.getAttribute("data-block-id");
|
|
11
|
+
if (!activeBlock || !blockId) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
const selectionRoot = getSelectionTextRoot(activeBlock, range.startContainer);
|
|
15
|
+
const offset = getTextOffsetWithin(selectionRoot, range);
|
|
16
|
+
return {
|
|
17
|
+
affinity: offset === 0 ? "start" : "end",
|
|
18
|
+
blockId,
|
|
19
|
+
offset,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export function restoreRichTextSelection(body, snapshot) {
|
|
23
|
+
if (!snapshot) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
const block = body.querySelector(`[data-block-id="${cssEscape(snapshot.blockId)}"]`);
|
|
27
|
+
if (!block) {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
const selectionRoot = getSelectionTextRoot(block, block);
|
|
31
|
+
const target = findFocusTargetAtVisibleTextOffset(selectionRoot, snapshot.offset);
|
|
32
|
+
if (!target) {
|
|
33
|
+
focusNodeEnd(selectionRoot);
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
const range = getOwnerDocument(body).createRange();
|
|
37
|
+
range.setStart(target.node, target.offset);
|
|
38
|
+
range.collapse(true);
|
|
39
|
+
const selection = getOwnerWindow(body).getSelection();
|
|
40
|
+
selection?.removeAllRanges();
|
|
41
|
+
selection?.addRange(range);
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
function getCurrentSelection() {
|
|
45
|
+
return typeof window === "undefined" ? null : window.getSelection();
|
|
46
|
+
}
|
|
47
|
+
function getSelectionBlock(node, body) {
|
|
48
|
+
const element = node.nodeType === 3
|
|
49
|
+
? node.parentElement
|
|
50
|
+
: node.nodeType === 1
|
|
51
|
+
? node
|
|
52
|
+
: null;
|
|
53
|
+
const block = element?.closest("[data-block-id]");
|
|
54
|
+
return block && body.contains(block) ? block : null;
|
|
55
|
+
}
|
|
56
|
+
function getSelectionTextRoot(block, node) {
|
|
57
|
+
const nodeElement = node.nodeType === 3
|
|
58
|
+
? node.parentElement
|
|
59
|
+
: node.nodeType === 1
|
|
60
|
+
? node
|
|
61
|
+
: null;
|
|
62
|
+
const activeLabel = nodeElement?.closest("[data-bullet-label], [data-ordered-label], [data-checkbox-label], [data-toggle-label]");
|
|
63
|
+
if (activeLabel && block.contains(activeLabel)) {
|
|
64
|
+
return activeLabel;
|
|
65
|
+
}
|
|
66
|
+
const directLabel = Array.from(block.querySelectorAll(getTreeRowLabelSelector())).find((label) => label.parentElement?.hasAttribute("data-rich-text-row"));
|
|
67
|
+
if (directLabel) {
|
|
68
|
+
return directLabel;
|
|
69
|
+
}
|
|
70
|
+
const code = block.querySelector("code");
|
|
71
|
+
return code ?? block;
|
|
72
|
+
}
|
|
73
|
+
function getTreeRowLabelSelector() {
|
|
74
|
+
return [
|
|
75
|
+
"[data-bullet-label]",
|
|
76
|
+
"[data-ordered-label]",
|
|
77
|
+
"[data-checkbox-label]",
|
|
78
|
+
"[data-toggle-label]",
|
|
79
|
+
].join(", ");
|
|
80
|
+
}
|
|
81
|
+
function getTextOffsetWithin(root, range) {
|
|
82
|
+
const textRange = getOwnerDocument(root).createRange();
|
|
83
|
+
textRange.selectNodeContents(root);
|
|
84
|
+
textRange.setEnd(range.startContainer, range.startOffset);
|
|
85
|
+
return getEditorVisibleTextLength(textRange.cloneContents());
|
|
86
|
+
}
|
|
87
|
+
function findFocusTargetAtVisibleTextOffset(root, offset) {
|
|
88
|
+
const remaining = { value: Math.max(0, Math.trunc(offset)) };
|
|
89
|
+
return findFocusTargetInChildren(root, remaining);
|
|
90
|
+
}
|
|
91
|
+
function findFocusTargetInChildren(root, remaining) {
|
|
92
|
+
for (const child of Array.from(root.childNodes)) {
|
|
93
|
+
if (child.nodeType === 3) {
|
|
94
|
+
const text = child.textContent ?? "";
|
|
95
|
+
const textLength = getVisibleTextLength(text);
|
|
96
|
+
if (remaining.value <= textLength) {
|
|
97
|
+
return {
|
|
98
|
+
node: child,
|
|
99
|
+
offset: getUtf16IndexAtVisibleTextOffset(text, remaining.value),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
remaining.value -= textLength;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (isLineBreakNode(child)) {
|
|
106
|
+
const parent = child.parentNode;
|
|
107
|
+
if (!parent) {
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (remaining.value === 0) {
|
|
111
|
+
return { node: parent, offset: getChildNodeIndex(child) };
|
|
112
|
+
}
|
|
113
|
+
if (remaining.value === 1) {
|
|
114
|
+
return { node: parent, offset: getChildNodeIndex(child) + 1 };
|
|
115
|
+
}
|
|
116
|
+
remaining.value -= 1;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
const target = findFocusTargetInChildren(child, remaining);
|
|
120
|
+
if (target) {
|
|
121
|
+
return target;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
function focusNodeEnd(root) {
|
|
127
|
+
const target = findLastTextFocusTarget(root);
|
|
128
|
+
const range = getOwnerDocument(root).createRange();
|
|
129
|
+
if (target) {
|
|
130
|
+
range.setStart(target.node, target.offset);
|
|
131
|
+
}
|
|
132
|
+
else {
|
|
133
|
+
range.selectNodeContents(root);
|
|
134
|
+
range.collapse(false);
|
|
135
|
+
}
|
|
136
|
+
const selection = getOwnerWindow(root).getSelection();
|
|
137
|
+
selection?.removeAllRanges();
|
|
138
|
+
selection?.addRange(range);
|
|
139
|
+
}
|
|
140
|
+
function findLastTextFocusTarget(root) {
|
|
141
|
+
for (const child of Array.from(root.childNodes).reverse()) {
|
|
142
|
+
if (child.nodeType === 3) {
|
|
143
|
+
return {
|
|
144
|
+
node: child,
|
|
145
|
+
offset: child.textContent?.length ?? 0,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
if (isLineBreakNode(child)) {
|
|
149
|
+
return {
|
|
150
|
+
node: root,
|
|
151
|
+
offset: getChildNodeIndex(child) + 1,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
const target = findLastTextFocusTarget(child);
|
|
155
|
+
if (target) {
|
|
156
|
+
return target;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
function getEditorVisibleTextLength(root) {
|
|
162
|
+
let length = 0;
|
|
163
|
+
for (const child of Array.from(root.childNodes)) {
|
|
164
|
+
if (child.nodeType === 3) {
|
|
165
|
+
length += getVisibleTextLength(child.textContent ?? "");
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (isLineBreakNode(child)) {
|
|
169
|
+
length += 1;
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
length += getEditorVisibleTextLength(child);
|
|
173
|
+
}
|
|
174
|
+
return length;
|
|
175
|
+
}
|
|
176
|
+
function isLineBreakNode(node) {
|
|
177
|
+
return node.nodeType === 1 && node.tagName === "BR";
|
|
178
|
+
}
|
|
179
|
+
function getChildNodeIndex(node) {
|
|
180
|
+
return Array.prototype.indexOf.call(node.parentNode?.childNodes ?? [], node);
|
|
181
|
+
}
|
|
182
|
+
function getVisibleTextLength(value) {
|
|
183
|
+
return Array.from(value).length;
|
|
184
|
+
}
|
|
185
|
+
function getUtf16IndexAtVisibleTextOffset(value, offset) {
|
|
186
|
+
if (offset <= 0) {
|
|
187
|
+
return 0;
|
|
188
|
+
}
|
|
189
|
+
let visibleOffset = 0;
|
|
190
|
+
for (let index = 0; index < value.length;) {
|
|
191
|
+
const nextIndex = getNextUtf16Index(value, index);
|
|
192
|
+
visibleOffset += 1;
|
|
193
|
+
if (visibleOffset >= offset) {
|
|
194
|
+
return nextIndex;
|
|
195
|
+
}
|
|
196
|
+
index = nextIndex;
|
|
197
|
+
}
|
|
198
|
+
return value.length;
|
|
199
|
+
}
|
|
200
|
+
function getNextUtf16Index(value, index) {
|
|
201
|
+
const codePoint = value.codePointAt(index);
|
|
202
|
+
return index + (codePoint && codePoint > 0xffff ? 2 : 1);
|
|
203
|
+
}
|
|
204
|
+
function getOwnerDocument(node) {
|
|
205
|
+
return node.ownerDocument ?? document;
|
|
206
|
+
}
|
|
207
|
+
function getOwnerWindow(node) {
|
|
208
|
+
return getOwnerDocument(node).defaultView ?? window;
|
|
209
|
+
}
|
|
210
|
+
function cssEscape(value) {
|
|
211
|
+
if (typeof CSS !== "undefined" && CSS.escape) {
|
|
212
|
+
return CSS.escape(value);
|
|
213
|
+
}
|
|
214
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
215
|
+
}
|
|
@@ -7,6 +7,16 @@ export type TextBlockShortcut = {
|
|
|
7
7
|
} | {
|
|
8
8
|
type: "quote";
|
|
9
9
|
markdown: string;
|
|
10
|
+
} | {
|
|
11
|
+
type: "bullet";
|
|
12
|
+
markdown: string;
|
|
13
|
+
} | {
|
|
14
|
+
type: "ordered";
|
|
15
|
+
markdown: string;
|
|
16
|
+
} | {
|
|
17
|
+
type: "toggle";
|
|
18
|
+
collapsed: boolean;
|
|
19
|
+
markdown: string;
|
|
10
20
|
} | {
|
|
11
21
|
type: "checkbox";
|
|
12
22
|
checked: boolean;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
const dividerMarkers = new Set(["---", "—-", "***", "___"]);
|
|
2
2
|
export function getTextBlockShortcut(markdown) {
|
|
3
3
|
const trimmed = markdown.trim();
|
|
4
|
+
const line = markdown.replace(/\u00a0/g, " ");
|
|
4
5
|
if (dividerMarkers.has(trimmed)) {
|
|
5
6
|
return { type: "divider" };
|
|
6
7
|
}
|
|
7
|
-
const checkbox =
|
|
8
|
+
const checkbox = line.match(/^\[( |x|X)?\]\s*(.*)$/);
|
|
8
9
|
if (checkbox) {
|
|
9
10
|
return {
|
|
10
11
|
type: "checkbox",
|
|
@@ -15,9 +16,24 @@ export function getTextBlockShortcut(markdown) {
|
|
|
15
16
|
if (trimmed.startsWith("# ")) {
|
|
16
17
|
return { type: "heading", markdown: trimmed.slice(2).trim() };
|
|
17
18
|
}
|
|
19
|
+
if (trimmed.startsWith(">> ")) {
|
|
20
|
+
return {
|
|
21
|
+
type: "toggle",
|
|
22
|
+
collapsed: false,
|
|
23
|
+
markdown: trimmed.slice(3).trim(),
|
|
24
|
+
};
|
|
25
|
+
}
|
|
18
26
|
if (trimmed.startsWith("> ")) {
|
|
19
27
|
return { type: "quote", markdown: trimmed.slice(2).trim() };
|
|
20
28
|
}
|
|
29
|
+
const bullet = line.match(/^[-*]\s(.*)$/);
|
|
30
|
+
if (bullet) {
|
|
31
|
+
return { type: "bullet", markdown: bullet[1]?.trim() ?? "" };
|
|
32
|
+
}
|
|
33
|
+
const ordered = line.match(/^1\.\s(.*)$/);
|
|
34
|
+
if (ordered) {
|
|
35
|
+
return { type: "ordered", markdown: ordered[1]?.trim() ?? "" };
|
|
36
|
+
}
|
|
21
37
|
if (trimmed.startsWith("```")) {
|
|
22
38
|
return { type: "code", text: trimmed.slice(3).trimStart() };
|
|
23
39
|
}
|
|
@@ -5,6 +5,7 @@ export type RichTextIconProps = {
|
|
|
5
5
|
export declare function AddIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
export declare function BoldIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
7
7
|
export declare function CloseIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
8
|
+
export declare function BulletListIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
8
9
|
export declare function CopyIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
9
10
|
export declare function CodeIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
10
11
|
export declare function CutIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -16,6 +17,8 @@ export declare function ImageIcon(props: RichTextIconProps): import("react/jsx-r
|
|
|
16
17
|
export declare function ItalicIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
17
18
|
export declare function LinkIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
18
19
|
export declare function MicIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
20
|
+
export declare function PasteIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
19
21
|
export declare function QuoteIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
20
22
|
export declare function StopIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
21
23
|
export declare function TitleIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
24
|
+
export declare function ToggleIcon(props: RichTextIconProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -11,6 +11,9 @@ export function BoldIcon(props) {
|
|
|
11
11
|
export function CloseIcon(props) {
|
|
12
12
|
return (_jsx(IconSvg, { ...props, children: _jsx("path", { d: "m6 6 12 12M18 6 6 18", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "2" }) }));
|
|
13
13
|
}
|
|
14
|
+
export function BulletListIcon(props) {
|
|
15
|
+
return (_jsxs(IconSvg, { ...props, children: [_jsx("path", { d: "M9 7h10M9 12h10M9 17h10", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "2" }), _jsx("circle", { cx: "5", cy: "7", fill: "currentColor", r: "1.4" }), _jsx("circle", { cx: "5", cy: "12", fill: "currentColor", r: "1.4" }), _jsx("circle", { cx: "5", cy: "17", fill: "currentColor", r: "1.4" })] }));
|
|
16
|
+
}
|
|
14
17
|
export function CopyIcon(props) {
|
|
15
18
|
return (_jsxs(IconSvg, { ...props, children: [_jsx("rect", { height: "11", rx: "1.8", stroke: "currentColor", strokeWidth: "2", width: "9", x: "9", y: "7" }), _jsx("path", { d: "M6 15H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h8a2 2 0 0 1 2 2v1", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "2" })] }));
|
|
16
19
|
}
|
|
@@ -44,6 +47,9 @@ export function LinkIcon(props) {
|
|
|
44
47
|
export function MicIcon(props) {
|
|
45
48
|
return (_jsxs(IconSvg, { ...props, children: [_jsx("path", { d: "M12 4a3 3 0 0 0-3 3v5a3 3 0 0 0 6 0V7a3 3 0 0 0-3-3Z", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2" }), _jsx("path", { d: "M5 11a7 7 0 0 0 14 0M12 18v3m-3 0h6", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "2" })] }));
|
|
46
49
|
}
|
|
50
|
+
export function PasteIcon(props) {
|
|
51
|
+
return (_jsxs(IconSvg, { ...props, children: [_jsx("path", { d: "M9 5h6m-6 0a3 3 0 0 1 6 0m-6 0H7a2 2 0 0 0-2 2v11a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2" }), _jsx("path", { d: "M12 9v7m-3-3 3 3 3-3", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2" })] }));
|
|
52
|
+
}
|
|
47
53
|
export function QuoteIcon(props) {
|
|
48
54
|
return (_jsx(IconSvg, { ...props, children: _jsx("path", { d: "M9 7H6.5A2.5 2.5 0 0 0 4 9.5V17h5v-5H6.5v-1.5H9zm11 0h-2.5A2.5 2.5 0 0 0 15 9.5V17h5v-5h-2.5v-1.5H20z", fill: "currentColor" }) }));
|
|
49
55
|
}
|
|
@@ -53,3 +59,6 @@ export function StopIcon(props) {
|
|
|
53
59
|
export function TitleIcon(props) {
|
|
54
60
|
return (_jsx(IconSvg, { ...props, children: _jsx("path", { d: "M5 6h14M12 6v12m-4 0h8", stroke: "currentColor", strokeLinecap: "round", strokeWidth: "2" }) }));
|
|
55
61
|
}
|
|
62
|
+
export function ToggleIcon(props) {
|
|
63
|
+
return (_jsx(IconSvg, { ...props, children: _jsx("path", { d: "m8 7 4 5-4 5M13 7h6M13 12h6M13 17h6", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2" }) }));
|
|
64
|
+
}
|
package/dist/react/index.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
export { EditorSessionProvider, useEditorExitGuard, useEditorSession, } from "./EditorSessionProvider";
|
|
2
|
-
export type { EditorSessionControls, EditorSessionProviderProps, UseEditorSessionOptions, } from "./EditorSessionProvider";
|
|
3
|
-
export { RichTextDocumentSurface } from "./RichTextDocumentSurface";
|
|
4
|
-
export type { RichTextDocumentSurfaceBackground } from "./RichTextDocumentSurface";
|
|
5
|
-
export { RichTextEditor } from "./RichTextEditor";
|
|
6
|
-
export {
|
|
7
|
-
export {
|
|
8
|
-
export {
|
|
9
|
-
export type
|
|
1
|
+
export { EditorSessionProvider, useEditorExitGuard, useEditorSession, } from "./session/EditorSessionProvider";
|
|
2
|
+
export type { EditorSessionControls, EditorSessionProviderProps, UseEditorSessionOptions, } from "./session/EditorSessionProvider";
|
|
3
|
+
export { RichTextDocumentSurface } from "./editor/RichTextDocumentSurface";
|
|
4
|
+
export type { RichTextDocumentSurfaceBackground } from "./editor/RichTextDocumentSurface";
|
|
5
|
+
export { RichTextEditor, type RichTextEditorBehavior, type RichTextContentChange, type RichTextHistoryControls, type RichTextHistoryLabel, type RichTextHistoryMetadata, type RichTextHistorySnapshot, type RichTextHistorySnapshotEntry, type RichTextImageUploadHandler, type RichTextImageUploadResult, } from "./editor/RichTextEditor";
|
|
6
|
+
export type { RichTextEditorEntitlements, RichTextFeatureGate, RichTextLockedFeatureMode, } from "../core/features";
|
|
7
|
+
export { createEditorOperation, type RichTextEditorOperation, type RichTextEditorOperationKind, } from "./editor/editorOperations";
|
|
8
|
+
export { RichTextReadTitle } from "./editor/RichTextTitleInput";
|
|
9
|
+
export { RichTextRenderer, type RichTextAnnotationTarget, } from "./editor/RichTextRenderer";
|
|
10
|
+
export type { RichTextToolBlockRenderer } from "./editor/RichTextRenderedBlock";
|
|
11
|
+
export { UnsavedChangesDialog } from "./session/UnsavedChangesDialog";
|
|
12
|
+
export type { UnsavedChangesDialogProps } from "./session/UnsavedChangesDialog";
|
package/dist/react/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export { EditorSessionProvider, useEditorExitGuard, useEditorSession, } from "./EditorSessionProvider.js";
|
|
2
|
-
export { RichTextDocumentSurface } from "./RichTextDocumentSurface.js";
|
|
3
|
-
export { RichTextEditor } from "./RichTextEditor.js";
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
6
|
-
export {
|
|
1
|
+
export { EditorSessionProvider, useEditorExitGuard, useEditorSession, } from "./session/EditorSessionProvider.js";
|
|
2
|
+
export { RichTextDocumentSurface } from "./editor/RichTextDocumentSurface.js";
|
|
3
|
+
export { RichTextEditor, } from "./editor/RichTextEditor.js";
|
|
4
|
+
export { createEditorOperation, } from "./editor/editorOperations.js";
|
|
5
|
+
export { RichTextReadTitle } from "./editor/RichTextTitleInput.js";
|
|
6
|
+
export { RichTextRenderer, } from "./editor/RichTextRenderer.js";
|
|
7
|
+
export { UnsavedChangesDialog } from "./session/UnsavedChangesDialog.js";
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import { type EditorDirtyScope, type EditorSessionValue } from "
|
|
3
|
-
import { type EditorExitAction } from "
|
|
2
|
+
import { type EditorDirtyScope, type EditorSessionValue } from "../../session/session";
|
|
3
|
+
import { type EditorExitAction } from "../../session/sessionRegistry";
|
|
4
4
|
export type EditorSessionProviderProps = {
|
|
5
5
|
children: ReactNode;
|
|
6
6
|
};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { createContext, useContext, useEffect, useState, useSyncExternalStore, } from "react";
|
|
4
|
-
import { createEditorSession, } from "
|
|
5
|
-
import { createEditorSessionRegistry, } from "
|
|
6
|
-
import { canonicalSerialize } from "
|
|
4
|
+
import { createEditorSession, } from "../../session/session.js";
|
|
5
|
+
import { createEditorSessionRegistry, } from "../../session/sessionRegistry.js";
|
|
6
|
+
import { canonicalSerialize } from "../../session/session.js";
|
|
7
7
|
import { UnsavedChangesDialog } from "./UnsavedChangesDialog.js";
|
|
8
8
|
const EditorSessionRegistryContext = createContext(null);
|
|
9
9
|
export function EditorSessionProvider({ children, }) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { RichTextStyleScope } from "
|
|
3
|
+
import { RichTextStyleScope } from "../styles/RichTextStyles.js";
|
|
4
4
|
export function UnsavedChangesDialog({ error, onDiscardAndLeave, onSaveAndLeave, onStay, open, saving, }) {
|
|
5
5
|
if (!open) {
|
|
6
6
|
return null;
|