@portabletext/editor 2.19.3 → 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.
@@ -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 { blockOffsetToBlockSelectionPoint, blockOffsetToSelectionPoint, blockOffsetsToSelection, childSelectionPointToBlockOffset } from "../_chunks-es/util.child-selection-point-to-block-offset.js";
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,
@@ -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","splitTextBlock","context","block","point","firstChild","children","at","lastChild","length","before","sliceTextBlock","schema","path","_key","offset","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,eAAe;AAAA,EAC7BC;AAAAA,EACAC;AAAAA,EACAC;AAKF,GAA8E;AAC5E,QAAMC,aAAaF,MAAMG,SAASC,GAAG,CAAC,GAChCC,YAAYL,MAAMG,SAASC,GAAGJ,MAAMG,SAASG,SAAS,CAAC;AAE7D,MAAI,CAACJ,cAAc,CAACG;AAClB;AAGF,QAAME,SAASC,eAAe;AAAA,IAC5BT,SAAS;AAAA,MACPU,QAAQV,QAAQU;AAAAA,MAChBb,WAAW;AAAA,QACTH,QAAQ;AAAA,UACNiB,MAAM,CAAC;AAAA,YAACC,MAAMX,MAAMW;AAAAA,UAAAA,GAAO,YAAY;AAAA,YAACA,MAAMT,WAAWS;AAAAA,UAAAA,CAAK;AAAA,UAC9DC,QAAQ;AAAA,QAAA;AAAA,QAEVlB,OAAOO;AAAAA,MAAAA;AAAAA,IACT;AAAA,IAEFD;AAAAA,EAAAA,CACD,GACKa,QAAQL,eAAe;AAAA,IAC3BT,SAAS;AAAA,MACPU,QAAQV,QAAQU;AAAAA,MAChBb,WAAW;AAAA,QACTH,QAAQQ;AAAAA,QACRP,OAAO;AAAA,UACLgB,MAAM,CAAC;AAAA,YAACC,MAAMX,MAAMW;AAAAA,UAAAA,GAAO,YAAY;AAAA,YAACA,MAAMN,UAAUM;AAAAA,UAAAA,CAAK;AAAA,UAC7DC,QAAQE,OAAOf,SAASM,SAAS,IAAIA,UAAUU,KAAKT,SAAS;AAAA,QAAA;AAAA,MAC/D;AAAA,IACF;AAAA,IAEFN;AAAAA,EAAAA,CACD;AAED,SAAO;AAAA,IAACO;AAAAA,IAAQM;AAAAA,EAAAA;AAClB;"}
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.19.3",
3
+ "version": "2.20.0",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -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
- const manualSelection = event.at
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: manualSelection,
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
- guard: ({snapshot, event}) => {
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?: {anchor: BlockOffset; focus: BlockOffset}
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
- const value = fromSlateValue(
18
- editor.children,
19
- context.schema.block.name,
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: manualSelection,
16
+ selection: operation.at,
57
17
  },
58
18
  blockIndexMap: operation.editor.blockIndexMap,
59
- }) ?? editor.selection)
60
- : editor.selection
19
+ })
20
+ : operation.editor.selection
61
21
 
62
- if (!selection) {
63
- return
22
+ if (!at) {
23
+ throw new Error('Unable to add decorator without a selection')
64
24
  }
65
25
 
66
- const editorSelection = slateRangeToSelection({
67
- schema: context.schema,
68
- editor,
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
- if (!anchorOffset || !focusOffset) {
91
- throw new Error('Unable to find anchor or focus offset')
92
- }
30
+ const endAtEndOfNode = Editor.isEnd(editor, end, end.path)
93
31
 
94
- if (Range.isExpanded(selection)) {
95
- // Split if needed
96
- Transforms.setNodes(
97
- editor,
98
- {},
99
- {at: selection, match: Text.isText, split: true, hanging: true},
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 trimmedSelection = getTrimmedSelection({
120
- blockIndexMap: editor.blockIndexMap,
121
- context: {
122
- converters: [],
123
- keyGenerator: context.keyGenerator,
124
- readOnly: false,
125
- schema: context.schema,
126
- selection: newSelection,
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
- if (!trimmedSelection) {
133
- throw new Error('Unable to find trimmed selection')
134
- }
50
+ at = rangeRef.unref()
135
51
 
136
- const newRange = toSlateRange({
137
- context: {
138
- schema: context.schema,
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 (!newRange) {
146
- throw new Error('Unable to find new selection')
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 = Range.isRange(newRange)
151
- ? [
152
- ...Editor.nodes(editor, {
153
- at: newRange,
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: selection,
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, selection, {
91
+ const [block, blockPath] = Editor.node(editor, at, {
185
92
  depth: 1,
186
93
  })
187
94
  const lonelyEmptySpan =
@@ -14,6 +14,8 @@ import {isSelectionCollapsed} from './selector.is-selection-collapsed'
14
14
 
15
15
  /**
16
16
  * @public
17
+ *
18
+ * @deprecated - Will be removed in the next major version.
17
19
  */
18
20
  export const getTrimmedSelection: EditorSelector<EditorSelection> = (
19
21
  snapshot,
@@ -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;"}