@portabletext/editor 1.52.8 → 1.53.1

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.
Files changed (53) hide show
  1. package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
  2. package/lib/_chunks-cjs/selector.is-selecting-entire-blocks.cjs +144 -6
  3. package/lib/_chunks-cjs/selector.is-selecting-entire-blocks.cjs.map +1 -1
  4. package/lib/_chunks-cjs/selector.is-selection-expanded.cjs +6 -140
  5. package/lib/_chunks-cjs/selector.is-selection-expanded.cjs.map +1 -1
  6. package/lib/_chunks-es/selector.get-text-before.js.map +1 -1
  7. package/lib/_chunks-es/selector.is-selecting-entire-blocks.js +148 -10
  8. package/lib/_chunks-es/selector.is-selecting-entire-blocks.js.map +1 -1
  9. package/lib/_chunks-es/selector.is-selection-expanded.js +6 -140
  10. package/lib/_chunks-es/selector.is-selection-expanded.js.map +1 -1
  11. package/lib/index.cjs +143 -97
  12. package/lib/index.cjs.map +1 -1
  13. package/lib/index.js +123 -77
  14. package/lib/index.js.map +1 -1
  15. package/lib/selectors/index.cjs +10 -10
  16. package/lib/selectors/index.cjs.map +1 -1
  17. package/lib/selectors/index.d.cts +11 -11
  18. package/lib/selectors/index.d.ts +11 -11
  19. package/lib/selectors/index.js +4 -4
  20. package/lib/selectors/index.js.map +1 -1
  21. package/package.json +13 -13
  22. package/src/behaviors/behavior.abstract.keyboard.ts +10 -0
  23. package/src/behaviors/behavior.abstract.split.ts +105 -87
  24. package/src/behaviors/behavior.core.insert-break.ts +14 -0
  25. package/src/behaviors/behavior.core.ts +1 -0
  26. package/src/internal-utils/key-is.ts +1 -0
  27. package/src/selectors/index.ts +13 -1
  28. package/src/selectors/selector.get-active-annotations.ts +2 -1
  29. package/src/selectors/selector.get-active-list-item.ts +1 -1
  30. package/src/selectors/selector.get-active-style.ts +1 -1
  31. package/src/selectors/selector.get-caret-word-selection.ts +1 -1
  32. package/src/selectors/selector.get-first-block.ts +14 -0
  33. package/src/selectors/selector.get-focus-block-object.ts +18 -0
  34. package/src/selectors/selector.get-focus-block.ts +23 -0
  35. package/src/selectors/selector.get-focus-child.ts +39 -0
  36. package/src/selectors/selector.get-focus-inline-object.ts +1 -1
  37. package/src/selectors/selector.get-focus-list-block.ts +18 -0
  38. package/src/selectors/selector.get-focus-span.ts +18 -0
  39. package/src/selectors/selector.get-focus-text-block.ts +18 -0
  40. package/src/selectors/selector.get-last-block.ts +16 -0
  41. package/src/selectors/selector.get-list-state.ts +2 -1
  42. package/src/selectors/selector.get-next-block.ts +38 -0
  43. package/src/selectors/selector.get-next-inline-object.ts +1 -1
  44. package/src/selectors/selector.get-previous-block.ts +35 -0
  45. package/src/selectors/selector.get-previous-inline-object.ts +1 -1
  46. package/src/selectors/selector.get-selected-blocks.ts +50 -0
  47. package/src/selectors/selector.get-selection-end-block.ts +4 -1
  48. package/src/selectors/selector.get-selection-start-block.ts +4 -1
  49. package/src/selectors/selector.get-text-before.ts +1 -1
  50. package/src/selectors/selector.get-trimmed-selection.ts +1 -1
  51. package/src/selectors/selector.is-active-annotation.ts +1 -1
  52. package/src/selectors/selector.is-selecting-entire-blocks.ts +2 -1
  53. package/src/selectors/selectors.ts +0 -299
@@ -1,111 +1,132 @@
1
1
  import {isTextBlock, parseBlock} from '../internal-utils/parse-blocks'
2
2
  import * as selectors from '../selectors'
3
- import {getSelectionStartPoint, isSelectionCollapsed} from '../utils'
4
- import {getBlockEndPoint} from '../utils/util.get-block-end-point'
5
- import {getSelectionEndPoint} from '../utils/util.get-selection-end-point'
6
- import {sliceBlocks} from '../utils/util.slice-blocks'
3
+ import * as utils from '../utils'
7
4
  import {raise} from './behavior.types.action'
8
5
  import {defineBehavior} from './behavior.types.behavior'
9
6
 
10
7
  export const abstractSplitBehaviors = [
8
+ /**
9
+ * You can't split an inline object.
10
+ */
11
+ defineBehavior({
12
+ on: 'split',
13
+ guard: ({snapshot}) =>
14
+ selectors.isSelectionCollapsed(snapshot) &&
15
+ selectors.getFocusInlineObject(snapshot),
16
+ actions: [],
17
+ }),
18
+
19
+ /**
20
+ * You can't split a block object.
21
+ */
22
+ defineBehavior({
23
+ on: 'split',
24
+ guard: ({snapshot}) =>
25
+ selectors.isSelectionCollapsed(snapshot) &&
26
+ selectors.getFocusBlockObject(snapshot),
27
+ actions: [],
28
+ }),
29
+
30
+ defineBehavior({
31
+ on: 'split',
32
+ guard: ({snapshot}) => {
33
+ const selection = snapshot.context.selection
34
+
35
+ if (!selection || utils.isSelectionCollapsed(selection)) {
36
+ return false
37
+ }
38
+
39
+ const selectionStartBlock = selectors.getSelectionStartBlock(snapshot)
40
+ const selectionEndBlock = selectors.getSelectionEndBlock(snapshot)
41
+
42
+ if (!selectionStartBlock || !selectionEndBlock) {
43
+ return false
44
+ }
45
+
46
+ if (
47
+ !isTextBlock(snapshot.context, selectionStartBlock.node) &&
48
+ isTextBlock(snapshot.context, selectionEndBlock.node)
49
+ ) {
50
+ return {selection}
51
+ }
52
+
53
+ return false
54
+ },
55
+ actions: [(_, {selection}) => [raise({type: 'delete', at: selection})]],
56
+ }),
57
+
58
+ defineBehavior({
59
+ on: 'split',
60
+ guard: ({snapshot}) => {
61
+ const selection = snapshot.context.selection
62
+
63
+ if (!selection || utils.isSelectionCollapsed(selection)) {
64
+ return false
65
+ }
66
+
67
+ return {selection}
68
+ },
69
+ actions: [
70
+ (_, {selection}) => [
71
+ raise({type: 'delete', at: selection}),
72
+ raise({type: 'split'}),
73
+ ],
74
+ ],
75
+ }),
76
+
11
77
  defineBehavior({
12
78
  on: 'split',
13
79
  guard: ({snapshot}) => {
14
- if (!snapshot.context.selection) {
80
+ const selection = snapshot.context.selection
81
+
82
+ if (!selection || !utils.isSelectionCollapsed(selection)) {
83
+ return false
84
+ }
85
+
86
+ const selectionStartPoint = utils.getSelectionStartPoint(selection)
87
+
88
+ const focusTextBlock = selectors.getFocusTextBlock(snapshot)
89
+
90
+ if (!focusTextBlock) {
15
91
  return false
16
92
  }
17
93
 
18
- const selectionStartPoint = getSelectionStartPoint(
19
- snapshot.context.selection,
20
- )
21
- const selectionEndPoint = getSelectionEndPoint(snapshot.context.selection)
22
-
23
- const focusTextBlock = selectors.getFocusTextBlock({
24
- ...snapshot,
25
- context: {
26
- ...snapshot.context,
27
- selection: {
28
- anchor: selectionStartPoint,
29
- focus: selectionEndPoint,
30
- },
31
- },
94
+ const blockEndPoint = utils.getBlockEndPoint({
95
+ context: snapshot.context,
96
+ block: focusTextBlock,
32
97
  })
33
98
 
34
- if (focusTextBlock) {
35
- const blockEndPoint = getBlockEndPoint({
36
- context: snapshot.context,
37
- block: focusTextBlock,
38
- })
39
- const newTextBlockSelection = {
40
- anchor: selectionEndPoint,
41
- focus: blockEndPoint,
42
- }
43
- const newTextBlock = parseBlock({
44
- block: sliceBlocks({
99
+ const newTextBlockSelection = {
100
+ anchor: selectionStartPoint,
101
+ focus: blockEndPoint,
102
+ }
103
+
104
+ const newTextBlock = parseBlock({
105
+ block: utils
106
+ .sliceBlocks({
45
107
  context: {
46
108
  ...snapshot.context,
47
109
  selection: newTextBlockSelection,
48
110
  },
49
111
  blocks: [focusTextBlock.node],
50
- }).at(0),
51
- context: snapshot.context,
52
- options: {refreshKeys: true, validateFields: true},
53
- })
54
-
55
- if (!newTextBlock || !isTextBlock(snapshot.context, newTextBlock)) {
56
- return false
57
- }
58
-
59
- return {
60
- newTextBlock,
61
- newTextBlockSelection,
62
- selection: {
63
- anchor: selectionStartPoint,
64
- focus: blockEndPoint,
65
- },
66
- }
67
- }
68
-
69
- const focusBlockObject = selectors.getFocusBlockObject({
70
- ...snapshot,
71
- context: {
72
- ...snapshot.context,
73
- selection: {
74
- anchor: selectionStartPoint,
75
- focus: selectionEndPoint,
76
- },
77
- },
112
+ })
113
+ .at(0),
114
+ context: snapshot.context,
115
+ options: {refreshKeys: true, validateFields: true},
78
116
  })
79
117
 
80
- if (focusBlockObject) {
81
- const newTextBlock = parseBlock({
82
- block: {
83
- _type: snapshot.context.schema.block.name,
84
- children: [],
85
- },
86
- context: snapshot.context,
87
- options: {refreshKeys: true, validateFields: true},
88
- })
89
-
90
- if (!newTextBlock) {
91
- return false
92
- }
93
-
94
- return {
95
- newTextBlock,
96
- newTextBlockSelection: {
97
- anchor: selectionEndPoint,
98
- focus: selectionEndPoint,
99
- },
100
- selection: snapshot.context.selection,
101
- }
118
+ if (!newTextBlock) {
119
+ return false
102
120
  }
103
121
 
104
- return false
122
+ return {
123
+ newTextBlock,
124
+ newTextBlockSelection,
125
+ }
105
126
  },
106
127
  actions: [
107
- (_, {newTextBlock, selection}) =>
108
- isSelectionCollapsed(selection)
128
+ (_, {newTextBlock, newTextBlockSelection}) =>
129
+ utils.isSelectionCollapsed(newTextBlockSelection)
109
130
  ? [
110
131
  raise({
111
132
  type: 'insert.block',
@@ -115,10 +136,7 @@ export const abstractSplitBehaviors = [
115
136
  }),
116
137
  ]
117
138
  : [
118
- raise({
119
- type: 'delete',
120
- at: selection,
121
- }),
139
+ raise({type: 'delete', at: newTextBlockSelection}),
122
140
  raise({
123
141
  type: 'insert.block',
124
142
  block: newTextBlock,
@@ -235,9 +235,23 @@ const breakingEntireBlocks = defineBehavior({
235
235
  ],
236
236
  })
237
237
 
238
+ const breakingInlineObject = defineBehavior({
239
+ on: 'insert.break',
240
+ guard: ({snapshot}) => {
241
+ const selectionCollapsed = selectors.isSelectionCollapsed(snapshot)
242
+ const focusInlineObject = selectors.getFocusInlineObject(snapshot)
243
+
244
+ return selectionCollapsed && focusInlineObject
245
+ },
246
+ actions: [
247
+ () => [raise({type: 'move.forward', distance: 1}), raise({type: 'split'})],
248
+ ],
249
+ })
250
+
238
251
  export const coreInsertBreakBehaviors = {
239
252
  breakingAtTheEndOfTextBlock,
240
253
  breakingAtTheStartOfTextBlock,
241
254
  breakingEntireDocument,
242
255
  breakingEntireBlocks,
256
+ breakingInlineObject,
243
257
  }
@@ -29,6 +29,7 @@ export const coreBehaviorsConfig = [
29
29
  coreInsertBreakBehaviors.breakingAtTheStartOfTextBlock,
30
30
  coreInsertBreakBehaviors.breakingEntireDocument,
31
31
  coreInsertBreakBehaviors.breakingEntireBlocks,
32
+ coreInsertBreakBehaviors.breakingInlineObject,
32
33
  ].map((behavior) => ({
33
34
  behavior,
34
35
  priority: corePriority,
@@ -1,4 +1,5 @@
1
1
  export const keyIs = {
2
+ break: (event) => event.key === 'Enter' && !event.shiftKey,
2
3
  lineBreak: (event) => event.key === 'Enter' && event.shiftKey,
3
4
  } satisfies Record<string, KeyboardEventPredicate>
4
5
 
@@ -7,15 +7,28 @@ export {getAnchorSpan} from './selector.get-anchor-span'
7
7
  export {getAnchorTextBlock} from './selector.get-anchor-text-block'
8
8
  export {getBlockOffsets} from './selector.get-block-offsets'
9
9
  export {getCaretWordSelection} from './selector.get-caret-word-selection'
10
+ export {getFirstBlock} from './selector.get-first-block'
11
+ export {getFocusBlock} from './selector.get-focus-block'
12
+ export {getFocusBlockObject} from './selector.get-focus-block-object'
13
+ export {getFocusChild} from './selector.get-focus-child'
10
14
  export {getFocusInlineObject} from './selector.get-focus-inline-object'
15
+ export {getFocusListBlock} from './selector.get-focus-list-block'
16
+ export {getFocusSpan} from './selector.get-focus-span'
17
+ export {getFocusTextBlock} from './selector.get-focus-text-block'
18
+ export {getLastBlock} from './selector.get-last-block'
11
19
  export {getListIndex} from './selector.get-list-state'
20
+ export {getNextBlock} from './selector.get-next-block'
12
21
  export {getNextInlineObject} from './selector.get-next-inline-object'
22
+ export {getPreviousBlock} from './selector.get-previous-block'
13
23
  export {getPreviousInlineObject} from './selector.get-previous-inline-object'
24
+ export {getSelectedBlocks} from './selector.get-selected-blocks'
14
25
  export {getSelectedSlice} from './selector.get-selected-slice'
15
26
  export {getSelectedSpans} from './selector.get-selected-spans'
16
27
  export {getSelectedTextBlocks} from './selector.get-selected-text-blocks'
17
28
  export {getSelection} from './selector.get-selection'
29
+ export {getSelectionEndBlock} from './selector.get-selection-end-block'
18
30
  export {getSelectionEndPoint} from './selector.get-selection-end-point'
31
+ export {getSelectionStartBlock} from './selector.get-selection-start-block'
19
32
  export {getSelectionStartPoint} from './selector.get-selection-start-point'
20
33
  export {getSelectionText} from './selector.get-selection-text'
21
34
  export {getBlockTextBefore} from './selector.get-text-before'
@@ -33,4 +46,3 @@ export {isPointBeforeSelection} from './selector.is-point-before-selection'
33
46
  export {isSelectingEntireBlocks} from './selector.is-selecting-entire-blocks'
34
47
  export {isSelectionCollapsed} from './selector.is-selection-collapsed'
35
48
  export {isSelectionExpanded} from './selector.is-selection-expanded'
36
- export * from './selectors'
@@ -1,9 +1,10 @@
1
1
  import type {PortableTextObject} from '@sanity/types'
2
2
  import type {EditorSelector} from '../editor/editor-selector'
3
3
  import {isTextBlock} from '../internal-utils/parse-blocks'
4
+ import {getFocusSpan} from './selector.get-focus-span'
5
+ import {getSelectedBlocks} from './selector.get-selected-blocks'
4
6
  import {getSelectedSpans} from './selector.get-selected-spans'
5
7
  import {isSelectionCollapsed} from './selector.is-selection-collapsed'
6
- import {getFocusSpan, getSelectedBlocks} from './selectors'
7
8
 
8
9
  /**
9
10
  * @public
@@ -1,7 +1,7 @@
1
1
  import type {PortableTextListBlock} from '@sanity/types'
2
2
  import type {EditorSelector} from '../editor/editor-selector'
3
3
  import {isTextBlock} from '../internal-utils/parse-blocks'
4
- import {getSelectedBlocks} from './selectors'
4
+ import {getSelectedBlocks} from './selector.get-selected-blocks'
5
5
 
6
6
  /**
7
7
  * @public
@@ -1,7 +1,7 @@
1
1
  import type {PortableTextTextBlock} from '@sanity/types'
2
2
  import type {EditorSelector} from '../editor/editor-selector'
3
3
  import {isTextBlock} from '../internal-utils/parse-blocks'
4
- import {getSelectedBlocks} from './selectors'
4
+ import {getSelectedBlocks} from './selector.get-selected-blocks'
5
5
 
6
6
  /**
7
7
  * @public
@@ -7,13 +7,13 @@ import {
7
7
  getBlockStartPoint,
8
8
  spanSelectionPointToBlockOffset,
9
9
  } from '../utils'
10
+ import {getFocusTextBlock} from './selector.get-focus-text-block'
10
11
  import {getNextInlineObject} from './selector.get-next-inline-object'
11
12
  import {getPreviousInlineObject} from './selector.get-previous-inline-object'
12
13
  import {getSelectionStartPoint} from './selector.get-selection-start-point'
13
14
  import {getSelectionText} from './selector.get-selection-text'
14
15
  import {isSelectionCollapsed} from './selector.is-selection-collapsed'
15
16
  import {isSelectionExpanded} from './selector.is-selection-expanded'
16
- import {getFocusTextBlock} from './selectors'
17
17
 
18
18
  /**
19
19
  * @public
@@ -0,0 +1,14 @@
1
+ import type {PortableTextBlock} from '@sanity/types'
2
+ import type {EditorSelector} from '../editor/editor-selector'
3
+ import type {BlockPath} from '../types/paths'
4
+
5
+ /**
6
+ * @public
7
+ */
8
+ export const getFirstBlock: EditorSelector<
9
+ {node: PortableTextBlock; path: BlockPath} | undefined
10
+ > = (snapshot) => {
11
+ const node = snapshot.context.value[0]
12
+
13
+ return node ? {node, path: [{_key: node._key}]} : undefined
14
+ }
@@ -0,0 +1,18 @@
1
+ import type {PortableTextObject} from '@sanity/types'
2
+ import type {EditorSelector} from '../editor/editor-selector'
3
+ import {isTextBlock} from '../internal-utils/parse-blocks'
4
+ import type {BlockPath} from '../types/paths'
5
+ import {getFocusBlock} from './selector.get-focus-block'
6
+
7
+ /**
8
+ * @public
9
+ */
10
+ export const getFocusBlockObject: EditorSelector<
11
+ {node: PortableTextObject; path: BlockPath} | undefined
12
+ > = (snapshot) => {
13
+ const focusBlock = getFocusBlock(snapshot)
14
+
15
+ return focusBlock && !isTextBlock(snapshot.context, focusBlock.node)
16
+ ? {node: focusBlock.node, path: focusBlock.path}
17
+ : undefined
18
+ }
@@ -0,0 +1,23 @@
1
+ import type {PortableTextBlock} from '@sanity/types'
2
+ import type {EditorSelector} from '../editor/editor-selector'
3
+ import {getBlockKeyFromSelectionPoint} from '../selection/selection-point'
4
+ import type {BlockPath} from '../types/paths'
5
+
6
+ /**
7
+ * @public
8
+ */
9
+ export const getFocusBlock: EditorSelector<
10
+ {node: PortableTextBlock; path: BlockPath} | undefined
11
+ > = (snapshot) => {
12
+ if (!snapshot.context.selection) {
13
+ return undefined
14
+ }
15
+
16
+ const key = getBlockKeyFromSelectionPoint(snapshot.context.selection.focus)
17
+
18
+ const node = key
19
+ ? snapshot.context.value.find((block) => block._key === key)
20
+ : undefined
21
+
22
+ return node && key ? {node, path: [{_key: key}]} : undefined
23
+ }
@@ -0,0 +1,39 @@
1
+ import type {
2
+ KeyedSegment,
3
+ PortableTextObject,
4
+ PortableTextSpan,
5
+ } from '@sanity/types'
6
+ import type {EditorSelector} from '../editor/editor-selector'
7
+ import {getChildKeyFromSelectionPoint} from '../selection/selection-point'
8
+ import {getFocusTextBlock} from './selector.get-focus-text-block'
9
+
10
+ /**
11
+ * @public
12
+ */
13
+ export const getFocusChild: EditorSelector<
14
+ | {
15
+ node: PortableTextObject | PortableTextSpan
16
+ path: [KeyedSegment, 'children', KeyedSegment]
17
+ }
18
+ | undefined
19
+ > = (snapshot) => {
20
+ if (!snapshot.context.selection) {
21
+ return undefined
22
+ }
23
+
24
+ const focusBlock = getFocusTextBlock(snapshot)
25
+
26
+ if (!focusBlock) {
27
+ return undefined
28
+ }
29
+
30
+ const key = getChildKeyFromSelectionPoint(snapshot.context.selection.focus)
31
+
32
+ const node = key
33
+ ? focusBlock.node.children.find((span) => span._key === key)
34
+ : undefined
35
+
36
+ return node && key
37
+ ? {node, path: [...focusBlock.path, 'children', {_key: key}]}
38
+ : undefined
39
+ }
@@ -4,7 +4,7 @@ import {
4
4
  type PortableTextObject,
5
5
  } from '@sanity/types'
6
6
  import type {EditorSelector} from '../editor/editor-selector'
7
- import {getFocusChild} from './selectors'
7
+ import {getFocusChild} from './selector.get-focus-child'
8
8
 
9
9
  /**
10
10
  * @public
@@ -0,0 +1,18 @@
1
+ import type {PortableTextListBlock} from '@sanity/types'
2
+ import type {EditorSelector} from '../editor/editor-selector'
3
+ import {isListBlock} from '../internal-utils/parse-blocks'
4
+ import type {BlockPath} from '../types/paths'
5
+ import {getFocusTextBlock} from './selector.get-focus-text-block'
6
+
7
+ /**
8
+ * @public
9
+ */
10
+ export const getFocusListBlock: EditorSelector<
11
+ {node: PortableTextListBlock; path: BlockPath} | undefined
12
+ > = (snapshot) => {
13
+ const focusTextBlock = getFocusTextBlock(snapshot)
14
+
15
+ return focusTextBlock && isListBlock(snapshot.context, focusTextBlock.node)
16
+ ? {node: focusTextBlock.node, path: focusTextBlock.path}
17
+ : undefined
18
+ }
@@ -0,0 +1,18 @@
1
+ import type {KeyedSegment, PortableTextSpan} from '@sanity/types'
2
+ import type {EditorSelector} from '../editor/editor-selector'
3
+ import {isSpan} from '../internal-utils/parse-blocks'
4
+ import {getFocusChild} from './selector.get-focus-child'
5
+
6
+ /**
7
+ * @public
8
+ */
9
+ export const getFocusSpan: EditorSelector<
10
+ | {node: PortableTextSpan; path: [KeyedSegment, 'children', KeyedSegment]}
11
+ | undefined
12
+ > = (snapshot) => {
13
+ const focusChild = getFocusChild(snapshot)
14
+
15
+ return focusChild && isSpan(snapshot.context, focusChild.node)
16
+ ? {node: focusChild.node, path: focusChild.path}
17
+ : undefined
18
+ }
@@ -0,0 +1,18 @@
1
+ import type {PortableTextTextBlock} from '@sanity/types'
2
+ import type {EditorSelector} from '../editor/editor-selector'
3
+ import {isTextBlock} from '../internal-utils/parse-blocks'
4
+ import type {BlockPath} from '../types/paths'
5
+ import {getFocusBlock} from './selector.get-focus-block'
6
+
7
+ /**
8
+ * @public
9
+ */
10
+ export const getFocusTextBlock: EditorSelector<
11
+ {node: PortableTextTextBlock; path: BlockPath} | undefined
12
+ > = (snapshot) => {
13
+ const focusBlock = getFocusBlock(snapshot)
14
+
15
+ return focusBlock && isTextBlock(snapshot.context, focusBlock.node)
16
+ ? {node: focusBlock.node, path: focusBlock.path}
17
+ : undefined
18
+ }
@@ -0,0 +1,16 @@
1
+ import type {PortableTextBlock} from '@sanity/types'
2
+ import type {EditorSelector} from '../editor/editor-selector'
3
+ import type {BlockPath} from '../types/paths'
4
+
5
+ /**
6
+ * @public
7
+ */
8
+ export const getLastBlock: EditorSelector<
9
+ {node: PortableTextBlock; path: BlockPath} | undefined
10
+ > = (snapshot) => {
11
+ const node = snapshot.context.value[snapshot.context.value.length - 1]
12
+ ? snapshot.context.value[snapshot.context.value.length - 1]
13
+ : undefined
14
+
15
+ return node ? {node, path: [{_key: node._key}]} : undefined
16
+ }
@@ -2,7 +2,8 @@ import type {PortableTextTextBlock} from '@sanity/types'
2
2
  import type {EditorSelector} from '../editor/editor-selector'
3
3
  import {isTextBlock} from '../internal-utils/parse-blocks'
4
4
  import type {BlockPath} from '../types/paths'
5
- import {getFocusTextBlock, getPreviousBlock} from './selectors'
5
+ import {getFocusTextBlock} from './selector.get-focus-text-block'
6
+ import {getPreviousBlock} from './selector.get-previous-block'
6
7
 
7
8
  /**
8
9
  * @beta
@@ -0,0 +1,38 @@
1
+ import type {PortableTextBlock} from '@sanity/types'
2
+ import type {EditorSelector} from '../editor/editor-selector'
3
+ import type {BlockPath} from '../types/paths'
4
+ import {getSelectionEndBlock} from './selector.get-selection-end-block'
5
+
6
+ /**
7
+ * @public
8
+ */
9
+ export const getNextBlock: EditorSelector<
10
+ {node: PortableTextBlock; path: BlockPath} | undefined
11
+ > = (snapshot) => {
12
+ let nextBlock: {node: PortableTextBlock; path: BlockPath} | undefined
13
+ const selectionEndBlock = getSelectionEndBlock(snapshot)
14
+
15
+ if (!selectionEndBlock) {
16
+ return undefined
17
+ }
18
+
19
+ let foundSelectionEndBlock = false
20
+
21
+ for (const block of snapshot.context.value) {
22
+ if (block._key === selectionEndBlock.node._key) {
23
+ foundSelectionEndBlock = true
24
+ continue
25
+ }
26
+
27
+ if (foundSelectionEndBlock) {
28
+ nextBlock = {node: block, path: [{_key: block._key}]}
29
+ break
30
+ }
31
+ }
32
+
33
+ if (foundSelectionEndBlock && nextBlock) {
34
+ return nextBlock
35
+ }
36
+
37
+ return undefined
38
+ }
@@ -5,8 +5,8 @@ import {
5
5
  } from '@sanity/types'
6
6
  import type {EditorSelector} from '../editor/editor-selector'
7
7
  import {isSpan} from '../utils'
8
+ import {getFocusTextBlock} from './selector.get-focus-text-block'
8
9
  import {getSelectionEndPoint} from './selector.get-selection-end-point'
9
- import {getFocusTextBlock} from './selectors'
10
10
 
11
11
  /**
12
12
  * @public
@@ -0,0 +1,35 @@
1
+ import type {KeyedSegment, PortableTextBlock} from '@sanity/types'
2
+ import type {EditorSelector} from '../editor/editor-selector'
3
+ import type {BlockPath} from '../types/paths'
4
+ import {getSelectionStartBlock} from './selector.get-selection-start-block'
5
+
6
+ /**
7
+ * @public
8
+ */
9
+ export const getPreviousBlock: EditorSelector<
10
+ {node: PortableTextBlock; path: BlockPath} | undefined
11
+ > = (snapshot) => {
12
+ let previousBlock: {node: PortableTextBlock; path: [KeyedSegment]} | undefined
13
+ const selectionStartBlock = getSelectionStartBlock(snapshot)
14
+
15
+ if (!selectionStartBlock) {
16
+ return undefined
17
+ }
18
+
19
+ let foundSelectionStartBlock = false
20
+
21
+ for (const block of snapshot.context.value) {
22
+ if (block._key === selectionStartBlock.node._key) {
23
+ foundSelectionStartBlock = true
24
+ break
25
+ }
26
+
27
+ previousBlock = {node: block, path: [{_key: block._key}]}
28
+ }
29
+
30
+ if (foundSelectionStartBlock && previousBlock) {
31
+ return previousBlock
32
+ }
33
+
34
+ return undefined
35
+ }
@@ -5,8 +5,8 @@ import {
5
5
  } from '@sanity/types'
6
6
  import type {EditorSelector} from '../editor/editor-selector'
7
7
  import {isSpan} from '../utils'
8
+ import {getFocusTextBlock} from './selector.get-focus-text-block'
8
9
  import {getSelectionStartPoint} from './selector.get-selection-start-point'
9
- import {getFocusTextBlock} from './selectors'
10
10
 
11
11
  /**
12
12
  * @public