@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,177 @@
|
|
|
1
|
+
const hoverLaneLeftWidth = 72;
|
|
2
|
+
const hoverLaneRightWidth = 36;
|
|
3
|
+
const hoverLaneVerticalPadding = 10;
|
|
4
|
+
const raisedBlockActionToolTopOffset = -4;
|
|
5
|
+
export function getBlockActionToolAnchorTop(blockType, top) {
|
|
6
|
+
return blockType === "checkbox" ? top + raisedBlockActionToolTopOffset : top;
|
|
7
|
+
}
|
|
8
|
+
export function getBlockActionToolRenderTop(placement) {
|
|
9
|
+
return placement.toolTop ?? placement.top;
|
|
10
|
+
}
|
|
11
|
+
export function getVisibleBlockActionToolPlacements(placements, state) {
|
|
12
|
+
const uniquePlacements = getUniqueBlockActionToolPlacements(placements);
|
|
13
|
+
const visibleBlockId = state.activeBlockId ??
|
|
14
|
+
state.draggedBlockId ??
|
|
15
|
+
state.hoveredBlockId ??
|
|
16
|
+
state.focusedBlockId;
|
|
17
|
+
return visibleBlockId
|
|
18
|
+
? uniquePlacements.filter((placement) => placement.blockId === visibleBlockId)
|
|
19
|
+
: [];
|
|
20
|
+
}
|
|
21
|
+
export function getPointerDropTarget(placements, draggedBlockId, pointerClientY, pointerClientX) {
|
|
22
|
+
const targetPlacements = placements.filter((placement) => {
|
|
23
|
+
return placement.blockId !== draggedBlockId;
|
|
24
|
+
});
|
|
25
|
+
const rowPlacements = targetPlacements.filter((placement) => {
|
|
26
|
+
return placement.dropRole !== "content";
|
|
27
|
+
});
|
|
28
|
+
const contentPlacements = targetPlacements.filter((placement) => {
|
|
29
|
+
return placement.dropRole === "content";
|
|
30
|
+
});
|
|
31
|
+
const targetPlacement = findContainingPlacement(rowPlacements, pointerClientY) ??
|
|
32
|
+
findContainingPlacement(contentPlacements, pointerClientY) ??
|
|
33
|
+
getClosestPlacement(rowPlacements, pointerClientY) ??
|
|
34
|
+
getClosestPlacement(contentPlacements, pointerClientY);
|
|
35
|
+
if (!targetPlacement) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
if (targetPlacement.dropRole === "content") {
|
|
39
|
+
return {
|
|
40
|
+
placement: "inside",
|
|
41
|
+
targetBlockId: targetPlacement.blockId,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (pointerClientX !== undefined &&
|
|
45
|
+
pointerClientX >= targetPlacement.left + 24) {
|
|
46
|
+
return {
|
|
47
|
+
placement: "inside",
|
|
48
|
+
targetBlockId: targetPlacement.blockId,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
const visualAncestorDropTarget = pointerClientX === undefined
|
|
52
|
+
? null
|
|
53
|
+
: getVisualAncestorDropTarget(rowPlacements, targetPlacement, pointerClientX);
|
|
54
|
+
if (visualAncestorDropTarget) {
|
|
55
|
+
return visualAncestorDropTarget;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
placement: pointerClientY >
|
|
59
|
+
targetPlacement.top + (targetPlacement.bottom - targetPlacement.top) / 2
|
|
60
|
+
? "after"
|
|
61
|
+
: "before",
|
|
62
|
+
targetBlockId: targetPlacement.blockId,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function getPointerDragDropResult(placements, draggedBlockId, pointerClientY, pointerClientX) {
|
|
66
|
+
const containingPlacement = findContainingPlacement(placements, pointerClientY);
|
|
67
|
+
if (containingPlacement?.blockId === draggedBlockId) {
|
|
68
|
+
return {
|
|
69
|
+
dropTarget: getDropTargetFromPlacement(containingPlacement, pointerClientY, pointerClientX),
|
|
70
|
+
status: "invalid",
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const dropTarget = getPointerDropTarget(placements, draggedBlockId, pointerClientY, pointerClientX);
|
|
74
|
+
if (!dropTarget) {
|
|
75
|
+
return { status: "invalid" };
|
|
76
|
+
}
|
|
77
|
+
const targetPlacement = placements.find((placement) => {
|
|
78
|
+
return (placement.blockId === dropTarget.targetBlockId &&
|
|
79
|
+
(dropTarget.placement === "inside" || placement.dropRole !== "content"));
|
|
80
|
+
});
|
|
81
|
+
if (dropTarget.targetBlockId === draggedBlockId ||
|
|
82
|
+
targetPlacement?.ancestorBlockIds?.includes(draggedBlockId)) {
|
|
83
|
+
return { dropTarget, status: "invalid" };
|
|
84
|
+
}
|
|
85
|
+
return { dropTarget, status: "valid" };
|
|
86
|
+
}
|
|
87
|
+
function getDropTargetFromPlacement(placement, pointerClientY, pointerClientX) {
|
|
88
|
+
if (placement.dropRole === "content" ||
|
|
89
|
+
(pointerClientX !== undefined && pointerClientX >= placement.left + 24)) {
|
|
90
|
+
return {
|
|
91
|
+
placement: "inside",
|
|
92
|
+
targetBlockId: placement.blockId,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
return {
|
|
96
|
+
placement: pointerClientY > placement.top + (placement.bottom - placement.top) / 2
|
|
97
|
+
? "after"
|
|
98
|
+
: "before",
|
|
99
|
+
targetBlockId: placement.blockId,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function getPointerHoverLaneBlockId(placements, pointerTop, pointerLeft) {
|
|
103
|
+
const placement = getUniqueBlockActionToolPlacements(placements).find((currentPlacement) => {
|
|
104
|
+
return (pointerTop >= currentPlacement.top - hoverLaneVerticalPadding &&
|
|
105
|
+
pointerTop <= currentPlacement.bottom + hoverLaneVerticalPadding &&
|
|
106
|
+
pointerLeft >= currentPlacement.left - hoverLaneLeftWidth &&
|
|
107
|
+
pointerLeft <= currentPlacement.left + hoverLaneRightWidth);
|
|
108
|
+
});
|
|
109
|
+
return placement?.blockId ?? null;
|
|
110
|
+
}
|
|
111
|
+
export function getUniqueBlockActionToolPlacements(placements) {
|
|
112
|
+
const seenBlockIds = new Set();
|
|
113
|
+
return placements.filter((placement) => {
|
|
114
|
+
if (placement.dropRole === "content") {
|
|
115
|
+
return false;
|
|
116
|
+
}
|
|
117
|
+
if (seenBlockIds.has(placement.blockId)) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
seenBlockIds.add(placement.blockId);
|
|
121
|
+
return true;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function getVisualAncestorDropTarget(rowPlacements, targetPlacement, pointerClientX) {
|
|
125
|
+
const targetDepth = targetPlacement.depth ?? targetPlacement.ancestorBlockIds?.length ?? 0;
|
|
126
|
+
if (targetDepth <= 0 || !targetPlacement.ancestorBlockIds?.length) {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
const desiredDepth = clamp(Math.round((pointerClientX - getMinimumPlacementLeft(rowPlacements)) /
|
|
130
|
+
getPlacementIndentSize(rowPlacements)), 0, targetDepth);
|
|
131
|
+
if (desiredDepth >= targetDepth) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const targetBlockId = targetPlacement.ancestorBlockIds[desiredDepth];
|
|
135
|
+
return targetBlockId
|
|
136
|
+
? {
|
|
137
|
+
placement: "after",
|
|
138
|
+
targetBlockId,
|
|
139
|
+
}
|
|
140
|
+
: null;
|
|
141
|
+
}
|
|
142
|
+
function getPlacementIndentSize(placements) {
|
|
143
|
+
const leftPositions = Array.from(new Set(placements.map((placement) => Math.round(placement.left)))).sort((a, b) => a - b);
|
|
144
|
+
const positiveDiffs = leftPositions
|
|
145
|
+
.slice(1)
|
|
146
|
+
.map((left, index) => left - (leftPositions[index] ?? left))
|
|
147
|
+
.filter((diff) => diff > 0);
|
|
148
|
+
return Math.min(...positiveDiffs, 42);
|
|
149
|
+
}
|
|
150
|
+
function getMinimumPlacementLeft(placements) {
|
|
151
|
+
return Math.min(...placements.map((placement) => placement.left), 0);
|
|
152
|
+
}
|
|
153
|
+
function clamp(value, min, max) {
|
|
154
|
+
return Math.min(Math.max(value, min), max);
|
|
155
|
+
}
|
|
156
|
+
function getDistanceToPlacement(placement, pointerClientY) {
|
|
157
|
+
if (pointerClientY >= placement.top && pointerClientY <= placement.bottom) {
|
|
158
|
+
return 0;
|
|
159
|
+
}
|
|
160
|
+
return Math.min(Math.abs(pointerClientY - placement.top), Math.abs(pointerClientY - placement.bottom));
|
|
161
|
+
}
|
|
162
|
+
function findContainingPlacement(placements, pointerClientY) {
|
|
163
|
+
return placements.find((placement) => {
|
|
164
|
+
return (pointerClientY >= placement.top && pointerClientY <= placement.bottom);
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
function getClosestPlacement(placements, pointerClientY) {
|
|
168
|
+
return placements.reduce((closestPlacement, placement) => {
|
|
169
|
+
if (!closestPlacement) {
|
|
170
|
+
return placement;
|
|
171
|
+
}
|
|
172
|
+
return getDistanceToPlacement(placement, pointerClientY) <
|
|
173
|
+
getDistanceToPlacement(closestPlacement, pointerClientY)
|
|
174
|
+
? placement
|
|
175
|
+
: closestPlacement;
|
|
176
|
+
}, null);
|
|
177
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export function warnIfImageBlockMissingDisplayUrl(block) {
|
|
2
|
+
if (block.type !== "image" ||
|
|
3
|
+
block.url ||
|
|
4
|
+
typeof block.uploadProgress === "number" ||
|
|
5
|
+
!block.alt?.trim()) {
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
console.warn("Rich text image block is missing a display URL.", {
|
|
9
|
+
alt: block.alt,
|
|
10
|
+
blockId: block.id,
|
|
11
|
+
});
|
|
12
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.findBlockPath = findBlockPath;
|
|
4
|
+
exports.getBlockAtPath = getBlockAtPath;
|
|
5
|
+
exports.getBlocksAtPath = getBlocksAtPath;
|
|
6
|
+
exports.removeBlockAtPath = removeBlockAtPath;
|
|
7
|
+
exports.updateBlockAtPath = updateBlockAtPath;
|
|
8
|
+
exports.insertBlockAtPath = insertBlockAtPath;
|
|
9
|
+
exports.pathContains = pathContains;
|
|
10
|
+
exports.withNestableBlockChildren = withNestableBlockChildren;
|
|
11
|
+
exports.withBlockChildren = withBlockChildren;
|
|
12
|
+
const blockTypes_1 = require("./blockTypes");
|
|
13
|
+
function findBlockPath(blocks, blockId) {
|
|
14
|
+
for (let index = 0; index < blocks.length; index += 1) {
|
|
15
|
+
const block = blocks[index];
|
|
16
|
+
if (!block) {
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (block.id === blockId) {
|
|
20
|
+
return [index];
|
|
21
|
+
}
|
|
22
|
+
if ((0, blockTypes_1.isNestableRichTextBlock)(block) && block.children?.length) {
|
|
23
|
+
const childPath = findBlockPath(block.children, blockId);
|
|
24
|
+
if (childPath) {
|
|
25
|
+
return [index, ...childPath];
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
function getBlockAtPath(blocks, path) {
|
|
32
|
+
let currentBlocks = blocks;
|
|
33
|
+
let currentBlock;
|
|
34
|
+
for (const index of path) {
|
|
35
|
+
currentBlock = currentBlocks[index];
|
|
36
|
+
if (!currentBlock) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
currentBlocks = (0, blockTypes_1.isNestableRichTextBlock)(currentBlock)
|
|
40
|
+
? currentBlock.children ?? []
|
|
41
|
+
: [];
|
|
42
|
+
}
|
|
43
|
+
return currentBlock ?? null;
|
|
44
|
+
}
|
|
45
|
+
function getBlocksAtPath(blocks, path) {
|
|
46
|
+
if (path.length === 0) {
|
|
47
|
+
return blocks;
|
|
48
|
+
}
|
|
49
|
+
const parent = getBlockAtPath(blocks, path);
|
|
50
|
+
return (0, blockTypes_1.isNestableRichTextBlock)(parent) ? parent.children ?? [] : null;
|
|
51
|
+
}
|
|
52
|
+
function removeBlockAtPath(blocks, path) {
|
|
53
|
+
const [index, ...rest] = path;
|
|
54
|
+
if (index === undefined) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
if (rest.length === 0) {
|
|
58
|
+
const block = blocks[index];
|
|
59
|
+
if (!block) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
block,
|
|
64
|
+
blocks: [...blocks.slice(0, index), ...blocks.slice(index + 1)],
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
const parent = blocks[index];
|
|
68
|
+
if (!(0, blockTypes_1.isNestableRichTextBlock)(parent)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
const removed = removeBlockAtPath(parent.children ?? [], rest);
|
|
72
|
+
if (!removed) {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
const updatedParent = withNestableBlockChildren(parent, removed.blocks);
|
|
76
|
+
return {
|
|
77
|
+
block: removed.block,
|
|
78
|
+
blocks: [
|
|
79
|
+
...blocks.slice(0, index),
|
|
80
|
+
updatedParent,
|
|
81
|
+
...blocks.slice(index + 1),
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function updateBlockAtPath(blocks, path, updater) {
|
|
86
|
+
const [index, ...rest] = path;
|
|
87
|
+
if (index === undefined) {
|
|
88
|
+
return blocks;
|
|
89
|
+
}
|
|
90
|
+
const block = blocks[index];
|
|
91
|
+
if (!block) {
|
|
92
|
+
return blocks;
|
|
93
|
+
}
|
|
94
|
+
const updatedBlock = rest.length === 0
|
|
95
|
+
? updater(block)
|
|
96
|
+
: (0, blockTypes_1.isNestableRichTextBlock)(block)
|
|
97
|
+
? withNestableBlockChildren(block, updateBlockAtPath(block.children ?? [], rest, updater))
|
|
98
|
+
: block;
|
|
99
|
+
return [...blocks.slice(0, index), updatedBlock, ...blocks.slice(index + 1)];
|
|
100
|
+
}
|
|
101
|
+
function insertBlockAtPath(blocks, parentPath, index, insertedBlocks) {
|
|
102
|
+
if (parentPath.length === 0) {
|
|
103
|
+
return [
|
|
104
|
+
...blocks.slice(0, index),
|
|
105
|
+
...insertedBlocks,
|
|
106
|
+
...blocks.slice(index),
|
|
107
|
+
];
|
|
108
|
+
}
|
|
109
|
+
return updateBlockAtPath(blocks, parentPath, (parent) => {
|
|
110
|
+
if (!(0, blockTypes_1.isNestableRichTextBlock)(parent)) {
|
|
111
|
+
return parent;
|
|
112
|
+
}
|
|
113
|
+
return withNestableBlockChildren(parent, [
|
|
114
|
+
...(parent.children ?? []).slice(0, index),
|
|
115
|
+
...insertedBlocks,
|
|
116
|
+
...(parent.children ?? []).slice(index),
|
|
117
|
+
]);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
function pathContains(parentPath, childPath) {
|
|
121
|
+
return parentPath.every((index, pathIndex) => childPath[pathIndex] === index);
|
|
122
|
+
}
|
|
123
|
+
function withNestableBlockChildren(block, children) {
|
|
124
|
+
if (block.type === "toggle") {
|
|
125
|
+
return { ...block, children };
|
|
126
|
+
}
|
|
127
|
+
if (children.length > 0) {
|
|
128
|
+
return { ...block, children };
|
|
129
|
+
}
|
|
130
|
+
const { children: _children, ...rest } = block;
|
|
131
|
+
return rest;
|
|
132
|
+
}
|
|
133
|
+
function withBlockChildren(block, children) {
|
|
134
|
+
return (0, blockTypes_1.isNestableRichTextBlock)(block)
|
|
135
|
+
? withNestableBlockChildren(block, children)
|
|
136
|
+
: block;
|
|
137
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.NESTABLE_RICH_TEXT_BLOCK_TYPES = void 0;
|
|
4
|
+
exports.isNestableRichTextBlock = isNestableRichTextBlock;
|
|
5
|
+
exports.NESTABLE_RICH_TEXT_BLOCK_TYPES = new Set(["bullet", "ordered", "checkbox", "toggle"]);
|
|
6
|
+
function isNestableRichTextBlock(block) {
|
|
7
|
+
return (!!block &&
|
|
8
|
+
exports.NESTABLE_RICH_TEXT_BLOCK_TYPES.has(block.type));
|
|
9
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.richTextJsonImportAdapter = exports.richTextJsonExportAdapter = void 0;
|
|
4
|
+
exports.exportRichTextBlocks = exportRichTextBlocks;
|
|
5
|
+
exports.importRichTextBlocks = importRichTextBlocks;
|
|
6
|
+
const features_1 = require("./features");
|
|
7
|
+
const richText_1 = require("./richText");
|
|
8
|
+
exports.richTextJsonExportAdapter = {
|
|
9
|
+
extension: "json",
|
|
10
|
+
exportBlocks: (blocks) => ({
|
|
11
|
+
data: JSON.stringify((0, richText_1.sanitizeRichTextBlocks)(blocks), null, 2),
|
|
12
|
+
extension: "json",
|
|
13
|
+
format: "bayon-rich-text-json",
|
|
14
|
+
mimeType: "application/json",
|
|
15
|
+
}),
|
|
16
|
+
id: "bayon-rich-text-json",
|
|
17
|
+
label: "Bayon rich text JSON",
|
|
18
|
+
mimeType: "application/json",
|
|
19
|
+
};
|
|
20
|
+
exports.richTextJsonImportAdapter = {
|
|
21
|
+
extension: "json",
|
|
22
|
+
id: "bayon-rich-text-json",
|
|
23
|
+
importData: (data) => JSON.parse(data),
|
|
24
|
+
label: "Bayon rich text JSON",
|
|
25
|
+
mimeType: "application/json",
|
|
26
|
+
};
|
|
27
|
+
async function exportRichTextBlocks({ adapter, blocks, features, }) {
|
|
28
|
+
const gate = getExportImportGate(features);
|
|
29
|
+
if (gate) {
|
|
30
|
+
return { gate, ok: false };
|
|
31
|
+
}
|
|
32
|
+
return {
|
|
33
|
+
ok: true,
|
|
34
|
+
value: adapter.exportBlocks((0, richText_1.sanitizeRichTextBlocks)(blocks)),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function importRichTextBlocks({ adapter, data, features, }) {
|
|
38
|
+
const gate = getExportImportGate(features);
|
|
39
|
+
if (gate) {
|
|
40
|
+
return { gate, ok: false };
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
ok: true,
|
|
44
|
+
value: (0, richText_1.sanitizeRichTextBlocks)(adapter.importData(data)),
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function getExportImportGate(features) {
|
|
48
|
+
const access = (0, features_1.getRichTextFeatureAccess)(features, "export-import");
|
|
49
|
+
return access.enabled
|
|
50
|
+
? null
|
|
51
|
+
: {
|
|
52
|
+
featureId: access.featureId,
|
|
53
|
+
label: access.label,
|
|
54
|
+
reason: access.reason,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.richTextEditorFeatureCatalog = void 0;
|
|
4
|
+
exports.getRichTextFeatureAccess = getRichTextFeatureAccess;
|
|
5
|
+
exports.isRichTextFeatureEnabled = isRichTextFeatureEnabled;
|
|
6
|
+
exports.richTextEditorFeatureCatalog = {
|
|
7
|
+
"image-upload": {
|
|
8
|
+
label: "Image upload",
|
|
9
|
+
tier: "free",
|
|
10
|
+
},
|
|
11
|
+
transcription: {
|
|
12
|
+
label: "Transcription",
|
|
13
|
+
tier: "free",
|
|
14
|
+
},
|
|
15
|
+
"export-import": {
|
|
16
|
+
label: "Export and import",
|
|
17
|
+
tier: "pro",
|
|
18
|
+
},
|
|
19
|
+
comments: {
|
|
20
|
+
label: "Comments",
|
|
21
|
+
tier: "pro",
|
|
22
|
+
},
|
|
23
|
+
"review-marks": {
|
|
24
|
+
label: "Review marks",
|
|
25
|
+
tier: "pro",
|
|
26
|
+
},
|
|
27
|
+
"schema-migrations": {
|
|
28
|
+
label: "Schema migrations",
|
|
29
|
+
tier: "pro",
|
|
30
|
+
},
|
|
31
|
+
templates: {
|
|
32
|
+
label: "Templates",
|
|
33
|
+
tier: "pro",
|
|
34
|
+
},
|
|
35
|
+
collaboration: {
|
|
36
|
+
label: "Collaboration",
|
|
37
|
+
tier: "pro",
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
function getRichTextFeatureAccess(features, featureId) {
|
|
41
|
+
const feature = exports.richTextEditorFeatureCatalog[featureId];
|
|
42
|
+
const enabled = features?.[featureId] ?? true;
|
|
43
|
+
if (enabled) {
|
|
44
|
+
return {
|
|
45
|
+
enabled: true,
|
|
46
|
+
featureId,
|
|
47
|
+
label: feature.label,
|
|
48
|
+
reason: undefined,
|
|
49
|
+
tier: feature.tier,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
return {
|
|
53
|
+
enabled: false,
|
|
54
|
+
featureId,
|
|
55
|
+
label: feature.label,
|
|
56
|
+
reason: feature.tier === "pro" ? "premium" : "disabled",
|
|
57
|
+
tier: feature.tier,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function isRichTextFeatureEnabled(features, featureId) {
|
|
61
|
+
return getRichTextFeatureAccess(features, featureId).enabled;
|
|
62
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runRichTextSchemaMigrations = runRichTextSchemaMigrations;
|
|
4
|
+
exports.instantiateRichTextTemplate = instantiateRichTextTemplate;
|
|
5
|
+
exports.connectRichTextCollaboration = connectRichTextCollaboration;
|
|
6
|
+
exports.createRichTextAnnotations = createRichTextAnnotations;
|
|
7
|
+
const features_1 = require("./features");
|
|
8
|
+
const richText_1 = require("./richText");
|
|
9
|
+
async function runRichTextSchemaMigrations({ blocks, features, migrations, }) {
|
|
10
|
+
const gate = getProFeatureGate(features, "schema-migrations");
|
|
11
|
+
if (gate) {
|
|
12
|
+
return { gate, ok: false };
|
|
13
|
+
}
|
|
14
|
+
let nextBlocks = (0, richText_1.sanitizeRichTextBlocks)(blocks);
|
|
15
|
+
const appliedMigrationIds = [];
|
|
16
|
+
for (const migration of migrations) {
|
|
17
|
+
nextBlocks = (0, richText_1.sanitizeRichTextBlocks)(migration.migrate(nextBlocks));
|
|
18
|
+
appliedMigrationIds.push(migration.id);
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
ok: true,
|
|
22
|
+
value: { appliedMigrationIds, blocks: nextBlocks },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
async function instantiateRichTextTemplate({ features, template, variables, }) {
|
|
26
|
+
const gate = getProFeatureGate(features, "templates");
|
|
27
|
+
if (gate) {
|
|
28
|
+
return { gate, ok: false };
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
ok: true,
|
|
32
|
+
value: (0, richText_1.sanitizeRichTextBlocks)(template.createBlocks(variables)),
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
async function connectRichTextCollaboration({ adapter, blocks, features, }) {
|
|
36
|
+
const gate = getProFeatureGate(features, "collaboration");
|
|
37
|
+
if (gate) {
|
|
38
|
+
return { gate, ok: false };
|
|
39
|
+
}
|
|
40
|
+
return {
|
|
41
|
+
ok: true,
|
|
42
|
+
value: await adapter.connect({ blocks: (0, richText_1.sanitizeRichTextBlocks)(blocks) }),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function createRichTextAnnotations({ annotations, features, }) {
|
|
46
|
+
const reviewGate = annotations.some((annotation) => annotation.kind === "review-mark")
|
|
47
|
+
? getProFeatureGate(features, "review-marks")
|
|
48
|
+
: null;
|
|
49
|
+
const commentGate = annotations.some((annotation) => annotation.kind === "comment")
|
|
50
|
+
? getProFeatureGate(features, "comments")
|
|
51
|
+
: null;
|
|
52
|
+
const gate = reviewGate ?? commentGate;
|
|
53
|
+
if (gate) {
|
|
54
|
+
return { gate, ok: false };
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
ok: true,
|
|
58
|
+
value: annotations.filter((annotation) => annotation.id.trim() && annotation.blockId.trim()),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
function getProFeatureGate(features, featureId) {
|
|
62
|
+
const access = (0, features_1.getRichTextFeatureAccess)(features, featureId);
|
|
63
|
+
return access.enabled
|
|
64
|
+
? null
|
|
65
|
+
: {
|
|
66
|
+
featureId: access.featureId,
|
|
67
|
+
label: access.label,
|
|
68
|
+
reason: access.reason,
|
|
69
|
+
};
|
|
70
|
+
}
|