@portabletext/editor 2.19.2 → 2.20.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 +6 -24
- package/lib/_chunks-es/selector.is-at-the-start-of-block.js +2 -91
- package/lib/_chunks-es/selector.is-at-the-start-of-block.js.map +1 -1
- package/lib/_chunks-es/util.merge-text-blocks.js +78 -2
- package/lib/_chunks-es/util.merge-text-blocks.js.map +1 -1
- package/lib/_chunks-es/util.slice-text-block.js +1 -18
- package/lib/_chunks-es/util.slice-text-block.js.map +1 -1
- package/lib/index.js +44 -128
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.js +1 -2
- package/lib/plugins/index.js.map +1 -1
- package/lib/selectors/index.d.ts +2 -0
- package/lib/selectors/index.js +92 -4
- package/lib/selectors/index.js.map +1 -1
- package/lib/utils/index.js +18 -3
- package/lib/utils/index.js.map +1 -1
- package/package.json +11 -11
- package/src/behaviors/behavior.abstract.decorator.ts +2 -10
- package/src/behaviors/behavior.abstract.delete.ts +1 -30
- package/src/behaviors/behavior.types.event.ts +3 -10
- package/src/operations/behavior.operation.decorator.add.ts +38 -131
- package/src/selectors/selector.get-trimmed-selection.ts +2 -0
- package/lib/_chunks-es/util.child-selection-point-to-block-offset.js +0 -81
- package/lib/_chunks-es/util.child-selection-point-to-block-offset.js.map +0 -1
package/lib/utils/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
+
import { getBlockKeyFromSelectionPoint } from "../_chunks-es/util.get-text-block-text.js";
|
|
1
2
|
import { blockOffsetToSpanSelectionPoint, getBlockStartPoint, getSelectionEndPoint, getSelectionStartPoint, getTextBlockText, isKeyedSegment, sliceBlocks, spanSelectionPointToBlockOffset } from "../_chunks-es/util.get-text-block-text.js";
|
|
2
|
-
import {
|
|
3
|
+
import { childSelectionPointToBlockOffset } from "../_chunks-es/util.merge-text-blocks.js";
|
|
4
|
+
import { blockOffsetToBlockSelectionPoint, blockOffsetToSelectionPoint, blockOffsetsToSelection, mergeTextBlocks } from "../_chunks-es/util.merge-text-blocks.js";
|
|
3
5
|
import { isEqualSelectionPoints } from "../_chunks-es/util.is-empty-text-block.js";
|
|
4
6
|
import { getBlockEndPoint, isEmptyTextBlock, isSelectionCollapsed } from "../_chunks-es/util.is-empty-text-block.js";
|
|
5
7
|
import { isSpan } from "@portabletext/schema";
|
|
6
8
|
import { isSpan as isSpan2, isTextBlock } from "@portabletext/schema";
|
|
7
|
-
import { mergeTextBlocks } from "../_chunks-es/util.merge-text-blocks.js";
|
|
8
9
|
import { sliceTextBlock } from "../_chunks-es/util.slice-text-block.js";
|
|
9
|
-
import { selectionPointToBlockOffset } from "../_chunks-es/util.slice-text-block.js";
|
|
10
10
|
function isEqualSelections(a, b) {
|
|
11
11
|
return !a && !b ? !0 : !a || !b ? !1 : isEqualSelectionPoints(a.anchor, b.anchor) && isEqualSelectionPoints(a.focus, b.focus);
|
|
12
12
|
}
|
|
@@ -21,6 +21,21 @@ function reverseSelection(selection) {
|
|
|
21
21
|
backward: !0
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
+
function selectionPointToBlockOffset({
|
|
25
|
+
context,
|
|
26
|
+
selectionPoint
|
|
27
|
+
}) {
|
|
28
|
+
const blockKey = getBlockKeyFromSelectionPoint(selectionPoint);
|
|
29
|
+
return selectionPoint.path.length === 1 && blockKey !== void 0 ? {
|
|
30
|
+
path: [{
|
|
31
|
+
_key: blockKey
|
|
32
|
+
}],
|
|
33
|
+
offset: selectionPoint.offset
|
|
34
|
+
} : childSelectionPointToBlockOffset({
|
|
35
|
+
context,
|
|
36
|
+
selectionPoint
|
|
37
|
+
});
|
|
38
|
+
}
|
|
24
39
|
function splitTextBlock({
|
|
25
40
|
context,
|
|
26
41
|
block,
|
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.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 {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","
|
|
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;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.20.0",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -72,17 +72,17 @@
|
|
|
72
72
|
"slate": "0.118.1",
|
|
73
73
|
"slate-dom": "^0.118.1",
|
|
74
74
|
"slate-react": "0.118.2",
|
|
75
|
-
"xstate": "^5.
|
|
76
|
-
"@portabletext/block-tools": "^4.0.
|
|
77
|
-
"@portabletext/keyboard-shortcuts": "^2.0
|
|
75
|
+
"xstate": "^5.24.0",
|
|
76
|
+
"@portabletext/block-tools": "^4.0.1",
|
|
77
|
+
"@portabletext/keyboard-shortcuts": "^2.1.0",
|
|
78
78
|
"@portabletext/patches": "^2.0.0",
|
|
79
79
|
"@portabletext/schema": "^2.0.0"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@sanity/diff-match-patch": "^3.2.0",
|
|
83
|
-
"@sanity/pkg-utils": "^9.0.
|
|
84
|
-
"@sanity/schema": "^4.
|
|
85
|
-
"@sanity/types": "^4.
|
|
83
|
+
"@sanity/pkg-utils": "^9.0.3",
|
|
84
|
+
"@sanity/schema": "^4.14.1",
|
|
85
|
+
"@sanity/types": "^4.14.1",
|
|
86
86
|
"@types/debug": "^4.1.12",
|
|
87
87
|
"@types/lodash": "^4.17.20",
|
|
88
88
|
"@types/lodash.startcase": "^4.4.9",
|
|
@@ -106,14 +106,14 @@
|
|
|
106
106
|
"vite": "^7.1.12",
|
|
107
107
|
"vitest": "^4.0.6",
|
|
108
108
|
"vitest-browser-react": "^2.0.2",
|
|
109
|
-
"@portabletext/sanity-bridge": "1.2.
|
|
109
|
+
"@portabletext/sanity-bridge": "1.2.1",
|
|
110
110
|
"@portabletext/test": "^1.0.0",
|
|
111
111
|
"racejar": "2.0.0"
|
|
112
112
|
},
|
|
113
113
|
"peerDependencies": {
|
|
114
|
-
"@portabletext/sanity-bridge": "^1.2.
|
|
115
|
-
"@sanity/schema": "^4.
|
|
116
|
-
"@sanity/types": "^4.
|
|
114
|
+
"@portabletext/sanity-bridge": "^1.2.1",
|
|
115
|
+
"@sanity/schema": "^4.14.1",
|
|
116
|
+
"@sanity/types": "^4.14.1",
|
|
117
117
|
"react": "^18.3 || ^19",
|
|
118
118
|
"rxjs": "^7.8.2"
|
|
119
119
|
},
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {isActiveDecorator} from '../selectors/selector.is-active-decorator'
|
|
2
|
-
import {blockOffsetsToSelection} from '../utils/util.block-offsets-to-selection'
|
|
3
2
|
import {raise} from './behavior.types.action'
|
|
4
3
|
import {defineBehavior} from './behavior.types.behavior'
|
|
5
4
|
|
|
@@ -16,19 +15,12 @@ export const abstractDecoratorBehaviors = [
|
|
|
16
15
|
defineBehavior({
|
|
17
16
|
on: 'decorator.toggle',
|
|
18
17
|
guard: ({snapshot, event}) => {
|
|
19
|
-
|
|
20
|
-
? blockOffsetsToSelection({
|
|
21
|
-
context: snapshot.context,
|
|
22
|
-
offsets: event.at,
|
|
23
|
-
})
|
|
24
|
-
: null
|
|
25
|
-
|
|
26
|
-
if (manualSelection) {
|
|
18
|
+
if (event.at) {
|
|
27
19
|
return !isActiveDecorator(event.decorator)({
|
|
28
20
|
...snapshot,
|
|
29
21
|
context: {
|
|
30
22
|
...snapshot.context,
|
|
31
|
-
selection:
|
|
23
|
+
selection: event.at,
|
|
32
24
|
},
|
|
33
25
|
})
|
|
34
26
|
}
|
|
@@ -3,10 +3,8 @@ import {getFocusChild} from '../selectors/selector.get-focus-child'
|
|
|
3
3
|
import {getFocusTextBlock} from '../selectors/selector.get-focus-text-block'
|
|
4
4
|
import {getNextBlock} from '../selectors/selector.get-next-block'
|
|
5
5
|
import {getPreviousBlock} from '../selectors/selector.get-previous-block'
|
|
6
|
-
import {getTrimmedSelection} from '../selectors/selector.get-trimmed-selection'
|
|
7
6
|
import {isAtTheEndOfBlock} from '../selectors/selector.is-at-the-end-of-block'
|
|
8
7
|
import {isAtTheStartOfBlock} from '../selectors/selector.is-at-the-start-of-block'
|
|
9
|
-
import {blockOffsetsToSelection} from '../utils/util.block-offsets-to-selection'
|
|
10
8
|
import {getBlockEndPoint} from '../utils/util.get-block-end-point'
|
|
11
9
|
import {getBlockStartPoint} from '../utils/util.get-block-start-point'
|
|
12
10
|
import {isEmptyTextBlock} from '../utils/util.is-empty-text-block'
|
|
@@ -270,33 +268,6 @@ export const abstractDeleteBehaviors = [
|
|
|
270
268
|
}),
|
|
271
269
|
defineBehavior({
|
|
272
270
|
on: 'delete.text',
|
|
273
|
-
|
|
274
|
-
const selection = blockOffsetsToSelection({
|
|
275
|
-
context: snapshot.context,
|
|
276
|
-
offsets: event.at,
|
|
277
|
-
})
|
|
278
|
-
|
|
279
|
-
if (!selection) {
|
|
280
|
-
return false
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const trimmedSelection = getTrimmedSelection({
|
|
284
|
-
...snapshot,
|
|
285
|
-
context: {
|
|
286
|
-
...snapshot.context,
|
|
287
|
-
value: snapshot.context.value,
|
|
288
|
-
selection,
|
|
289
|
-
},
|
|
290
|
-
})
|
|
291
|
-
|
|
292
|
-
if (!trimmedSelection) {
|
|
293
|
-
return false
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
return {
|
|
297
|
-
selection: trimmedSelection,
|
|
298
|
-
}
|
|
299
|
-
},
|
|
300
|
-
actions: [(_, {selection}) => [raise({type: 'delete', at: selection})]],
|
|
271
|
+
actions: [({event}) => [raise({...event, type: 'delete'})]],
|
|
301
272
|
}),
|
|
302
273
|
]
|
|
@@ -2,7 +2,6 @@ import type {PortableTextBlock} from '@sanity/types'
|
|
|
2
2
|
import type {EventPosition} from '../internal-utils/event-position'
|
|
3
3
|
import type {MIMEType} from '../internal-utils/mime-type'
|
|
4
4
|
import type {OmitFromUnion, PickFromUnion, StrictExtract} from '../type-utils'
|
|
5
|
-
import type {BlockOffset} from '../types/block-offset'
|
|
6
5
|
import type {
|
|
7
6
|
BlockWithOptionalKey,
|
|
8
7
|
ChildWithOptionalKey,
|
|
@@ -130,10 +129,7 @@ export type SyntheticBehaviorEvent =
|
|
|
130
129
|
| {
|
|
131
130
|
type: StrictExtract<SyntheticBehaviorEventType, 'decorator.add'>
|
|
132
131
|
decorator: string
|
|
133
|
-
at?:
|
|
134
|
-
anchor: BlockOffset
|
|
135
|
-
focus: BlockOffset
|
|
136
|
-
}
|
|
132
|
+
at?: NonNullable<EditorSelection>
|
|
137
133
|
}
|
|
138
134
|
| {
|
|
139
135
|
type: StrictExtract<SyntheticBehaviorEventType, 'decorator.remove'>
|
|
@@ -268,7 +264,7 @@ type AbstractBehaviorEvent =
|
|
|
268
264
|
| {
|
|
269
265
|
type: StrictExtract<SyntheticBehaviorEventType, 'decorator.toggle'>
|
|
270
266
|
decorator: string
|
|
271
|
-
at?:
|
|
267
|
+
at?: NonNullable<EditorSelection>
|
|
272
268
|
}
|
|
273
269
|
| {
|
|
274
270
|
type: StrictExtract<SyntheticBehaviorEventType, 'delete.backward'>
|
|
@@ -288,10 +284,7 @@ type AbstractBehaviorEvent =
|
|
|
288
284
|
}
|
|
289
285
|
| {
|
|
290
286
|
type: StrictExtract<SyntheticBehaviorEventType, 'delete.text'>
|
|
291
|
-
at:
|
|
292
|
-
anchor: BlockOffset
|
|
293
|
-
focus: BlockOffset
|
|
294
|
-
}
|
|
287
|
+
at: NonNullable<EditorSelection>
|
|
295
288
|
}
|
|
296
289
|
| {
|
|
297
290
|
type: StrictExtract<SyntheticBehaviorEventType, 'deserialize'>
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import {Editor, Range, Text, Transforms} from 'slate'
|
|
2
|
-
import {KEY_TO_VALUE_ELEMENT} from '../editor/weakMaps'
|
|
3
|
-
import {slateRangeToSelection} from '../internal-utils/slate-utils'
|
|
4
2
|
import {toSlateRange} from '../internal-utils/to-slate-range'
|
|
5
|
-
import {fromSlateValue} from '../internal-utils/values'
|
|
6
|
-
import {getTrimmedSelection} from '../selectors/selector.get-trimmed-selection'
|
|
7
|
-
import {blockOffsetToSpanSelectionPoint} from '../utils/util.block-offset'
|
|
8
|
-
import {blockOffsetsToSelection} from '../utils/util.block-offsets-to-selection'
|
|
9
|
-
import {selectionPointToBlockOffset} from '../utils/util.selection-point-to-block-offset'
|
|
10
3
|
import type {BehaviorOperationImplementation} from './behavior.operations'
|
|
11
4
|
|
|
12
5
|
export const decoratorAddOperationImplementation: BehaviorOperationImplementation<
|
|
@@ -14,147 +7,61 @@ export const decoratorAddOperationImplementation: BehaviorOperationImplementatio
|
|
|
14
7
|
> = ({context, operation}) => {
|
|
15
8
|
const editor = operation.editor
|
|
16
9
|
const mark = operation.decorator
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
KEY_TO_VALUE_ELEMENT.get(editor),
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
const manualAnchor = operation.at?.anchor
|
|
24
|
-
? blockOffsetToSpanSelectionPoint({
|
|
25
|
-
context: {
|
|
26
|
-
...context,
|
|
27
|
-
value,
|
|
28
|
-
},
|
|
29
|
-
blockOffset: operation.at.anchor,
|
|
30
|
-
direction: 'backward',
|
|
31
|
-
})
|
|
32
|
-
: undefined
|
|
33
|
-
const manualFocus = operation.at?.focus
|
|
34
|
-
? blockOffsetToSpanSelectionPoint({
|
|
35
|
-
context: {
|
|
36
|
-
...context,
|
|
37
|
-
value,
|
|
38
|
-
},
|
|
39
|
-
blockOffset: operation.at.focus,
|
|
40
|
-
direction: 'forward',
|
|
41
|
-
})
|
|
42
|
-
: undefined
|
|
43
|
-
const manualSelection =
|
|
44
|
-
manualAnchor && manualFocus
|
|
45
|
-
? {
|
|
46
|
-
anchor: manualAnchor,
|
|
47
|
-
focus: manualFocus,
|
|
48
|
-
}
|
|
49
|
-
: undefined
|
|
50
|
-
|
|
51
|
-
const selection = manualSelection
|
|
52
|
-
? (toSlateRange({
|
|
10
|
+
|
|
11
|
+
let at = operation.at
|
|
12
|
+
? toSlateRange({
|
|
53
13
|
context: {
|
|
54
14
|
schema: context.schema,
|
|
55
15
|
value: operation.editor.value,
|
|
56
|
-
selection:
|
|
16
|
+
selection: operation.at,
|
|
57
17
|
},
|
|
58
18
|
blockIndexMap: operation.editor.blockIndexMap,
|
|
59
|
-
})
|
|
60
|
-
: editor.selection
|
|
19
|
+
})
|
|
20
|
+
: operation.editor.selection
|
|
61
21
|
|
|
62
|
-
if (!
|
|
63
|
-
|
|
22
|
+
if (!at) {
|
|
23
|
+
throw new Error('Unable to add decorator without a selection')
|
|
64
24
|
}
|
|
65
25
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
range: selection,
|
|
70
|
-
})
|
|
71
|
-
const anchorOffset = editorSelection
|
|
72
|
-
? selectionPointToBlockOffset({
|
|
73
|
-
context: {
|
|
74
|
-
...context,
|
|
75
|
-
value,
|
|
76
|
-
},
|
|
77
|
-
selectionPoint: editorSelection.anchor,
|
|
78
|
-
})
|
|
79
|
-
: undefined
|
|
80
|
-
const focusOffset = editorSelection
|
|
81
|
-
? selectionPointToBlockOffset({
|
|
82
|
-
context: {
|
|
83
|
-
...context,
|
|
84
|
-
value,
|
|
85
|
-
},
|
|
86
|
-
selectionPoint: editorSelection.focus,
|
|
87
|
-
})
|
|
88
|
-
: undefined
|
|
26
|
+
if (Range.isExpanded(at)) {
|
|
27
|
+
const rangeRef = Editor.rangeRef(editor, at, {affinity: 'inward'})
|
|
28
|
+
const [start, end] = Range.edges(at)
|
|
89
29
|
|
|
90
|
-
|
|
91
|
-
throw new Error('Unable to find anchor or focus offset')
|
|
92
|
-
}
|
|
30
|
+
const endAtEndOfNode = Editor.isEnd(editor, end, end.path)
|
|
93
31
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
// The value might have changed after splitting
|
|
103
|
-
const newValue = fromSlateValue(
|
|
104
|
-
editor.children,
|
|
105
|
-
context.schema.block.name,
|
|
106
|
-
KEY_TO_VALUE_ELEMENT.get(editor),
|
|
107
|
-
)
|
|
108
|
-
// We need to find the new selection from the original offsets because the
|
|
109
|
-
// split operation might have changed the value.
|
|
110
|
-
const newSelection = blockOffsetsToSelection({
|
|
111
|
-
context: {
|
|
112
|
-
...context,
|
|
113
|
-
value: newValue,
|
|
114
|
-
},
|
|
115
|
-
offsets: {anchor: anchorOffset, focus: focusOffset},
|
|
116
|
-
backward: editorSelection?.backward,
|
|
32
|
+
Transforms.splitNodes(editor, {
|
|
33
|
+
at: end,
|
|
34
|
+
match: Text.isText,
|
|
35
|
+
mode: 'lowest',
|
|
36
|
+
voids: false,
|
|
37
|
+
always: !endAtEndOfNode,
|
|
117
38
|
})
|
|
118
39
|
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
value: newValue,
|
|
128
|
-
},
|
|
129
|
-
decoratorState: editor.decoratorState,
|
|
40
|
+
const startAtStartOfNode = Editor.isStart(editor, start, start.path)
|
|
41
|
+
|
|
42
|
+
Transforms.splitNodes(editor, {
|
|
43
|
+
at: start,
|
|
44
|
+
match: Text.isText,
|
|
45
|
+
mode: 'lowest',
|
|
46
|
+
voids: false,
|
|
47
|
+
always: !startAtStartOfNode,
|
|
130
48
|
})
|
|
131
49
|
|
|
132
|
-
|
|
133
|
-
throw new Error('Unable to find trimmed selection')
|
|
134
|
-
}
|
|
50
|
+
at = rangeRef.unref()
|
|
135
51
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
value: operation.editor.value,
|
|
140
|
-
selection: trimmedSelection,
|
|
141
|
-
},
|
|
142
|
-
blockIndexMap: operation.editor.blockIndexMap,
|
|
143
|
-
})
|
|
52
|
+
if (!at) {
|
|
53
|
+
throw new Error('Unable to add decorator without a selection')
|
|
54
|
+
}
|
|
144
55
|
|
|
145
|
-
if (!
|
|
146
|
-
|
|
56
|
+
if (!operation.at) {
|
|
57
|
+
Transforms.select(editor, at)
|
|
147
58
|
}
|
|
148
59
|
|
|
149
60
|
// Use new selection to find nodes to decorate
|
|
150
|
-
const splitTextNodes =
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
match: (node) => Text.isText(node),
|
|
155
|
-
}),
|
|
156
|
-
]
|
|
157
|
-
: []
|
|
61
|
+
const splitTextNodes = Editor.nodes(editor, {
|
|
62
|
+
at,
|
|
63
|
+
match: Text.isText,
|
|
64
|
+
})
|
|
158
65
|
|
|
159
66
|
for (const [node, path] of splitTextNodes) {
|
|
160
67
|
const marks = [
|
|
@@ -172,7 +79,7 @@ export const decoratorAddOperationImplementation: BehaviorOperationImplementatio
|
|
|
172
79
|
} else {
|
|
173
80
|
const selectedSpan = Array.from(
|
|
174
81
|
Editor.nodes(editor, {
|
|
175
|
-
at
|
|
82
|
+
at,
|
|
176
83
|
match: (node) => editor.isTextSpan(node),
|
|
177
84
|
}),
|
|
178
85
|
)?.at(0)
|
|
@@ -181,7 +88,7 @@ export const decoratorAddOperationImplementation: BehaviorOperationImplementatio
|
|
|
181
88
|
return
|
|
182
89
|
}
|
|
183
90
|
|
|
184
|
-
const [block, blockPath] = Editor.node(editor,
|
|
91
|
+
const [block, blockPath] = Editor.node(editor, at, {
|
|
185
92
|
depth: 1,
|
|
186
93
|
})
|
|
187
94
|
const lonelyEmptySpan =
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
import { blockOffsetToSpanSelectionPoint, getBlockKeyFromSelectionPoint, getChildKeyFromSelectionPoint } from "./util.get-text-block-text.js";
|
|
2
|
-
import { isTextBlock, isSpan } from "@portabletext/schema";
|
|
3
|
-
function blockOffsetToBlockSelectionPoint({
|
|
4
|
-
context,
|
|
5
|
-
blockOffset
|
|
6
|
-
}) {
|
|
7
|
-
let selectionPoint;
|
|
8
|
-
for (const block of context.value)
|
|
9
|
-
if (block._key === blockOffset.path[0]._key) {
|
|
10
|
-
selectionPoint = {
|
|
11
|
-
path: [{
|
|
12
|
-
_key: block._key
|
|
13
|
-
}],
|
|
14
|
-
offset: blockOffset.offset
|
|
15
|
-
};
|
|
16
|
-
break;
|
|
17
|
-
}
|
|
18
|
-
return selectionPoint;
|
|
19
|
-
}
|
|
20
|
-
function blockOffsetToSelectionPoint({
|
|
21
|
-
context,
|
|
22
|
-
blockOffset,
|
|
23
|
-
direction
|
|
24
|
-
}) {
|
|
25
|
-
return blockOffsetToSpanSelectionPoint({
|
|
26
|
-
context,
|
|
27
|
-
blockOffset,
|
|
28
|
-
direction
|
|
29
|
-
}) || blockOffsetToBlockSelectionPoint({
|
|
30
|
-
context,
|
|
31
|
-
blockOffset
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
|
-
function blockOffsetsToSelection({
|
|
35
|
-
context,
|
|
36
|
-
offsets,
|
|
37
|
-
backward
|
|
38
|
-
}) {
|
|
39
|
-
const anchor = blockOffsetToSelectionPoint({
|
|
40
|
-
context,
|
|
41
|
-
blockOffset: offsets.anchor,
|
|
42
|
-
direction: backward ? "backward" : "forward"
|
|
43
|
-
}), focus = blockOffsetToSelectionPoint({
|
|
44
|
-
context,
|
|
45
|
-
blockOffset: offsets.focus,
|
|
46
|
-
direction: backward ? "forward" : "backward"
|
|
47
|
-
});
|
|
48
|
-
return !anchor || !focus ? null : {
|
|
49
|
-
anchor,
|
|
50
|
-
focus,
|
|
51
|
-
backward
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
function childSelectionPointToBlockOffset({
|
|
55
|
-
context,
|
|
56
|
-
selectionPoint
|
|
57
|
-
}) {
|
|
58
|
-
let offset = 0;
|
|
59
|
-
const blockKey = getBlockKeyFromSelectionPoint(selectionPoint), childKey = getChildKeyFromSelectionPoint(selectionPoint);
|
|
60
|
-
if (!(!blockKey || !childKey)) {
|
|
61
|
-
for (const block of context.value)
|
|
62
|
-
if (block._key === blockKey && isTextBlock(context, block))
|
|
63
|
-
for (const child of block.children) {
|
|
64
|
-
if (child._key === childKey)
|
|
65
|
-
return {
|
|
66
|
-
path: [{
|
|
67
|
-
_key: block._key
|
|
68
|
-
}],
|
|
69
|
-
offset: offset + selectionPoint.offset
|
|
70
|
-
};
|
|
71
|
-
isSpan(context, child) && (offset += child.text.length);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
export {
|
|
76
|
-
blockOffsetToBlockSelectionPoint,
|
|
77
|
-
blockOffsetToSelectionPoint,
|
|
78
|
-
blockOffsetsToSelection,
|
|
79
|
-
childSelectionPointToBlockOffset
|
|
80
|
-
};
|
|
81
|
-
//# sourceMappingURL=util.child-selection-point-to-block-offset.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"util.child-selection-point-to-block-offset.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"],"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"],"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"],"mappings":";;AAOO,SAASA,iCAAiC;AAAA,EAC/CC;AAAAA,EACAC;AAIF,GAAqC;AACnC,MAAIC;AAEJ,aAAWC,SAASH,QAAQI;AAC1B,QAAID,MAAME,SAASJ,YAAYK,KAAK,CAAC,EAAED,MAAM;AAC3CH,uBAAiB;AAAA,QACfI,MAAM,CAAC;AAAA,UAACD,MAAMF,MAAME;AAAAA,QAAAA,CAAK;AAAA,QACzBE,QAAQN,YAAYM;AAAAA,MAAAA;AAEtB;AAAA,IACF;AAGF,SAAOL;AACT;AClBO,SAASM,4BAA4B;AAAA,EAC1CR;AAAAA,EACAC;AAAAA,EACAQ;AAKF,GAAqC;AAOnC,SAN2BC,gCAAgC;AAAA,IACzDV;AAAAA,IACAC;AAAAA,IACAQ;AAAAA,EAAAA,CACD,KAGQV,iCAAiC;AAAA,IACtCC;AAAAA,IACAC;AAAAA,EAAAA,CACD;AAIL;ACxBO,SAASU,wBAAwB;AAAA,EACtCX;AAAAA,EACAY;AAAAA,EACAC;AAKF,GAAoB;AAClB,QAAMC,SAASN,4BAA4B;AAAA,IACzCR;AAAAA,IACAC,aAAaW,QAAQE;AAAAA,IACrBL,WAAWI,WAAW,aAAa;AAAA,EAAA,CACpC,GACKE,QAAQP,4BAA4B;AAAA,IACxCR;AAAAA,IACAC,aAAaW,QAAQG;AAAAA,IACrBN,WAAWI,WAAW,YAAY;AAAA,EAAA,CACnC;AAED,SAAI,CAACC,UAAU,CAACC,QACP,OAGF;AAAA,IACLD;AAAAA,IACAC;AAAAA,IACAF;AAAAA,EAAAA;AAEJ;ACzBO,SAASG,iCAAiC;AAAA,EAC/ChB;AAAAA,EACAE;AAIF,GAA4B;AAC1B,MAAIK,SAAS;AAEb,QAAMU,WAAWC,8BAA8BhB,cAAc,GACvDiB,WAAWC,8BAA8BlB,cAAc;AAE7D,MAAI,EAAA,CAACe,YAAY,CAACE;AAIlB,eAAWhB,SAASH,QAAQI;AAC1B,UAAID,MAAME,SAASY,YAIdI,YAAYrB,SAASG,KAAK;AAI/B,mBAAWmB,SAASnB,MAAMoB,UAAU;AAClC,cAAID,MAAMjB,SAASc;AACjB,mBAAO;AAAA,cACLb,MAAM,CAAC;AAAA,gBAACD,MAAMF,MAAME;AAAAA,cAAAA,CAAK;AAAA,cACzBE,QAAQA,SAASL,eAAeK;AAAAA,YAAAA;AAIhCiB,iBAAOxB,SAASsB,KAAK,MACvBf,UAAUe,MAAMG,KAAKC;AAAAA,QAEzB;AAAA;AAEJ;"}
|