@portabletext/editor 1.23.0 → 1.25.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.
Files changed (71) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs +249 -62
  2. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  3. package/lib/_chunks-cjs/{selector.is-selection-collapsed.cjs → selector.is-active-style.cjs} +158 -3
  4. package/lib/_chunks-cjs/selector.is-active-style.cjs.map +1 -0
  5. package/lib/_chunks-cjs/util.slice-blocks.cjs +23 -9
  6. package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
  7. package/lib/_chunks-es/behavior.core.js +225 -38
  8. package/lib/_chunks-es/behavior.core.js.map +1 -1
  9. package/lib/_chunks-es/{selector.is-selection-collapsed.js → selector.is-active-style.js} +159 -4
  10. package/lib/_chunks-es/selector.is-active-style.js.map +1 -0
  11. package/lib/_chunks-es/util.slice-blocks.js +23 -9
  12. package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
  13. package/lib/behaviors/index.cjs +27 -27
  14. package/lib/behaviors/index.cjs.map +1 -1
  15. package/lib/behaviors/index.d.cts +2830 -139
  16. package/lib/behaviors/index.d.ts +2830 -139
  17. package/lib/behaviors/index.js +1 -1
  18. package/lib/index.cjs +695 -526
  19. package/lib/index.cjs.map +1 -1
  20. package/lib/index.d.cts +8950 -246
  21. package/lib/index.d.ts +8950 -246
  22. package/lib/index.js +696 -525
  23. package/lib/index.js.map +1 -1
  24. package/lib/selectors/index.cjs +24 -171
  25. package/lib/selectors/index.cjs.map +1 -1
  26. package/lib/selectors/index.d.cts +73 -0
  27. package/lib/selectors/index.d.ts +73 -0
  28. package/lib/selectors/index.js +3 -151
  29. package/lib/selectors/index.js.map +1 -1
  30. package/package.json +11 -10
  31. package/src/behavior-actions/behavior.action.data-transfer-set.ts +7 -0
  32. package/src/behavior-actions/behavior.action.insert-blocks.ts +61 -0
  33. package/src/behavior-actions/behavior.actions.ts +159 -83
  34. package/src/behaviors/behavior.core.annotations.ts +29 -0
  35. package/src/behaviors/behavior.core.block-objects.ts +13 -13
  36. package/src/behaviors/behavior.core.decorators.ts +19 -0
  37. package/src/behaviors/behavior.core.deserialize.ts +46 -0
  38. package/src/behaviors/behavior.core.lists.ts +57 -23
  39. package/src/behaviors/behavior.core.serialize.ts +44 -0
  40. package/src/behaviors/behavior.core.style.ts +19 -0
  41. package/src/behaviors/behavior.core.ts +19 -0
  42. package/src/behaviors/behavior.types.ts +126 -89
  43. package/src/converters/converter.json.ts +53 -0
  44. package/src/converters/converter.portable-text.deserialize.test.ts +686 -0
  45. package/src/converters/converter.portable-text.ts +59 -0
  46. package/src/converters/converter.text-html.deserialize.test.ts +349 -0
  47. package/src/converters/converter.text-html.serialize.test.ts +233 -0
  48. package/src/converters/converter.text-html.ts +61 -0
  49. package/src/converters/converter.text-plain.test.ts +241 -0
  50. package/src/converters/converter.text-plain.ts +91 -0
  51. package/src/converters/converter.ts +65 -0
  52. package/src/converters/converters.ts +11 -0
  53. package/src/editor/Editable.tsx +3 -13
  54. package/src/editor/create-editor.ts +48 -6
  55. package/src/editor/editor-machine.ts +56 -2
  56. package/src/editor/editor-selector.ts +1 -0
  57. package/src/editor/editor-snapshot.ts +5 -0
  58. package/src/editor/plugins/create-with-event-listeners.ts +82 -106
  59. package/src/internal-utils/asserters.ts +9 -0
  60. package/src/internal-utils/mime-type.ts +1 -0
  61. package/src/internal-utils/parse-blocks.ts +136 -0
  62. package/src/internal-utils/test-key-generator.ts +9 -0
  63. package/src/selectors/selector.get-selected-spans.test.ts +1 -0
  64. package/src/selectors/selector.get-selection-text.test.ts +1 -0
  65. package/src/selectors/selector.is-active-decorator.test.ts +1 -0
  66. package/src/utils/util.slice-blocks.test.ts +87 -0
  67. package/src/utils/util.slice-blocks.ts +27 -10
  68. package/lib/_chunks-cjs/selector.is-selection-collapsed.cjs.map +0 -1
  69. package/lib/_chunks-es/selector.is-selection-collapsed.js.map +0 -1
  70. package/src/editor/plugins/__tests__/createWithInsertData.test.tsx +0 -181
  71. package/src/editor/plugins/createWithInsertData.ts +0 -425
@@ -1,4 +1,5 @@
1
1
  import type {PortableTextBlock} from '@sanity/types'
2
+ import type {Converter} from '../converters/converter'
2
3
  import {toPortableTextRange} from '../internal-utils/ranges'
3
4
  import {fromSlateValue} from '../internal-utils/values'
4
5
  import {KEY_TO_VALUE_ELEMENT} from '../internal-utils/weakMaps'
@@ -11,6 +12,7 @@ import {getActiveDecorators} from './get-active-decorators'
11
12
  */
12
13
  export type EditorContext = {
13
14
  activeDecorators: Array<string>
15
+ converters: Array<Converter>
14
16
  keyGenerator: () => string
15
17
  schema: EditorSchema
16
18
  selection: EditorSelection
@@ -25,10 +27,12 @@ export type EditorSnapshot = {
25
27
  }
26
28
 
27
29
  export function createEditorSnapshot({
30
+ converters,
28
31
  editor,
29
32
  keyGenerator,
30
33
  schema,
31
34
  }: {
35
+ converters: Array<Converter>
32
36
  editor: PortableTextSlateEditor
33
37
  keyGenerator: () => string
34
38
  schema: EditorSchema
@@ -45,6 +49,7 @@ export function createEditorSnapshot({
45
49
  schema,
46
50
  slateEditorInstance: editor,
47
51
  }),
52
+ converters,
48
53
  keyGenerator,
49
54
  schema,
50
55
  selection,
@@ -17,123 +17,55 @@ export function createWithEventListeners(
17
17
  subscriptions.push(() => {
18
18
  const subscription = editorActor.on('*', (event) => {
19
19
  switch (event.type) {
20
- case 'annotation.add': {
21
- editorActor.send({
22
- type: 'behavior event',
23
- behaviorEvent: {
24
- type: 'annotation.add',
25
- annotation: event.annotation,
26
- },
27
- editor,
28
- })
29
- break
30
- }
31
- case 'annotation.remove': {
32
- editorActor.send({
33
- type: 'behavior event',
34
- behaviorEvent: {
35
- type: 'annotation.remove',
36
- annotation: event.annotation,
37
- },
38
- editor,
39
- })
40
- break
41
- }
42
- case 'blur': {
43
- editorActor.send({
44
- type: 'behavior event',
45
- behaviorEvent: {
46
- type: 'blur',
47
- },
48
- editor,
49
- })
50
- break
51
- }
52
- case 'custom.*': {
20
+ case 'custom.*':
53
21
  editorActor.send({
54
22
  type: 'custom behavior event',
55
23
  behaviorEvent: event.event,
56
24
  editor,
57
25
  })
58
26
  break
59
- }
60
- case 'decorator.toggle': {
61
- editorActor.send({
62
- type: 'behavior event',
63
- behaviorEvent: {
64
- type: 'decorator.toggle',
65
- decorator: event.decorator,
66
- },
67
- editor,
68
- })
69
- break
70
- }
71
- case 'focus': {
72
- editorActor.send({
73
- type: 'behavior event',
74
- behaviorEvent: {
75
- type: 'focus',
76
- },
77
- editor,
78
- })
79
- break
80
- }
81
- case 'insert.block object': {
82
- editorActor.send({
83
- type: 'behavior event',
84
- behaviorEvent: {
85
- type: 'insert.block object',
86
- placement: event.placement,
87
- blockObject: event.blockObject,
88
- },
89
- editor,
90
- })
91
- break
92
- }
93
- case 'insert.inline object': {
94
- editorActor.send({
95
- type: 'behavior event',
96
- behaviorEvent: {
97
- type: 'insert.inline object',
98
- inlineObject: event.inlineObject,
99
- },
100
- editor,
101
- })
102
- break
103
- }
104
- case 'list item.toggle': {
105
- editorActor.send({
106
- type: 'behavior event',
107
- behaviorEvent: {
108
- type: 'list item.toggle',
109
- listItem: event.listItem,
110
- },
111
- editor,
112
- })
113
- break
114
- }
115
- case 'select': {
116
- editorActor.send({
117
- type: 'behavior event',
118
- behaviorEvent: {
119
- type: 'select',
120
- selection: event.selection,
121
- },
122
- editor,
123
- })
124
- break
125
- }
126
- case 'style.toggle': {
27
+
28
+ case 'annotation.add':
29
+ case 'annotation.remove':
30
+ case 'annotation.toggle':
31
+ case 'blur':
32
+ case 'data transfer.set':
33
+ case 'decorator.add':
34
+ case 'decorator.remove':
35
+ case 'decorator.toggle':
36
+ case 'delete.backward':
37
+ case 'delete.block':
38
+ case 'delete.forward':
39
+ case 'delete.text':
40
+ case 'deserialization.failure':
41
+ case 'deserialization.success':
42
+ case 'focus':
43
+ case 'insert.block object':
44
+ case 'insert.inline object':
45
+ case 'insert.span':
46
+ case 'insert.text block':
47
+ case 'list item.add':
48
+ case 'list item.remove':
49
+ case 'list item.toggle':
50
+ case 'move.block':
51
+ case 'move.block down':
52
+ case 'move.block up':
53
+ case 'select':
54
+ case 'select.next block':
55
+ case 'select.previous block':
56
+ case 'serialization.failure':
57
+ case 'serialization.success':
58
+ case 'style.add':
59
+ case 'style.remove':
60
+ case 'style.toggle':
61
+ case 'text block.set':
62
+ case 'text block.unset':
127
63
  editorActor.send({
128
64
  type: 'behavior event',
129
- behaviorEvent: {
130
- type: 'style.toggle',
131
- style: event.style,
132
- },
65
+ behaviorEvent: event,
133
66
  editor,
134
67
  })
135
68
  break
136
- }
137
69
  }
138
70
  })
139
71
 
@@ -146,9 +78,11 @@ export function createWithEventListeners(
146
78
  deleteBackward,
147
79
  deleteForward,
148
80
  insertBreak,
81
+ insertData,
149
82
  insertSoftBreak,
150
83
  insertText,
151
84
  select,
85
+ setFragmentData,
152
86
  } = editor
153
87
 
154
88
  editor.deleteBackward = (unit) => {
@@ -201,6 +135,23 @@ export function createWithEventListeners(
201
135
  return
202
136
  }
203
137
 
138
+ editor.insertData = (dataTransfer) => {
139
+ if (isApplyingBehaviorActions(editor)) {
140
+ insertData(dataTransfer)
141
+ return
142
+ }
143
+
144
+ editorActor.send({
145
+ type: 'behavior event',
146
+ behaviorEvent: {
147
+ type: 'deserialize',
148
+ dataTransfer,
149
+ },
150
+ editor,
151
+ })
152
+ return
153
+ }
154
+
204
155
  editor.insertSoftBreak = () => {
205
156
  if (isApplyingBehaviorActions(editor)) {
206
157
  insertSoftBreak()
@@ -268,6 +219,31 @@ export function createWithEventListeners(
268
219
  return
269
220
  }
270
221
 
222
+ editor.setFragmentData = (dataTransfer, originEvent) => {
223
+ if (originEvent === 'drag') {
224
+ setFragmentData(dataTransfer)
225
+ return
226
+ }
227
+
228
+ if (isApplyingBehaviorActions(editor)) {
229
+ setFragmentData(dataTransfer)
230
+ return
231
+ }
232
+
233
+ dataTransfer.clearData()
234
+
235
+ editorActor.send({
236
+ type: 'behavior event',
237
+ behaviorEvent: {
238
+ type: 'serialize',
239
+ dataTransfer,
240
+ originEvent: originEvent ?? 'unknown',
241
+ },
242
+ editor,
243
+ })
244
+ return
245
+ }
246
+
271
247
  return editor
272
248
  }
273
249
  }
@@ -0,0 +1,9 @@
1
+ import type {TypedObject} from '@sanity/types'
2
+
3
+ export function isTypedObject(object: unknown): object is TypedObject {
4
+ return isRecord(object) && typeof object._type === 'string'
5
+ }
6
+
7
+ function isRecord(value: unknown): value is Record<string, unknown> {
8
+ return !!value && (typeof value === 'object' || typeof value === 'function')
9
+ }
@@ -0,0 +1 @@
1
+ export type MIMEType = `${string}/${string}`
@@ -0,0 +1,136 @@
1
+ import {
2
+ isPortableTextSpan,
3
+ isPortableTextTextBlock,
4
+ type PortableTextBlock,
5
+ } from '@sanity/types'
6
+ import type {EditorContext} from '../editor/editor-snapshot'
7
+ import {isTypedObject} from './asserters'
8
+
9
+ export function parseBlock({
10
+ context,
11
+ block,
12
+ }: {
13
+ context: Pick<EditorContext, 'keyGenerator' | 'schema'>
14
+ block: unknown
15
+ }): PortableTextBlock | undefined {
16
+ if (!isTypedObject(block)) {
17
+ return undefined
18
+ }
19
+
20
+ if (
21
+ block._type !== context.schema.block.name &&
22
+ !context.schema.blockObjects.some(
23
+ (blockObject) => blockObject.name === block._type,
24
+ )
25
+ ) {
26
+ return undefined
27
+ }
28
+
29
+ if (!isPortableTextTextBlock(block)) {
30
+ return {
31
+ ...block,
32
+ _key: context.keyGenerator(),
33
+ }
34
+ }
35
+
36
+ const markDefKeyMap = new Map<string, string>()
37
+ const markDefs = (block.markDefs ?? []).flatMap((markDef) => {
38
+ if (
39
+ context.schema.annotations.some(
40
+ (annotation) => annotation.name === markDef._type,
41
+ )
42
+ ) {
43
+ const _key = context.keyGenerator()
44
+ markDefKeyMap.set(markDef._key, _key)
45
+
46
+ return [
47
+ {
48
+ ...markDef,
49
+ _key,
50
+ },
51
+ ]
52
+ }
53
+
54
+ return []
55
+ })
56
+
57
+ const children = block.children.flatMap((child) => {
58
+ if (!isTypedObject(child)) {
59
+ return []
60
+ }
61
+
62
+ if (
63
+ child._type !== context.schema.span.name &&
64
+ !context.schema.inlineObjects.some(
65
+ (inlineObject) => inlineObject.name === child._type,
66
+ )
67
+ ) {
68
+ return []
69
+ }
70
+
71
+ if (!isPortableTextSpan(child)) {
72
+ return [
73
+ {
74
+ ...child,
75
+ _key: context.keyGenerator(),
76
+ },
77
+ ]
78
+ }
79
+
80
+ const marks = (child.marks ?? []).flatMap((mark) => {
81
+ if (markDefKeyMap.has(mark)) {
82
+ return [markDefKeyMap.get(mark)]
83
+ }
84
+
85
+ if (
86
+ context.schema.decorators.some((decorator) => decorator.value === mark)
87
+ ) {
88
+ return [mark]
89
+ }
90
+
91
+ return []
92
+ })
93
+
94
+ return [
95
+ {
96
+ ...child,
97
+ _key: context.keyGenerator(),
98
+ marks,
99
+ },
100
+ ]
101
+ })
102
+
103
+ const parsedBlock = {
104
+ ...block,
105
+ _key: context.keyGenerator(),
106
+ children:
107
+ children.length > 0
108
+ ? children
109
+ : [
110
+ {
111
+ _key: context.keyGenerator(),
112
+ _type: context.schema.span.name,
113
+ text: '',
114
+ marks: [],
115
+ },
116
+ ],
117
+ markDefs,
118
+ }
119
+
120
+ if (!context.schema.styles.find((style) => style.value === block.style)) {
121
+ const defaultStyle = context.schema.styles[0].value
122
+
123
+ if (defaultStyle !== undefined) {
124
+ parsedBlock.style = defaultStyle
125
+ } else {
126
+ delete parsedBlock.style
127
+ }
128
+ }
129
+
130
+ if (!context.schema.lists.find((list) => list.value === block.listItem)) {
131
+ delete parsedBlock.listItem
132
+ delete parsedBlock.level
133
+ }
134
+
135
+ return parsedBlock
136
+ }
@@ -0,0 +1,9 @@
1
+ export function createTestKeyGenerator() {
2
+ let index = 0
3
+
4
+ return function keyGenerator() {
5
+ const key = `k${index}`
6
+ index++
7
+ return key
8
+ }
9
+ }
@@ -6,6 +6,7 @@ test(getSelectedSpans.name, () => {
6
6
  function snapshot(selection: EditorSelection): EditorSnapshot {
7
7
  return {
8
8
  context: {
9
+ converters: [],
9
10
  schema: {} as EditorSchema,
10
11
  keyGenerator: () => '',
11
12
  activeDecorators: [],
@@ -6,6 +6,7 @@ test(getSelectionText.name, () => {
6
6
  function snapshot(selection: EditorSelection): EditorSnapshot {
7
7
  return {
8
8
  context: {
9
+ converters: [],
9
10
  schema: {} as EditorSchema,
10
11
  keyGenerator: () => '',
11
12
  activeDecorators: [],
@@ -7,6 +7,7 @@ test(isActiveDecorator.name, () => {
7
7
  function snapshot(selection: EditorSelection): EditorSnapshot {
8
8
  return {
9
9
  context: {
10
+ converters: [],
10
11
  schema: {} as EditorSchema,
11
12
  keyGenerator: () => '',
12
13
  activeDecorators: [],
@@ -134,6 +134,24 @@ describe(sliceBlocks.name, () => {
134
134
  ).toEqual([b2])
135
135
  })
136
136
 
137
+ test('starting selection on a block object', () => {
138
+ expect(
139
+ sliceBlocks({
140
+ blocks,
141
+ selection: {
142
+ anchor: {
143
+ path: [{_key: b2._key}],
144
+ offset: 0,
145
+ },
146
+ focus: {
147
+ path: [{_key: b3._key}, 'children', {_key: b3.children[0]._key}],
148
+ offset: 3,
149
+ },
150
+ },
151
+ }),
152
+ ).toEqual([b2, b3])
153
+ })
154
+
137
155
  test('ending selection on a block object', () => {
138
156
  expect(
139
157
  sliceBlocks({
@@ -254,4 +272,73 @@ describe(sliceBlocks.name, () => {
254
272
  },
255
273
  ])
256
274
  })
275
+
276
+ test('starting on inline object', () => {
277
+ expect(
278
+ sliceBlocks({
279
+ blocks,
280
+ selection: {
281
+ anchor: {
282
+ path: [{_key: b4._key}, 'children', {_key: b4.children[1]._key}],
283
+ offset: 0,
284
+ },
285
+ focus: {
286
+ path: [{_key: b4._key}, 'children', {_key: b4.children[2]._key}],
287
+ offset: 4,
288
+ },
289
+ },
290
+ }),
291
+ ).toEqual([
292
+ {
293
+ ...b4,
294
+ children: [b4.children[1], b4.children[2]],
295
+ },
296
+ ])
297
+ })
298
+
299
+ test('ending on inline object', () => {
300
+ expect(
301
+ sliceBlocks({
302
+ blocks,
303
+ selection: {
304
+ anchor: {
305
+ path: [{_key: b4._key}, 'children', {_key: b4.children[0]._key}],
306
+ offset: 0,
307
+ },
308
+ focus: {
309
+ path: [{_key: b4._key}, 'children', {_key: b4.children[1]._key}],
310
+ offset: 0,
311
+ },
312
+ },
313
+ }),
314
+ ).toEqual([
315
+ {
316
+ ...b4,
317
+ children: [b4.children[0], b4.children[1]],
318
+ },
319
+ ])
320
+ })
321
+
322
+ test('starting and ending on inline object', () => {
323
+ expect(
324
+ sliceBlocks({
325
+ blocks,
326
+ selection: {
327
+ anchor: {
328
+ path: [{_key: b4._key}, 'children', {_key: b4.children[1]._key}],
329
+ offset: 0,
330
+ },
331
+ focus: {
332
+ path: [{_key: b4._key}, 'children', {_key: b4.children[1]._key}],
333
+ offset: 0,
334
+ },
335
+ },
336
+ }),
337
+ ).toEqual([
338
+ {
339
+ ...b4,
340
+ children: [b4.children[1]],
341
+ },
342
+ ])
343
+ })
257
344
  })
@@ -47,8 +47,20 @@ export function sliceBlocks({
47
47
  }
48
48
 
49
49
  for (const block of blocks) {
50
+ if (!isPortableTextTextBlock(block)) {
51
+ if (block._key === startBlockKey && block._key === endBlockKey) {
52
+ startBlock = block
53
+ break
54
+ }
55
+ }
56
+
50
57
  if (block._key === startBlockKey) {
51
- if (isPortableTextTextBlock(block) && startChildKey) {
58
+ if (!isPortableTextTextBlock(block)) {
59
+ startBlock = block
60
+ continue
61
+ }
62
+
63
+ if (startChildKey) {
52
64
  for (const child of block.children) {
53
65
  if (child._key === startChildKey) {
54
66
  if (isPortableTextSpan(child)) {
@@ -66,17 +78,17 @@ export function sliceBlocks({
66
78
  },
67
79
  ],
68
80
  }
69
- continue
81
+ } else {
82
+ startBlock = {
83
+ ...block,
84
+ children: [child],
85
+ }
70
86
  }
71
87
 
72
- startBlock = {
73
- ...block,
74
- children: [child],
88
+ if (startChildKey === endChildKey) {
89
+ break
75
90
  }
76
- }
77
-
78
- if (startChildKey === endChildKey) {
79
- break
91
+ continue
80
92
  }
81
93
 
82
94
  if (startBlock && isPortableTextTextBlock(startBlock)) {
@@ -107,7 +119,12 @@ export function sliceBlocks({
107
119
  }
108
120
 
109
121
  if (block._key === endBlockKey) {
110
- if (isPortableTextTextBlock(block) && endBlockKey) {
122
+ if (!isPortableTextTextBlock(block)) {
123
+ endBlock = block
124
+ break
125
+ }
126
+
127
+ if (endChildKey) {
111
128
  endBlock = {
112
129
  ...block,
113
130
  children: [],
@@ -1 +0,0 @@
1
- {"version":3,"file":"selector.is-selection-collapsed.cjs","sources":["../../src/behavior-actions/behavior.guards.ts","../../src/selectors/selectors.ts","../../src/selectors/selector.is-selection-collapsed.ts"],"sourcesContent":["import {\n isPortableTextListBlock,\n isPortableTextTextBlock,\n type PortableTextListBlock,\n type PortableTextTextBlock,\n} from '@sanity/types'\nimport type {EditorSchema} from '../editor/define-schema'\n\n/**\n * @alpha\n */\nexport type BehaviorGuards = ReturnType<typeof createGuards>\n\nexport function createGuards({schema}: {schema: EditorSchema}) {\n function isListBlock(block: unknown): block is PortableTextListBlock {\n return isPortableTextListBlock(block) && block._type === schema.block.name\n }\n\n function isTextBlock(block: unknown): block is PortableTextTextBlock {\n return isPortableTextTextBlock(block) && block._type === schema.block.name\n }\n\n return {isListBlock, isTextBlock}\n}\n","import {\n isKeySegment,\n isPortableTextSpan,\n isPortableTextTextBlock,\n type KeyedSegment,\n type PortableTextBlock,\n type PortableTextListBlock,\n type PortableTextObject,\n type PortableTextSpan,\n type PortableTextTextBlock,\n} from '@sanity/types'\nimport {createGuards} from '../behavior-actions/behavior.guards'\nimport type {EditorSelector} from '../editor/editor-selector'\n\n/**\n * @public\n */\nexport const getFocusBlock: EditorSelector<\n {node: PortableTextBlock; path: [KeyedSegment]} | undefined\n> = ({context}) => {\n const key = context.selection\n ? isKeySegment(context.selection.focus.path[0])\n ? context.selection.focus.path[0]._key\n : undefined\n : undefined\n\n const node = key\n ? context.value.find((block) => block._key === key)\n : undefined\n\n return node && key ? {node, path: [{_key: key}]} : undefined\n}\n\n/**\n * @public\n */\nexport const getFocusListBlock: EditorSelector<\n {node: PortableTextListBlock; path: [KeyedSegment]} | undefined\n> = ({context}) => {\n const guards = createGuards(context)\n const focusBlock = getFocusBlock({context})\n\n return focusBlock && guards.isListBlock(focusBlock.node)\n ? {node: focusBlock.node, path: focusBlock.path}\n : undefined\n}\n\n/**\n * @public\n */\nexport const getFocusTextBlock: EditorSelector<\n {node: PortableTextTextBlock; path: [KeyedSegment]} | undefined\n> = ({context}) => {\n const focusBlock = getFocusBlock({context})\n\n return focusBlock && isPortableTextTextBlock(focusBlock.node)\n ? {node: focusBlock.node, path: focusBlock.path}\n : undefined\n}\n\n/**\n * @public\n */\nexport const getFocusBlockObject: EditorSelector<\n {node: PortableTextObject; path: [KeyedSegment]} | undefined\n> = ({context}) => {\n const focusBlock = getFocusBlock({context})\n\n return focusBlock && !isPortableTextTextBlock(focusBlock.node)\n ? {node: focusBlock.node, path: focusBlock.path}\n : undefined\n}\n\n/**\n * @public\n */\nexport const getFocusChild: EditorSelector<\n | {\n node: PortableTextObject | PortableTextSpan\n path: [KeyedSegment, 'children', KeyedSegment]\n }\n | undefined\n> = ({context}) => {\n const focusBlock = getFocusTextBlock({context})\n\n if (!focusBlock) {\n return undefined\n }\n\n const key = context.selection\n ? isKeySegment(context.selection.focus.path[2])\n ? context.selection.focus.path[2]._key\n : undefined\n : undefined\n\n const node = key\n ? focusBlock.node.children.find((span) => span._key === key)\n : undefined\n\n return node && key\n ? {node, path: [...focusBlock.path, 'children', {_key: key}]}\n : undefined\n}\n\n/**\n * @public\n */\nexport const getFocusSpan: EditorSelector<\n | {node: PortableTextSpan; path: [KeyedSegment, 'children', KeyedSegment]}\n | undefined\n> = ({context}) => {\n const focusChild = getFocusChild({context})\n\n return focusChild && isPortableTextSpan(focusChild.node)\n ? {node: focusChild.node, path: focusChild.path}\n : undefined\n}\n\n/**\n * @public\n */\nexport const getFirstBlock: EditorSelector<\n {node: PortableTextBlock; path: [KeyedSegment]} | undefined\n> = ({context}) => {\n const node = context.value[0]\n\n return node ? {node, path: [{_key: node._key}]} : undefined\n}\n\n/**\n * @public\n */\nexport const getLastBlock: EditorSelector<\n {node: PortableTextBlock; path: [KeyedSegment]} | undefined\n> = ({context}) => {\n const node = context.value[context.value.length - 1]\n ? context.value[context.value.length - 1]\n : undefined\n\n return node ? {node, path: [{_key: node._key}]} : undefined\n}\n\n/**\n * @public\n */\nexport const getSelectedBlocks: EditorSelector<\n Array<{node: PortableTextBlock; path: [KeyedSegment]}>\n> = ({context}) => {\n if (!context.selection) {\n return []\n }\n\n const selectedBlocks: Array<{node: PortableTextBlock; path: [KeyedSegment]}> =\n []\n const startKey = context.selection.backward\n ? isKeySegment(context.selection.focus.path[0])\n ? context.selection.focus.path[0]._key\n : undefined\n : isKeySegment(context.selection.anchor.path[0])\n ? context.selection.anchor.path[0]._key\n : undefined\n const endKey = context.selection.backward\n ? isKeySegment(context.selection.anchor.path[0])\n ? context.selection.anchor.path[0]._key\n : undefined\n : isKeySegment(context.selection.focus.path[0])\n ? context.selection.focus.path[0]._key\n : undefined\n\n if (!startKey || !endKey) {\n return selectedBlocks\n }\n\n for (const block of context.value) {\n if (block._key === startKey) {\n selectedBlocks.push({node: block, path: [{_key: block._key}]})\n\n if (startKey === endKey) {\n break\n }\n continue\n }\n\n if (block._key === endKey) {\n selectedBlocks.push({node: block, path: [{_key: block._key}]})\n break\n }\n\n if (selectedBlocks.length > 0) {\n selectedBlocks.push({node: block, path: [{_key: block._key}]})\n }\n }\n\n return selectedBlocks\n}\n\n/**\n * @public\n */\nexport const getSelectionStartBlock: EditorSelector<\n | {\n node: PortableTextBlock\n path: [KeyedSegment]\n }\n | undefined\n> = ({context}) => {\n if (!context.selection) {\n return undefined\n }\n\n const key = context.selection.backward\n ? isKeySegment(context.selection.focus.path[0])\n ? context.selection.focus.path[0]._key\n : undefined\n : isKeySegment(context.selection.anchor.path[0])\n ? context.selection.anchor.path[0]._key\n : undefined\n\n const node = key\n ? context.value.find((block) => block._key === key)\n : undefined\n\n return node && key ? {node, path: [{_key: key}]} : undefined\n}\n\n/**\n * @public\n */\nexport const getSelectionEndBlock: EditorSelector<\n | {\n node: PortableTextBlock\n path: [KeyedSegment]\n }\n | undefined\n> = ({context}) => {\n if (!context.selection) {\n return undefined\n }\n\n const key = context.selection.backward\n ? isKeySegment(context.selection.anchor.path[0])\n ? context.selection.anchor.path[0]._key\n : undefined\n : isKeySegment(context.selection.focus.path[0])\n ? context.selection.focus.path[0]._key\n : undefined\n\n const node = key\n ? context.value.find((block) => block._key === key)\n : undefined\n\n return node && key ? {node, path: [{_key: key}]} : undefined\n}\n\n/**\n * @public\n */\nexport const getPreviousBlock: EditorSelector<\n {node: PortableTextBlock; path: [KeyedSegment]} | undefined\n> = ({context}) => {\n let previousBlock: {node: PortableTextBlock; path: [KeyedSegment]} | undefined\n const selectionStartBlock = getSelectionStartBlock({context})\n\n if (!selectionStartBlock) {\n return undefined\n }\n\n let foundSelectionStartBlock = false\n\n for (const block of context.value) {\n if (block._key === selectionStartBlock.node._key) {\n foundSelectionStartBlock = true\n break\n }\n\n previousBlock = {node: block, path: [{_key: block._key}]}\n }\n\n if (foundSelectionStartBlock && previousBlock) {\n return previousBlock\n }\n\n return undefined\n}\n\n/**\n * @public\n */\nexport const getNextBlock: EditorSelector<\n {node: PortableTextBlock; path: [KeyedSegment]} | undefined\n> = ({context}) => {\n let nextBlock: {node: PortableTextBlock; path: [KeyedSegment]} | undefined\n const selectionEndBlock = getSelectionEndBlock({context})\n\n if (!selectionEndBlock) {\n return undefined\n }\n\n let foundSelectionEndBlock = false\n\n for (const block of context.value) {\n if (block._key === selectionEndBlock.node._key) {\n foundSelectionEndBlock = true\n continue\n }\n\n if (foundSelectionEndBlock) {\n nextBlock = {node: block, path: [{_key: block._key}]}\n break\n }\n }\n\n if (foundSelectionEndBlock && nextBlock) {\n return nextBlock\n }\n\n return undefined\n}\n","import type {EditorSelector} from '../editor/editor-selector'\n\n/**\n * @public\n */\nexport const isSelectionCollapsed: EditorSelector<boolean> = ({context}) => {\n return (\n JSON.stringify(context.selection?.anchor.path) ===\n JSON.stringify(context.selection?.focus.path) &&\n context.selection?.anchor.offset === context.selection?.focus.offset\n )\n}\n"],"names":["createGuards","schema","isListBlock","block","isPortableTextListBlock","_type","name","isTextBlock","isPortableTextTextBlock","getFocusBlock","context","key","selection","isKeySegment","focus","path","_key","undefined","node","value","find","getFocusListBlock","guards","focusBlock","getFocusTextBlock","getFocusBlockObject","getFocusChild","children","span","getFocusSpan","focusChild","isPortableTextSpan","getFirstBlock","getLastBlock","length","getSelectedBlocks","selectedBlocks","startKey","backward","anchor","endKey","push","getSelectionStartBlock","getSelectionEndBlock","getPreviousBlock","previousBlock","selectionStartBlock","foundSelectionStartBlock","getNextBlock","nextBlock","selectionEndBlock","foundSelectionEndBlock","isSelectionCollapsed","JSON","stringify","offset"],"mappings":"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"}