@portabletext/editor 2.21.2 → 3.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/lib/_chunks-dts/index.d.ts +50 -210
- package/lib/_chunks-es/selector.is-at-the-start-of-block.js +103 -20
- package/lib/_chunks-es/selector.is-at-the-start-of-block.js.map +1 -1
- package/lib/_chunks-es/{util.get-text-block-text.js → util.slice-blocks.js} +29 -5
- package/lib/_chunks-es/util.slice-blocks.js.map +1 -0
- package/lib/_chunks-es/util.slice-text-block.js +13 -2
- package/lib/_chunks-es/util.slice-text-block.js.map +1 -1
- package/lib/behaviors/index.d.ts +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.js +323 -320
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.d.ts +2 -133
- package/lib/plugins/index.js +2 -796
- package/lib/plugins/index.js.map +1 -1
- package/lib/selectors/index.d.ts +2 -24
- package/lib/selectors/index.js +28 -130
- package/lib/selectors/index.js.map +1 -1
- package/lib/utils/index.d.ts +3 -3
- package/lib/utils/index.js +97 -9
- package/lib/utils/index.js.map +1 -1
- package/package.json +7 -9
- package/src/behaviors/behavior.perform-event.ts +7 -7
- package/src/editor/PortableTextEditor.tsx +0 -19
- package/src/editor/create-editor.ts +0 -3
- package/src/editor/editor-machine.ts +0 -10
- package/src/editor/event-to-change.tsx +5 -1
- package/src/editor/plugins/create-with-event-listeners.ts +0 -4
- package/src/editor/plugins/createWithObjectKeys.ts +2 -1
- package/src/editor/plugins/createWithPatches.ts +3 -3
- package/src/editor/plugins/createWithPlaceholderBlock.ts +2 -1
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +2 -1
- package/src/editor/plugins/with-plugins.ts +10 -14
- package/src/editor/relay-machine.ts +0 -4
- package/src/editor/sync-machine.ts +2 -2
- package/src/editor.ts +0 -4
- package/src/history/behavior.operation.history.redo.ts +67 -0
- package/src/history/behavior.operation.history.undo.ts +71 -0
- package/src/history/event.history.undo.test.tsx +672 -0
- package/src/history/history.preserving-keys.test.tsx +112 -0
- package/src/history/remote-patches.ts +20 -0
- package/src/history/slate-plugin.history.ts +146 -0
- package/src/history/slate-plugin.redoing.ts +21 -0
- package/src/history/slate-plugin.undoing.ts +21 -0
- package/src/history/slate-plugin.without-history.ts +23 -0
- package/src/history/transform-operation.ts +245 -0
- package/src/history/undo-redo-collaboration.test.tsx +541 -0
- package/src/history/undo-redo.feature +125 -0
- package/src/history/undo-redo.test.tsx +195 -0
- package/src/history/undo-step.ts +148 -0
- package/src/index.ts +0 -1
- package/src/internal-utils/applyPatch.ts +46 -1
- package/src/operations/behavior.operations.ts +2 -4
- package/src/plugins/index.ts +0 -3
- package/src/selectors/index.ts +0 -3
- package/src/test/vitest/step-definitions.tsx +88 -8
- package/src/test/vitest/test-editor.tsx +1 -1
- package/lib/_chunks-es/selector.get-selection-text.js +0 -92
- package/lib/_chunks-es/selector.get-selection-text.js.map +0 -1
- package/lib/_chunks-es/selector.get-text-before.js +0 -36
- package/lib/_chunks-es/selector.get-text-before.js.map +0 -1
- package/lib/_chunks-es/util.get-text-block-text.js.map +0 -1
- package/lib/_chunks-es/util.is-empty-text-block.js +0 -40
- package/lib/_chunks-es/util.is-empty-text-block.js.map +0 -1
- package/lib/_chunks-es/util.merge-text-blocks.js +0 -101
- package/lib/_chunks-es/util.merge-text-blocks.js.map +0 -1
- package/src/editor/plugins/createWithMaxBlocks.ts +0 -53
- package/src/editor/plugins/createWithUndoRedo.ts +0 -628
- package/src/editor/with-undo-step.ts +0 -37
- package/src/editor/withUndoRedo.ts +0 -34
- package/src/editor-event-listener.tsx +0 -28
- package/src/plugins/plugin.decorator-shortcut.ts +0 -238
- package/src/plugins/plugin.markdown.test.tsx +0 -42
- package/src/plugins/plugin.markdown.tsx +0 -131
- package/src/plugins/plugin.one-line.tsx +0 -123
- package/src/selectors/selector.get-list-state.test.ts +0 -189
- package/src/selectors/selector.get-list-state.ts +0 -96
- package/src/selectors/selector.get-selected-slice.ts +0 -13
- package/src/selectors/selector.get-trimmed-selection.test.ts +0 -657
- package/src/selectors/selector.get-trimmed-selection.ts +0 -189
package/lib/utils/index.js
CHANGED
|
@@ -1,15 +1,103 @@
|
|
|
1
|
-
import { getBlockKeyFromSelectionPoint } from "../_chunks-es/util.
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { isEqualSelectionPoints } from "../_chunks-es/util.is-empty-text-block.js";
|
|
6
|
-
import { getBlockEndPoint, isEmptyTextBlock, isSelectionCollapsed } from "../_chunks-es/util.is-empty-text-block.js";
|
|
7
|
-
import { isSpan } from "@portabletext/schema";
|
|
8
|
-
import { isSpan as isSpan2, isTextBlock } from "@portabletext/schema";
|
|
1
|
+
import { blockOffsetToSpanSelectionPoint, getBlockKeyFromSelectionPoint, getChildKeyFromSelectionPoint, isEqualSelectionPoints, parseBlock } from "../_chunks-es/util.slice-blocks.js";
|
|
2
|
+
import { getBlockEndPoint, getBlockStartPoint, getSelectionEndPoint, getSelectionStartPoint, isKeyedSegment, isSelectionCollapsed, sliceBlocks, spanSelectionPointToBlockOffset } from "../_chunks-es/util.slice-blocks.js";
|
|
3
|
+
import { isTextBlock, isSpan } from "@portabletext/schema";
|
|
4
|
+
import { isSpan as isSpan2, isTextBlock as isTextBlock2 } from "@portabletext/schema";
|
|
9
5
|
import { sliceTextBlock } from "../_chunks-es/util.slice-text-block.js";
|
|
6
|
+
import { getTextBlockText, isEmptyTextBlock } from "../_chunks-es/util.slice-text-block.js";
|
|
7
|
+
function blockOffsetToBlockSelectionPoint({
|
|
8
|
+
context,
|
|
9
|
+
blockOffset
|
|
10
|
+
}) {
|
|
11
|
+
let selectionPoint;
|
|
12
|
+
for (const block of context.value)
|
|
13
|
+
if (block._key === blockOffset.path[0]._key) {
|
|
14
|
+
selectionPoint = {
|
|
15
|
+
path: [{
|
|
16
|
+
_key: block._key
|
|
17
|
+
}],
|
|
18
|
+
offset: blockOffset.offset
|
|
19
|
+
};
|
|
20
|
+
break;
|
|
21
|
+
}
|
|
22
|
+
return selectionPoint;
|
|
23
|
+
}
|
|
24
|
+
function blockOffsetToSelectionPoint({
|
|
25
|
+
context,
|
|
26
|
+
blockOffset,
|
|
27
|
+
direction
|
|
28
|
+
}) {
|
|
29
|
+
return blockOffsetToSpanSelectionPoint({
|
|
30
|
+
context,
|
|
31
|
+
blockOffset,
|
|
32
|
+
direction
|
|
33
|
+
}) || blockOffsetToBlockSelectionPoint({
|
|
34
|
+
context,
|
|
35
|
+
blockOffset
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function blockOffsetsToSelection({
|
|
39
|
+
context,
|
|
40
|
+
offsets,
|
|
41
|
+
backward
|
|
42
|
+
}) {
|
|
43
|
+
const anchor = blockOffsetToSelectionPoint({
|
|
44
|
+
context,
|
|
45
|
+
blockOffset: offsets.anchor,
|
|
46
|
+
direction: backward ? "backward" : "forward"
|
|
47
|
+
}), focus = blockOffsetToSelectionPoint({
|
|
48
|
+
context,
|
|
49
|
+
blockOffset: offsets.focus,
|
|
50
|
+
direction: backward ? "forward" : "backward"
|
|
51
|
+
});
|
|
52
|
+
return !anchor || !focus ? null : {
|
|
53
|
+
anchor,
|
|
54
|
+
focus,
|
|
55
|
+
backward
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function childSelectionPointToBlockOffset({
|
|
59
|
+
context,
|
|
60
|
+
selectionPoint
|
|
61
|
+
}) {
|
|
62
|
+
let offset = 0;
|
|
63
|
+
const blockKey = getBlockKeyFromSelectionPoint(selectionPoint), childKey = getChildKeyFromSelectionPoint(selectionPoint);
|
|
64
|
+
if (!(!blockKey || !childKey)) {
|
|
65
|
+
for (const block of context.value)
|
|
66
|
+
if (block._key === blockKey && isTextBlock(context, block))
|
|
67
|
+
for (const child of block.children) {
|
|
68
|
+
if (child._key === childKey)
|
|
69
|
+
return {
|
|
70
|
+
path: [{
|
|
71
|
+
_key: block._key
|
|
72
|
+
}],
|
|
73
|
+
offset: offset + selectionPoint.offset
|
|
74
|
+
};
|
|
75
|
+
isSpan(context, child) && (offset += child.text.length);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
10
79
|
function isEqualSelections(a, b) {
|
|
11
80
|
return !a && !b ? !0 : !a || !b ? !1 : isEqualSelectionPoints(a.anchor, b.anchor) && isEqualSelectionPoints(a.focus, b.focus);
|
|
12
81
|
}
|
|
82
|
+
function mergeTextBlocks({
|
|
83
|
+
context,
|
|
84
|
+
targetBlock,
|
|
85
|
+
incomingBlock
|
|
86
|
+
}) {
|
|
87
|
+
const parsedIncomingBlock = parseBlock({
|
|
88
|
+
context,
|
|
89
|
+
block: incomingBlock,
|
|
90
|
+
options: {
|
|
91
|
+
removeUnusedMarkDefs: !0,
|
|
92
|
+
validateFields: !1
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
return !parsedIncomingBlock || !isTextBlock(context, parsedIncomingBlock) ? targetBlock : {
|
|
96
|
+
...targetBlock,
|
|
97
|
+
children: [...targetBlock.children, ...parsedIncomingBlock.children],
|
|
98
|
+
markDefs: [...targetBlock.markDefs ?? [], ...parsedIncomingBlock.markDefs ?? []]
|
|
99
|
+
};
|
|
100
|
+
}
|
|
13
101
|
function reverseSelection(selection) {
|
|
14
102
|
return selection && (selection.backward ? {
|
|
15
103
|
anchor: selection.focus,
|
|
@@ -99,7 +187,7 @@ export {
|
|
|
99
187
|
isKeyedSegment,
|
|
100
188
|
isSelectionCollapsed,
|
|
101
189
|
isSpan2 as isSpan,
|
|
102
|
-
isTextBlock,
|
|
190
|
+
isTextBlock2 as isTextBlock,
|
|
103
191
|
mergeTextBlocks,
|
|
104
192
|
reverseSelection,
|
|
105
193
|
selectionPointToBlockOffset,
|
package/lib/utils/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/utils/util.is-equal-selections.ts","../../src/utils/util.reverse-selection.ts","../../src/utils/util.selection-point-to-block-offset.ts","../../src/utils/util.split-text-block.ts"],"sourcesContent":["import type {EditorSelection} from '../types/editor'\nimport {isEqualSelectionPoints} from './util.is-equal-selection-points'\n\n/**\n * @public\n */\nexport function isEqualSelections(a: EditorSelection, b: EditorSelection) {\n if (!a && !b) {\n return true\n }\n\n if (!a || !b) {\n return false\n }\n\n return (\n isEqualSelectionPoints(a.anchor, b.anchor) &&\n isEqualSelectionPoints(a.focus, b.focus)\n )\n}\n","import type {EditorSelection} from '../types/editor'\n\n/**\n * @public\n */\nexport function reverseSelection<\n TEditorSelection extends NonNullable<EditorSelection> | null,\n>(selection: TEditorSelection): TEditorSelection {\n if (!selection) {\n return selection\n }\n\n if (selection.backward) {\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: false,\n } as TEditorSelection\n }\n\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: true,\n } as TEditorSelection\n}\n","import type {EditorContext} from '../editor/editor-snapshot'\nimport type {BlockOffset} from '../types/block-offset'\nimport type {EditorSelectionPoint} from '../types/editor'\nimport {childSelectionPointToBlockOffset} from './util.child-selection-point-to-block-offset'\nimport {getBlockKeyFromSelectionPoint} from './util.selection-point'\n\n/**\n * @public\n */\nexport function selectionPointToBlockOffset({\n context,\n selectionPoint,\n}: {\n context: Pick<EditorContext, 'schema' | 'value'>\n selectionPoint: EditorSelectionPoint\n}): BlockOffset | undefined {\n const blockKey = getBlockKeyFromSelectionPoint(selectionPoint)\n\n if (selectionPoint.path.length === 1 && blockKey !== undefined) {\n return {\n path: [{_key: blockKey}],\n offset: selectionPoint.offset,\n }\n }\n\n return childSelectionPointToBlockOffset({\n context,\n selectionPoint,\n })\n}\n","import {isSpan} from '@portabletext/schema'\nimport type {PortableTextTextBlock} from '@sanity/types'\nimport type {EditorContext} from '../editor/editor-snapshot'\nimport type {EditorSelectionPoint} from '../types/editor'\nimport {sliceTextBlock} from './util.slice-text-block'\n\n/**\n * @beta\n */\nexport function splitTextBlock({\n context,\n block,\n point,\n}: {\n context: Pick<EditorContext, 'schema'>\n block: PortableTextTextBlock\n point: EditorSelectionPoint\n}): {before: PortableTextTextBlock; after: PortableTextTextBlock} | undefined {\n const firstChild = block.children.at(0)\n const lastChild = block.children.at(block.children.length - 1)\n\n if (!firstChild || !lastChild) {\n return undefined\n }\n\n const before = sliceTextBlock({\n context: {\n schema: context.schema,\n selection: {\n anchor: {\n path: [{_key: block._key}, 'children', {_key: firstChild._key}],\n offset: 0,\n },\n focus: point,\n },\n },\n block,\n })\n const after = sliceTextBlock({\n context: {\n schema: context.schema,\n selection: {\n anchor: point,\n focus: {\n path: [{_key: block._key}, 'children', {_key: lastChild._key}],\n offset: isSpan(context, lastChild) ? lastChild.text.length : 0,\n },\n },\n },\n block,\n })\n\n return {before, after}\n}\n"],"names":["isEqualSelections","a","b","isEqualSelectionPoints","anchor","focus","reverseSelection","selection","backward","selectionPointToBlockOffset","context","selectionPoint","blockKey","getBlockKeyFromSelectionPoint","path","length","undefined","_key","offset","childSelectionPointToBlockOffset","splitTextBlock","block","point","firstChild","children","at","lastChild","before","sliceTextBlock","schema","after","isSpan","text"],"mappings":";;;;;;;;;AAMO,SAASA,kBAAkBC,GAAoBC,GAAoB;AACxE,SAAI,CAACD,KAAK,CAACC,IACF,KAGL,CAACD,KAAK,CAACC,IACF,KAIPC,uBAAuBF,EAAEG,QAAQF,EAAEE,MAAM,KACzCD,uBAAuBF,EAAEI,OAAOH,EAAEG,KAAK;AAE3C;ACdO,SAASC,iBAEdC,WAA+C;AAC/C,SAAKA,cAIDA,UAAUC,WACL;AAAA,IACLJ,QAAQG,UAAUF;AAAAA,IAClBA,OAAOE,UAAUH;AAAAA,IACjBI,UAAU;AAAA,EAAA,IAIP;AAAA,IACLJ,QAAQG,UAAUF;AAAAA,IAClBA,OAAOE,UAAUH;AAAAA,IACjBI,UAAU;AAAA,EAAA;AAEd;AChBO,SAASC,4BAA4B;AAAA,EAC1CC;AAAAA,EACAC;AAIF,GAA4B;AAC1B,QAAMC,WAAWC,8BAA8BF,cAAc;AAE7D,SAAIA,eAAeG,KAAKC,WAAW,KAAKH,aAAaI,SAC5C;AAAA,IACLF,MAAM,CAAC;AAAA,MAACG,MAAML;AAAAA,IAAAA,CAAS;AAAA,IACvBM,QAAQP,eAAeO;AAAAA,EAAAA,IAIpBC,iCAAiC;AAAA,IACtCT;AAAAA,IACAC;AAAAA,EAAAA,CACD;AACH;ACpBO,SAASS,eAAe;AAAA,EAC7BV;AAAAA,EACAW;AAAAA,EACAC;AAKF,GAA8E;AAC5E,QAAMC,aAAaF,MAAMG,SAASC,GAAG,CAAC,GAChCC,YAAYL,MAAMG,SAASC,GAAGJ,MAAMG,SAAST,SAAS,CAAC;AAE7D,MAAI,CAACQ,cAAc,CAACG;AAClB;AAGF,QAAMC,SAASC,eAAe;AAAA,IAC5BlB,SAAS;AAAA,MACPmB,QAAQnB,QAAQmB;AAAAA,MAChBtB,WAAW;AAAA,QACTH,QAAQ;AAAA,UACNU,MAAM,CAAC;AAAA,YAACG,MAAMI,MAAMJ;AAAAA,UAAAA,GAAO,YAAY;AAAA,YAACA,MAAMM,WAAWN;AAAAA,UAAAA,CAAK;AAAA,UAC9DC,QAAQ;AAAA,QAAA;AAAA,QAEVb,OAAOiB;AAAAA,MAAAA;AAAAA,IACT;AAAA,IAEFD;AAAAA,EAAAA,CACD,GACKS,QAAQF,eAAe;AAAA,IAC3BlB,SAAS;AAAA,MACPmB,QAAQnB,QAAQmB;AAAAA,MAChBtB,WAAW;AAAA,QACTH,QAAQkB;AAAAA,QACRjB,OAAO;AAAA,UACLS,MAAM,CAAC;AAAA,YAACG,MAAMI,MAAMJ;AAAAA,UAAAA,GAAO,YAAY;AAAA,YAACA,MAAMS,UAAUT;AAAAA,UAAAA,CAAK;AAAA,UAC7DC,QAAQa,OAAOrB,SAASgB,SAAS,IAAIA,UAAUM,KAAKjB,SAAS;AAAA,QAAA;AAAA,MAC/D;AAAA,IACF;AAAA,IAEFM;AAAAA,EAAAA,CACD;AAED,SAAO;AAAA,IAACM;AAAAA,IAAQG;AAAAA,EAAAA;AAClB;"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/utils/util.block-offset-to-block-selection-point.ts","../../src/utils/util.block-offset-to-selection-point.ts","../../src/utils/util.block-offsets-to-selection.ts","../../src/utils/util.child-selection-point-to-block-offset.ts","../../src/utils/util.is-equal-selections.ts","../../src/utils/util.merge-text-blocks.ts","../../src/utils/util.reverse-selection.ts","../../src/utils/util.selection-point-to-block-offset.ts","../../src/utils/util.split-text-block.ts"],"sourcesContent":["import type {EditorContext} from '../editor/editor-snapshot'\nimport type {BlockOffset} from '../types/block-offset'\nimport type {EditorSelectionPoint} from '../types/editor'\n\n/**\n * @public\n */\nexport function blockOffsetToBlockSelectionPoint({\n context,\n blockOffset,\n}: {\n context: Pick<EditorContext, 'value'>\n blockOffset: BlockOffset\n}): EditorSelectionPoint | undefined {\n let selectionPoint: EditorSelectionPoint | undefined\n\n for (const block of context.value) {\n if (block._key === blockOffset.path[0]._key) {\n selectionPoint = {\n path: [{_key: block._key}],\n offset: blockOffset.offset,\n }\n break\n }\n }\n\n return selectionPoint\n}\n","import type {EditorContext} from '../editor/editor-snapshot'\nimport type {BlockOffset} from '../types/block-offset'\nimport type {EditorSelectionPoint} from '../types/editor'\nimport {blockOffsetToSpanSelectionPoint} from './util.block-offset'\nimport {blockOffsetToBlockSelectionPoint} from './util.block-offset-to-block-selection-point'\n\n/**\n * @public\n */\nexport function blockOffsetToSelectionPoint({\n context,\n blockOffset,\n direction,\n}: {\n context: Pick<EditorContext, 'schema' | 'value'>\n blockOffset: BlockOffset\n direction: 'forward' | 'backward'\n}): EditorSelectionPoint | undefined {\n const spanSelectionPoint = blockOffsetToSpanSelectionPoint({\n context,\n blockOffset,\n direction,\n })\n\n if (!spanSelectionPoint) {\n return blockOffsetToBlockSelectionPoint({\n context,\n blockOffset,\n })\n }\n\n return spanSelectionPoint\n}\n","import type {EditorContext} from '../editor/editor-snapshot'\nimport type {BlockOffset} from '../types/block-offset'\nimport type {EditorSelection} from '../types/editor'\nimport {blockOffsetToSelectionPoint} from './util.block-offset-to-selection-point'\n\n/**\n * @public\n */\nexport function blockOffsetsToSelection({\n context,\n offsets,\n backward,\n}: {\n context: Pick<EditorContext, 'schema' | 'value'>\n offsets: {anchor: BlockOffset; focus: BlockOffset}\n backward?: boolean\n}): EditorSelection {\n const anchor = blockOffsetToSelectionPoint({\n context,\n blockOffset: offsets.anchor,\n direction: backward ? 'backward' : 'forward',\n })\n const focus = blockOffsetToSelectionPoint({\n context,\n blockOffset: offsets.focus,\n direction: backward ? 'forward' : 'backward',\n })\n\n if (!anchor || !focus) {\n return null\n }\n\n return {\n anchor,\n focus,\n backward,\n }\n}\n","import {isSpan, isTextBlock} from '@portabletext/schema'\nimport type {EditorContext} from '../editor/editor-snapshot'\nimport type {BlockOffset} from '../types/block-offset'\nimport type {EditorSelectionPoint} from '../types/editor'\nimport {\n getBlockKeyFromSelectionPoint,\n getChildKeyFromSelectionPoint,\n} from './util.selection-point'\n\n/**\n * @public\n */\nexport function childSelectionPointToBlockOffset({\n context,\n selectionPoint,\n}: {\n context: Pick<EditorContext, 'schema' | 'value'>\n selectionPoint: EditorSelectionPoint\n}): BlockOffset | undefined {\n let offset = 0\n\n const blockKey = getBlockKeyFromSelectionPoint(selectionPoint)\n const childKey = getChildKeyFromSelectionPoint(selectionPoint)\n\n if (!blockKey || !childKey) {\n return undefined\n }\n\n for (const block of context.value) {\n if (block._key !== blockKey) {\n continue\n }\n\n if (!isTextBlock(context, block)) {\n continue\n }\n\n for (const child of block.children) {\n if (child._key === childKey) {\n return {\n path: [{_key: block._key}],\n offset: offset + selectionPoint.offset,\n }\n }\n\n if (isSpan(context, child)) {\n offset += child.text.length\n }\n }\n }\n}\n","import type {EditorSelection} from '../types/editor'\nimport {isEqualSelectionPoints} from './util.is-equal-selection-points'\n\n/**\n * @public\n */\nexport function isEqualSelections(a: EditorSelection, b: EditorSelection) {\n if (!a && !b) {\n return true\n }\n\n if (!a || !b) {\n return false\n }\n\n return (\n isEqualSelectionPoints(a.anchor, b.anchor) &&\n isEqualSelectionPoints(a.focus, b.focus)\n )\n}\n","import {isTextBlock} from '@portabletext/schema'\nimport type {PortableTextTextBlock} from '@sanity/types'\nimport type {EditorContext} from '../editor/editor-snapshot'\nimport {parseBlock} from './parse-blocks'\n\n/**\n * @beta\n */\nexport function mergeTextBlocks({\n context,\n targetBlock,\n incomingBlock,\n}: {\n context: Pick<EditorContext, 'keyGenerator' | 'schema'>\n targetBlock: PortableTextTextBlock\n incomingBlock: PortableTextTextBlock\n}) {\n const parsedIncomingBlock = parseBlock({\n context,\n block: incomingBlock,\n options: {removeUnusedMarkDefs: true, validateFields: false},\n })\n\n if (!parsedIncomingBlock || !isTextBlock(context, parsedIncomingBlock)) {\n return targetBlock\n }\n\n return {\n ...targetBlock,\n children: [...targetBlock.children, ...parsedIncomingBlock.children],\n markDefs: [\n ...(targetBlock.markDefs ?? []),\n ...(parsedIncomingBlock.markDefs ?? []),\n ],\n }\n}\n","import type {EditorSelection} from '../types/editor'\n\n/**\n * @public\n */\nexport function reverseSelection<\n TEditorSelection extends NonNullable<EditorSelection> | null,\n>(selection: TEditorSelection): TEditorSelection {\n if (!selection) {\n return selection\n }\n\n if (selection.backward) {\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: false,\n } as TEditorSelection\n }\n\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: true,\n } as TEditorSelection\n}\n","import type {EditorContext} from '../editor/editor-snapshot'\nimport type {BlockOffset} from '../types/block-offset'\nimport type {EditorSelectionPoint} from '../types/editor'\nimport {childSelectionPointToBlockOffset} from './util.child-selection-point-to-block-offset'\nimport {getBlockKeyFromSelectionPoint} from './util.selection-point'\n\n/**\n * @public\n */\nexport function selectionPointToBlockOffset({\n context,\n selectionPoint,\n}: {\n context: Pick<EditorContext, 'schema' | 'value'>\n selectionPoint: EditorSelectionPoint\n}): BlockOffset | undefined {\n const blockKey = getBlockKeyFromSelectionPoint(selectionPoint)\n\n if (selectionPoint.path.length === 1 && blockKey !== undefined) {\n return {\n path: [{_key: blockKey}],\n offset: selectionPoint.offset,\n }\n }\n\n return childSelectionPointToBlockOffset({\n context,\n selectionPoint,\n })\n}\n","import {isSpan} from '@portabletext/schema'\nimport type {PortableTextTextBlock} from '@sanity/types'\nimport type {EditorContext} from '../editor/editor-snapshot'\nimport type {EditorSelectionPoint} from '../types/editor'\nimport {sliceTextBlock} from './util.slice-text-block'\n\n/**\n * @beta\n */\nexport function splitTextBlock({\n context,\n block,\n point,\n}: {\n context: Pick<EditorContext, 'schema'>\n block: PortableTextTextBlock\n point: EditorSelectionPoint\n}): {before: PortableTextTextBlock; after: PortableTextTextBlock} | undefined {\n const firstChild = block.children.at(0)\n const lastChild = block.children.at(block.children.length - 1)\n\n if (!firstChild || !lastChild) {\n return undefined\n }\n\n const before = sliceTextBlock({\n context: {\n schema: context.schema,\n selection: {\n anchor: {\n path: [{_key: block._key}, 'children', {_key: firstChild._key}],\n offset: 0,\n },\n focus: point,\n },\n },\n block,\n })\n const after = sliceTextBlock({\n context: {\n schema: context.schema,\n selection: {\n anchor: point,\n focus: {\n path: [{_key: block._key}, 'children', {_key: lastChild._key}],\n offset: isSpan(context, lastChild) ? lastChild.text.length : 0,\n },\n },\n },\n block,\n })\n\n return {before, after}\n}\n"],"names":["blockOffsetToBlockSelectionPoint","context","blockOffset","selectionPoint","block","value","_key","path","offset","blockOffsetToSelectionPoint","direction","blockOffsetToSpanSelectionPoint","blockOffsetsToSelection","offsets","backward","anchor","focus","childSelectionPointToBlockOffset","blockKey","getBlockKeyFromSelectionPoint","childKey","getChildKeyFromSelectionPoint","isTextBlock","child","children","isSpan","text","length","isEqualSelections","a","b","isEqualSelectionPoints","mergeTextBlocks","targetBlock","incomingBlock","parsedIncomingBlock","parseBlock","options","removeUnusedMarkDefs","validateFields","markDefs","reverseSelection","selection","selectionPointToBlockOffset","undefined","splitTextBlock","point","firstChild","at","lastChild","before","sliceTextBlock","schema","after"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -74,9 +74,9 @@
|
|
|
74
74
|
"slate-react": "0.119.0",
|
|
75
75
|
"xstate": "^5.24.0",
|
|
76
76
|
"@portabletext/block-tools": "^4.0.2",
|
|
77
|
+
"@portabletext/schema": "^2.0.0",
|
|
77
78
|
"@portabletext/keyboard-shortcuts": "^2.1.0",
|
|
78
|
-
"@portabletext/patches": "^2.0.0"
|
|
79
|
-
"@portabletext/schema": "^2.0.0"
|
|
79
|
+
"@portabletext/patches": "^2.0.0"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@sanity/diff-match-patch": "^3.2.0",
|
|
@@ -90,9 +90,9 @@
|
|
|
90
90
|
"@types/react": "^19.2.2",
|
|
91
91
|
"@types/react-dom": "^19.2.2",
|
|
92
92
|
"@vitejs/plugin-react": "^5.0.4",
|
|
93
|
-
"@vitest/browser": "^4.0.
|
|
94
|
-
"@vitest/browser-playwright": "^4.0.
|
|
95
|
-
"@vitest/coverage-istanbul": "^4.0.
|
|
93
|
+
"@vitest/browser": "^4.0.8",
|
|
94
|
+
"@vitest/browser-playwright": "^4.0.8",
|
|
95
|
+
"@vitest/coverage-istanbul": "^4.0.8",
|
|
96
96
|
"babel-plugin-react-compiler": "1.0.0",
|
|
97
97
|
"eslint": "^9.38.0",
|
|
98
98
|
"eslint-formatter-gha": "^1.6.0",
|
|
@@ -104,7 +104,7 @@
|
|
|
104
104
|
"typescript": "5.9.3",
|
|
105
105
|
"typescript-eslint": "^8.46.1",
|
|
106
106
|
"vite": "^7.1.12",
|
|
107
|
-
"vitest": "^4.0.
|
|
107
|
+
"vitest": "^4.0.8",
|
|
108
108
|
"vitest-browser-react": "^2.0.2",
|
|
109
109
|
"@portabletext/sanity-bridge": "1.2.2",
|
|
110
110
|
"@portabletext/test": "^1.0.0",
|
|
@@ -141,8 +141,6 @@
|
|
|
141
141
|
"test:browser:watch": "vitest --project browser",
|
|
142
142
|
"test:browser:webkit": "vitest --run --project \"browser (webkit)\"",
|
|
143
143
|
"test:browser:webkit:watch": "vitest --project \"browser (webkit)\"",
|
|
144
|
-
"test:e2e:chromium": "vitest --run --project \"browser.bak (chromium)\"",
|
|
145
|
-
"test:e2e:chromium:watch": "vitest --project \"browser.bak (chromium)\"",
|
|
146
144
|
"test:unit": "vitest --run --project unit",
|
|
147
145
|
"test:unit:watch": "vitest --project unit",
|
|
148
146
|
"test:watch": "vitest"
|
|
@@ -2,8 +2,8 @@ import {createEditorDom} from '../editor/editor-dom'
|
|
|
2
2
|
import type {EditorSchema} from '../editor/editor-schema'
|
|
3
3
|
import type {EditorSnapshot} from '../editor/editor-snapshot'
|
|
4
4
|
import {withPerformingBehaviorOperation} from '../editor/with-performing-behavior-operation'
|
|
5
|
-
import {clearUndoStep, createUndoStep} from '../editor/with-undo-step'
|
|
6
5
|
import {withoutNormalizingConditional} from '../editor/without-normalizing-conditional'
|
|
6
|
+
import {clearUndoStepId, createUndoStepId} from '../history/undo-step'
|
|
7
7
|
import {debugWithName} from '../internal-utils/debug'
|
|
8
8
|
import {performOperation} from '../operations/behavior.operations'
|
|
9
9
|
import type {PortableTextSlateEditor} from '../types/editor'
|
|
@@ -61,7 +61,7 @@ export function performEvent({
|
|
|
61
61
|
) => void
|
|
62
62
|
}) {
|
|
63
63
|
if (mode === 'send' && !isNativeBehaviorEvent(event)) {
|
|
64
|
-
|
|
64
|
+
createUndoStepId(editor)
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
debug(`(${mode}:${eventCategory(event)})`, JSON.stringify(event, null, 2))
|
|
@@ -110,7 +110,7 @@ export function performEvent({
|
|
|
110
110
|
nativeEvent?.preventDefault()
|
|
111
111
|
|
|
112
112
|
if (mode === 'send') {
|
|
113
|
-
|
|
113
|
+
clearUndoStepId(editor)
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
withPerformingBehaviorOperation(editor, () => {
|
|
@@ -211,7 +211,7 @@ export function performEvent({
|
|
|
211
211
|
|
|
212
212
|
if (actionSetIndex > 0) {
|
|
213
213
|
// Since there are multiple action sets
|
|
214
|
-
|
|
214
|
+
createUndoStepId(editor)
|
|
215
215
|
|
|
216
216
|
undoStepCreated = true
|
|
217
217
|
}
|
|
@@ -224,7 +224,7 @@ export function performEvent({
|
|
|
224
224
|
// we set up a new undo step.
|
|
225
225
|
// All actions performed recursively from now will be squashed into this
|
|
226
226
|
// undo step
|
|
227
|
-
|
|
227
|
+
createUndoStepId(editor)
|
|
228
228
|
|
|
229
229
|
undoStepCreated = true
|
|
230
230
|
}
|
|
@@ -321,7 +321,7 @@ export function performEvent({
|
|
|
321
321
|
)
|
|
322
322
|
|
|
323
323
|
if (undoStepCreated) {
|
|
324
|
-
|
|
324
|
+
clearUndoStepId(editor)
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
327
|
|
|
@@ -332,7 +332,7 @@ export function performEvent({
|
|
|
332
332
|
nativeEvent?.preventDefault()
|
|
333
333
|
|
|
334
334
|
if (mode === 'send') {
|
|
335
|
-
|
|
335
|
+
clearUndoStepId(editor)
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
withPerformingBehaviorOperation(editor, () => {
|
|
@@ -67,11 +67,6 @@ export type PortableTextEditorProps<
|
|
|
67
67
|
*/
|
|
68
68
|
schemaType: ArraySchemaType<PortableTextBlock> | ArrayDefinition
|
|
69
69
|
|
|
70
|
-
/**
|
|
71
|
-
* Maximum number of blocks to allow within the editor
|
|
72
|
-
*/
|
|
73
|
-
maxBlocks?: number | string
|
|
74
|
-
|
|
75
70
|
/**
|
|
76
71
|
* Function used to generate keys for array items (`_key`)
|
|
77
72
|
*/
|
|
@@ -152,10 +147,6 @@ export class PortableTextEditor extends Component<
|
|
|
152
147
|
const {actors, editor, subscriptions} = createInternalEditor({
|
|
153
148
|
initialValue: props.value,
|
|
154
149
|
keyGenerator: props.keyGenerator,
|
|
155
|
-
maxBlocks:
|
|
156
|
-
props.maxBlocks === undefined
|
|
157
|
-
? undefined
|
|
158
|
-
: Number.parseInt(props.maxBlocks.toString(), 10),
|
|
159
150
|
readOnly: props.readOnly,
|
|
160
151
|
schema: props.schemaType,
|
|
161
152
|
})
|
|
@@ -221,16 +212,6 @@ export class PortableTextEditor extends Component<
|
|
|
221
212
|
})
|
|
222
213
|
}
|
|
223
214
|
|
|
224
|
-
if (this.props.maxBlocks !== prevProps.maxBlocks) {
|
|
225
|
-
this.editor._internal.editorActor.send({
|
|
226
|
-
type: 'update maxBlocks',
|
|
227
|
-
maxBlocks:
|
|
228
|
-
this.props.maxBlocks === undefined
|
|
229
|
-
? undefined
|
|
230
|
-
: Number.parseInt(this.props.maxBlocks.toString(), 10),
|
|
231
|
-
})
|
|
232
|
-
}
|
|
233
|
-
|
|
234
215
|
if (this.props.value !== prevProps.value) {
|
|
235
216
|
this.editor.send({
|
|
236
217
|
type: 'update value',
|
|
@@ -108,7 +108,6 @@ export function createInternalEditor(config: EditorConfig): {
|
|
|
108
108
|
|
|
109
109
|
case 'update readOnly':
|
|
110
110
|
case 'patches':
|
|
111
|
-
case 'update maxBlocks':
|
|
112
111
|
editorActor.send(event)
|
|
113
112
|
break
|
|
114
113
|
|
|
@@ -169,7 +168,6 @@ function editorConfigToMachineInput(config: EditorConfig) {
|
|
|
169
168
|
converters: createCoreConverters(legacySchema),
|
|
170
169
|
getLegacySchema: () => legacySchema,
|
|
171
170
|
keyGenerator: config.keyGenerator ?? defaultKeyGenerator,
|
|
172
|
-
maxBlocks: config.maxBlocks,
|
|
173
171
|
readOnly: config.readOnly,
|
|
174
172
|
schema,
|
|
175
173
|
initialValue: config.initialValue,
|
|
@@ -239,7 +237,6 @@ function createActors(config: {
|
|
|
239
237
|
config.editorActor.send({
|
|
240
238
|
type: 'mutation',
|
|
241
239
|
patches: event.patches,
|
|
242
|
-
snapshot: event.snapshot,
|
|
243
240
|
value: event.snapshot,
|
|
244
241
|
})
|
|
245
242
|
}
|
|
@@ -57,10 +57,6 @@ export type ExternalEditorEvent =
|
|
|
57
57
|
type: 'update readOnly'
|
|
58
58
|
readOnly: boolean
|
|
59
59
|
}
|
|
60
|
-
| {
|
|
61
|
-
type: 'update maxBlocks'
|
|
62
|
-
maxBlocks: number | undefined
|
|
63
|
-
}
|
|
64
60
|
| PatchesEvent
|
|
65
61
|
|
|
66
62
|
type InternalPatchEvent = NamespaceEvent<PatchEvent, 'internal'> & {
|
|
@@ -191,7 +187,6 @@ export const editorMachine = setup({
|
|
|
191
187
|
pendingIncomingPatchesEvents: Array<PatchesEvent>
|
|
192
188
|
schema: EditorSchema
|
|
193
189
|
initialReadOnly: boolean
|
|
194
|
-
maxBlocks: number | undefined
|
|
195
190
|
selection: EditorSelection
|
|
196
191
|
initialValue: Array<PortableTextBlock> | undefined
|
|
197
192
|
internalDrag?: {
|
|
@@ -206,7 +201,6 @@ export const editorMachine = setup({
|
|
|
206
201
|
converters?: Array<Converter>
|
|
207
202
|
getLegacySchema: () => PortableTextMemberSchemaTypes
|
|
208
203
|
keyGenerator: () => string
|
|
209
|
-
maxBlocks?: number
|
|
210
204
|
readOnly?: boolean
|
|
211
205
|
schema: EditorSchema
|
|
212
206
|
initialValue?: Array<PortableTextBlock>
|
|
@@ -387,15 +381,11 @@ export const editorMachine = setup({
|
|
|
387
381
|
schema: input.schema,
|
|
388
382
|
selection: null,
|
|
389
383
|
initialReadOnly: input.readOnly ?? false,
|
|
390
|
-
maxBlocks: input.maxBlocks,
|
|
391
384
|
initialValue: input.initialValue,
|
|
392
385
|
}),
|
|
393
386
|
on: {
|
|
394
387
|
'add behavior': {actions: 'add behavior to context'},
|
|
395
388
|
'remove behavior': {actions: 'remove behavior from context'},
|
|
396
|
-
'update maxBlocks': {
|
|
397
|
-
actions: assign({maxBlocks: ({event}) => event.maxBlocks}),
|
|
398
|
-
},
|
|
399
389
|
'add slate editor': {actions: 'add slate editor to context'},
|
|
400
390
|
'update selection': {
|
|
401
391
|
actions: [
|
|
@@ -6,10 +6,6 @@ import {isPerformingBehaviorOperation} from '../with-performing-behavior-operati
|
|
|
6
6
|
|
|
7
7
|
export function createWithEventListeners(editorActor: EditorActor) {
|
|
8
8
|
return function withEventListeners(editor: Editor) {
|
|
9
|
-
if (editorActor.getSnapshot().context.maxBlocks !== undefined) {
|
|
10
|
-
return editor
|
|
11
|
-
}
|
|
12
|
-
|
|
13
9
|
const {delete: editorDelete, select} = editor
|
|
14
10
|
|
|
15
11
|
editor.delete = (options) => {
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import {isSpan, isTextBlock} from '@portabletext/schema'
|
|
2
2
|
import {isEqual} from 'lodash'
|
|
3
3
|
import {Editor, Element, Node, Path, Transforms} from 'slate'
|
|
4
|
+
import {isRedoing} from '../../history/slate-plugin.redoing'
|
|
5
|
+
import {isUndoing} from '../../history/slate-plugin.undoing'
|
|
4
6
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
5
7
|
import type {EditorActor} from '../editor-machine'
|
|
6
8
|
import {withNormalizeNode} from '../with-normalizing-node'
|
|
7
9
|
import {isChangingRemotely} from '../withChanges'
|
|
8
|
-
import {isRedoing, isUndoing} from '../withUndoRedo'
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* This plugin makes sure that every new node in the editor get a new _key prop when created
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import {insert, setIfMissing, unset, type Patch} from '@portabletext/patches'
|
|
2
2
|
import {Editor, type Descendant, type Operation} from 'slate'
|
|
3
|
+
import {pluginWithoutHistory} from '../../history/slate-plugin.without-history'
|
|
4
|
+
import {getCurrentUndoStepId} from '../../history/undo-step'
|
|
3
5
|
import {createApplyPatch} from '../../internal-utils/applyPatch'
|
|
4
6
|
import {debugWithName} from '../../internal-utils/debug'
|
|
5
7
|
import {
|
|
@@ -17,10 +19,8 @@ import type {PortableTextSlateEditor} from '../../types/editor'
|
|
|
17
19
|
import type {EditorActor} from '../editor-machine'
|
|
18
20
|
import type {RelayActor} from '../relay-machine'
|
|
19
21
|
import {IS_PROCESSING_REMOTE_CHANGES, KEY_TO_VALUE_ELEMENT} from '../weakMaps'
|
|
20
|
-
import {getCurrentUndoStepId} from '../with-undo-step'
|
|
21
22
|
import {withRemoteChanges} from '../withChanges'
|
|
22
23
|
import {isPatching, PATCHING, withoutPatching} from '../withoutPatching'
|
|
23
|
-
import {withoutSaving} from './createWithUndoRedo'
|
|
24
24
|
|
|
25
25
|
const debug = debugWithName('plugin:withPatches')
|
|
26
26
|
const debugVerbose = false
|
|
@@ -61,7 +61,7 @@ export function createWithPatches({
|
|
|
61
61
|
withRemoteChanges(editor, () => {
|
|
62
62
|
Editor.withoutNormalizing(editor, () => {
|
|
63
63
|
withoutPatching(editor, () => {
|
|
64
|
-
|
|
64
|
+
pluginWithoutHistory(editor, () => {
|
|
65
65
|
for (const patch of patches) {
|
|
66
66
|
if (debug.enabled)
|
|
67
67
|
debug(`Handling remote patch ${JSON.stringify(patch)}`)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import {Editor} from 'slate'
|
|
2
|
+
import {isRedoing} from '../../history/slate-plugin.redoing'
|
|
3
|
+
import {isUndoing} from '../../history/slate-plugin.undoing'
|
|
2
4
|
import {debugWithName} from '../../internal-utils/debug'
|
|
3
5
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
4
6
|
import type {EditorActor} from '../editor-machine'
|
|
5
7
|
import {isChangingRemotely} from '../withChanges'
|
|
6
|
-
import {isRedoing, isUndoing} from '../withUndoRedo'
|
|
7
8
|
|
|
8
9
|
const debug = debugWithName('plugin:withPlaceholderBlock')
|
|
9
10
|
|
|
@@ -8,6 +8,8 @@ import {isTextBlock} from '@portabletext/schema'
|
|
|
8
8
|
import type {PortableTextObject, PortableTextSpan} from '@sanity/types'
|
|
9
9
|
import {isEqual, uniq} from 'lodash'
|
|
10
10
|
import {Editor, Element, Node, Path, Range, Text, Transforms} from 'slate'
|
|
11
|
+
import {isRedoing} from '../../history/slate-plugin.redoing'
|
|
12
|
+
import {isUndoing} from '../../history/slate-plugin.undoing'
|
|
11
13
|
import {debugWithName} from '../../internal-utils/debug'
|
|
12
14
|
import {getNextSpan, getPreviousSpan} from '../../internal-utils/sibling-utils'
|
|
13
15
|
import type {BehaviorOperationImplementation} from '../../operations/behavior.operations'
|
|
@@ -17,7 +19,6 @@ import type {EditorActor} from '../editor-machine'
|
|
|
17
19
|
import {getEditorSnapshot} from '../editor-selector'
|
|
18
20
|
import {withNormalizeNode} from '../with-normalizing-node'
|
|
19
21
|
import {isChangingRemotely} from '../withChanges'
|
|
20
|
-
import {isRedoing, isUndoing} from '../withUndoRedo'
|
|
21
22
|
|
|
22
23
|
const debug = debugWithName('plugin:withPortableTextMarkModel')
|
|
23
24
|
|
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import type {BaseOperation, Editor, Node, NodeEntry} from 'slate'
|
|
2
|
+
import {pluginHistory} from '../../history/slate-plugin.history'
|
|
2
3
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
3
4
|
import type {EditorActor} from '../editor-machine'
|
|
4
5
|
import type {RelayActor} from '../relay-machine'
|
|
5
6
|
import {createWithEventListeners} from './create-with-event-listeners'
|
|
6
|
-
import {createWithMaxBlocks} from './createWithMaxBlocks'
|
|
7
7
|
import {createWithObjectKeys} from './createWithObjectKeys'
|
|
8
8
|
import {createWithPatches} from './createWithPatches'
|
|
9
9
|
import {createWithPlaceholderBlock} from './createWithPlaceholderBlock'
|
|
10
10
|
import {createWithPortableTextMarkModel} from './createWithPortableTextMarkModel'
|
|
11
11
|
import {createWithSchemaTypes} from './createWithSchemaTypes'
|
|
12
|
-
import {createWithUndoRedo} from './createWithUndoRedo'
|
|
13
12
|
import {createWithUtils} from './createWithUtils'
|
|
14
13
|
import {pluginUpdateSelection} from './slate-plugin.update-selection'
|
|
15
14
|
import {pluginUpdateValue} from './slate-plugin.update-value'
|
|
@@ -41,8 +40,7 @@ export const withPlugins = <T extends Editor>(
|
|
|
41
40
|
relayActor,
|
|
42
41
|
subscriptions: options.subscriptions,
|
|
43
42
|
})
|
|
44
|
-
const
|
|
45
|
-
const withUndoRedo = createWithUndoRedo({
|
|
43
|
+
const withUndoRedo = pluginHistory({
|
|
46
44
|
editorActor,
|
|
47
45
|
subscriptions: options.subscriptions,
|
|
48
46
|
})
|
|
@@ -62,16 +60,14 @@ export const withPlugins = <T extends Editor>(
|
|
|
62
60
|
withPortableTextMarkModel(
|
|
63
61
|
withPlaceholderBlock(
|
|
64
62
|
withUtils(
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
}),
|
|
74
|
-
),
|
|
63
|
+
withUndoRedo(
|
|
64
|
+
withPatches(
|
|
65
|
+
pluginUpdateValue(
|
|
66
|
+
editorActor.getSnapshot().context,
|
|
67
|
+
pluginUpdateSelection({
|
|
68
|
+
editorActor,
|
|
69
|
+
editor: e,
|
|
70
|
+
}),
|
|
75
71
|
),
|
|
76
72
|
),
|
|
77
73
|
),
|
|
@@ -72,10 +72,6 @@ export type InternalEditorEmittedEvent = EditorEmittedEvent | UnsetEvent
|
|
|
72
72
|
export type MutationEvent = {
|
|
73
73
|
type: 'mutation'
|
|
74
74
|
patches: Array<Patch>
|
|
75
|
-
/**
|
|
76
|
-
* @deprecated Use `value` instead
|
|
77
|
-
*/
|
|
78
|
-
snapshot: Array<PortableTextBlock> | undefined
|
|
79
75
|
value: Array<PortableTextBlock> | undefined
|
|
80
76
|
}
|
|
81
77
|
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
type AnyEventObject,
|
|
17
17
|
type CallbackLogicFunction,
|
|
18
18
|
} from 'xstate'
|
|
19
|
+
import {pluginWithoutHistory} from '../history/slate-plugin.without-history'
|
|
19
20
|
import {debugWithName} from '../internal-utils/debug'
|
|
20
21
|
import {validateValue} from '../internal-utils/validateValue'
|
|
21
22
|
import {toSlateBlock, VOID_CHILD_KEY} from '../internal-utils/values'
|
|
@@ -25,7 +26,6 @@ import type {
|
|
|
25
26
|
PortableTextSlateEditor,
|
|
26
27
|
} from '../types/editor'
|
|
27
28
|
import type {EditorSchema} from './editor-schema'
|
|
28
|
-
import {withoutSaving} from './plugins/createWithUndoRedo'
|
|
29
29
|
import {isChangingRemotely, withRemoteChanges} from './withChanges'
|
|
30
30
|
import {withoutPatching} from './withoutPatching'
|
|
31
31
|
|
|
@@ -582,7 +582,7 @@ function clearEditor({
|
|
|
582
582
|
hadSelection: boolean
|
|
583
583
|
}) {
|
|
584
584
|
Editor.withoutNormalizing(slateEditor, () => {
|
|
585
|
-
|
|
585
|
+
pluginWithoutHistory(slateEditor, () => {
|
|
586
586
|
withRemoteChanges(slateEditor, () => {
|
|
587
587
|
withoutPatching(slateEditor, () => {
|
|
588
588
|
if (doneSyncing) {
|
package/src/editor.ts
CHANGED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import {flatten} from 'lodash'
|
|
2
|
+
import {Editor, Transforms} from 'slate'
|
|
3
|
+
import {debugWithName} from '../internal-utils/debug'
|
|
4
|
+
import type {BehaviorOperationImplementation} from '../operations/behavior.operations'
|
|
5
|
+
import {getRemotePatches} from './remote-patches'
|
|
6
|
+
import {pluginRedoing, setIsRedoing} from './slate-plugin.redoing'
|
|
7
|
+
import {
|
|
8
|
+
pluginWithoutHistory,
|
|
9
|
+
setWithHistory,
|
|
10
|
+
} from './slate-plugin.without-history'
|
|
11
|
+
import {transformOperation} from './transform-operation'
|
|
12
|
+
|
|
13
|
+
const debug = debugWithName('behavior.operation.history.redo')
|
|
14
|
+
|
|
15
|
+
export const historyRedoOperationImplementation: BehaviorOperationImplementation<
|
|
16
|
+
'history.redo'
|
|
17
|
+
> = ({operation}) => {
|
|
18
|
+
const editor = operation.editor
|
|
19
|
+
const {redos} = editor.history
|
|
20
|
+
const remotePatches = getRemotePatches(editor)
|
|
21
|
+
|
|
22
|
+
if (redos.length > 0) {
|
|
23
|
+
const step = redos[redos.length - 1]
|
|
24
|
+
debug('Redoing', step)
|
|
25
|
+
if (step.operations.length > 0) {
|
|
26
|
+
const otherPatches = remotePatches.filter(
|
|
27
|
+
(item) => item.time >= step.timestamp,
|
|
28
|
+
)
|
|
29
|
+
let transformedOperations = step.operations
|
|
30
|
+
otherPatches.forEach((item) => {
|
|
31
|
+
transformedOperations = flatten(
|
|
32
|
+
transformedOperations.map((op) =>
|
|
33
|
+
transformOperation(
|
|
34
|
+
editor,
|
|
35
|
+
item.patch,
|
|
36
|
+
op,
|
|
37
|
+
item.snapshot,
|
|
38
|
+
item.previousSnapshot,
|
|
39
|
+
),
|
|
40
|
+
),
|
|
41
|
+
)
|
|
42
|
+
})
|
|
43
|
+
try {
|
|
44
|
+
Editor.withoutNormalizing(editor, () => {
|
|
45
|
+
pluginRedoing(editor, () => {
|
|
46
|
+
pluginWithoutHistory(editor, () => {
|
|
47
|
+
transformedOperations.forEach((op) => {
|
|
48
|
+
editor.apply(op)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
})
|
|
52
|
+
})
|
|
53
|
+
} catch (err) {
|
|
54
|
+
debug('Could not perform redo step', err)
|
|
55
|
+
remotePatches.splice(0, remotePatches.length)
|
|
56
|
+
Transforms.deselect(editor)
|
|
57
|
+
editor.history = {undos: [], redos: []}
|
|
58
|
+
setWithHistory(editor, true)
|
|
59
|
+
setIsRedoing(editor, false)
|
|
60
|
+
editor.onChange()
|
|
61
|
+
return
|
|
62
|
+
}
|
|
63
|
+
editor.history.undos.push(step)
|
|
64
|
+
editor.history.redos.pop()
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|