@portabletext/editor 1.21.6 → 1.23.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 (53) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  2. package/lib/_chunks-cjs/selector.get-text-before.cjs +4 -4
  3. package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
  4. package/lib/_chunks-cjs/{util.get-block-start-point.cjs → util.reverse-selection.cjs} +12 -12
  5. package/lib/_chunks-cjs/util.reverse-selection.cjs.map +1 -0
  6. package/lib/_chunks-cjs/util.slice-blocks.cjs +75 -0
  7. package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -0
  8. package/lib/_chunks-es/behavior.core.js.map +1 -1
  9. package/lib/_chunks-es/selector.get-text-before.js +1 -1
  10. package/lib/_chunks-es/{util.get-block-start-point.js → util.reverse-selection.js} +12 -12
  11. package/lib/_chunks-es/util.reverse-selection.js.map +1 -0
  12. package/lib/_chunks-es/util.slice-blocks.js +76 -0
  13. package/lib/_chunks-es/util.slice-blocks.js.map +1 -0
  14. package/lib/behaviors/index.cjs.map +1 -1
  15. package/lib/behaviors/index.d.cts +57 -0
  16. package/lib/behaviors/index.d.ts +57 -0
  17. package/lib/behaviors/index.js.map +1 -1
  18. package/lib/index.cjs +33 -12
  19. package/lib/index.cjs.map +1 -1
  20. package/lib/index.d.cts +418 -0
  21. package/lib/index.d.ts +418 -0
  22. package/lib/index.js +33 -12
  23. package/lib/index.js.map +1 -1
  24. package/lib/selectors/index.cjs +10 -4
  25. package/lib/selectors/index.cjs.map +1 -1
  26. package/lib/selectors/index.d.cts +5 -0
  27. package/lib/selectors/index.d.ts +5 -0
  28. package/lib/selectors/index.js +9 -2
  29. package/lib/selectors/index.js.map +1 -1
  30. package/lib/utils/index.cjs +4 -3
  31. package/lib/utils/index.cjs.map +1 -1
  32. package/lib/utils/index.d.cts +11 -0
  33. package/lib/utils/index.d.ts +11 -0
  34. package/lib/utils/index.js +3 -1
  35. package/lib/utils/index.js.map +1 -1
  36. package/package.json +16 -12
  37. package/src/behaviors/behavior.markdown.ts +42 -0
  38. package/src/behaviors/behavior.types.ts +15 -0
  39. package/src/editor/Editable.tsx +17 -0
  40. package/src/editor/create-editor.ts +1 -0
  41. package/src/editor/define-schema.ts +24 -1
  42. package/src/editor/editor-event-listener.tsx +45 -0
  43. package/src/editor/editor-machine.ts +13 -26
  44. package/src/editor/editor-provider.tsx +27 -0
  45. package/src/editor/editor-selector.ts +21 -0
  46. package/src/editor/editor-snapshot.ts +37 -1
  47. package/src/selectors/index.ts +1 -0
  48. package/src/selectors/selector.get-selected-slice.ts +12 -0
  49. package/src/utils/index.ts +1 -0
  50. package/src/utils/util.slice-blocks.test.ts +257 -0
  51. package/src/utils/util.slice-blocks.ts +153 -0
  52. package/lib/_chunks-cjs/util.get-block-start-point.cjs.map +0 -1
  53. package/lib/_chunks-es/util.get-block-start-point.js.map +0 -1
@@ -5,6 +5,51 @@ import {useEditor} from './editor-provider'
5
5
 
6
6
  /**
7
7
  * @public
8
+ * Listen for events emitted by the editor. Must be used inside `EditorProvider`. Events available include:
9
+ * - 'blurred'
10
+ * - 'done loading'
11
+ * - 'editable'
12
+ * - 'error'
13
+ * - 'focused'
14
+ * - 'invalid value'
15
+ * - 'loading'
16
+ * - 'mutation'
17
+ * - 'patch'
18
+ * - 'read only'
19
+ * - 'ready'
20
+ * - 'selection'
21
+ * - 'value changed'
22
+ *
23
+ * @example
24
+ * Listen and log events.
25
+ * ```tsx
26
+ * import {EditorEventListener, EditorProvider} from '@portabletext/editor'
27
+ *
28
+ * function MyComponent() {
29
+ * return (
30
+ * <EditorProvider>
31
+ * <EditorEventListener
32
+ * on={(event) => {
33
+ * console.log(event)
34
+ * }
35
+ * } />
36
+ * { ... }
37
+ * </EditorProvider>
38
+ * )
39
+ * }
40
+ * ```
41
+ * @example
42
+ * Handle events when there is a mutation.
43
+ * ```tsx
44
+ * <EditorEventListener
45
+ * on={(event) => {
46
+ * if (event.type === 'mutation') {
47
+ * console.log('Value changed:', event.snapshot)
48
+ * }
49
+ * }}
50
+ * />
51
+ * ```
52
+ * @group Components
8
53
  */
9
54
  export function EditorEventListener(props: {
10
55
  on: (event: EditorEmittedEvent) => void
@@ -20,9 +20,6 @@ import {
20
20
  type NativeBehaviorEvent,
21
21
  type SyntheticBehaviorEvent,
22
22
  } from '../behaviors/behavior.types'
23
- import {toPortableTextRange} from '../internal-utils/ranges'
24
- import {fromSlateValue} from '../internal-utils/values'
25
- import {KEY_TO_VALUE_ELEMENT} from '../internal-utils/weakMaps'
26
23
  import type {OmitFromUnion, PickFromUnion} from '../type-utils'
27
24
  import type {
28
25
  EditorSelection,
@@ -30,8 +27,7 @@ import type {
30
27
  PortableTextSlateEditor,
31
28
  } from '../types/editor'
32
29
  import type {EditorSchema} from './define-schema'
33
- import type {EditorContext} from './editor-snapshot'
34
- import {getActiveDecorators} from './get-active-decorators'
30
+ import {createEditorSnapshot} from './editor-snapshot'
35
31
  import {withApplyingBehaviorActions} from './with-applying-behavior-actions'
36
32
 
37
33
  export * from 'xstate/guards'
@@ -109,6 +105,10 @@ export type InternalEditorEvent =
109
105
  type: 'update behaviors'
110
106
  behaviors: Array<Behavior>
111
107
  }
108
+ | {
109
+ type: 'update key generator'
110
+ keyGenerator: () => string
111
+ }
112
112
  | {
113
113
  type: 'update value'
114
114
  value: Array<PortableTextBlock> | undefined
@@ -342,27 +342,11 @@ export const editorMachine = setup({
342
342
  return
343
343
  }
344
344
 
345
- const value = fromSlateValue(
346
- event.editor.children,
347
- context.schema.block.name,
348
- KEY_TO_VALUE_ELEMENT.get(event.editor),
349
- )
350
- const selection = toPortableTextRange(
351
- value,
352
- event.editor.selection,
353
- context.schema,
354
- )
355
-
356
- const editorContext = {
357
- activeDecorators: getActiveDecorators({
358
- schema: context.schema,
359
- slateEditorInstance: event.editor,
360
- }),
345
+ const editorSnapshot = createEditorSnapshot({
346
+ editor: event.editor,
361
347
  keyGenerator: context.keyGenerator,
362
348
  schema: context.schema,
363
- selection,
364
- value,
365
- } satisfies EditorContext
349
+ })
366
350
 
367
351
  let behaviorOverwritten = false
368
352
 
@@ -370,7 +354,7 @@ export const editorMachine = setup({
370
354
  const shouldRun =
371
355
  eventBehavior.guard === undefined ||
372
356
  eventBehavior.guard({
373
- context: editorContext,
357
+ context: editorSnapshot.context,
374
358
  event: event.behaviorEvent,
375
359
  })
376
360
 
@@ -380,7 +364,7 @@ export const editorMachine = setup({
380
364
 
381
365
  const actionIntendSets = eventBehavior.actions.map((actionSet) =>
382
366
  actionSet(
383
- {context: editorContext, event: event.behaviorEvent},
367
+ {context: editorSnapshot.context, event: event.behaviorEvent},
384
368
  shouldRun,
385
369
  ),
386
370
  )
@@ -513,6 +497,9 @@ export const editorMachine = setup({
513
497
  'patches': {actions: emit(({event}) => event)},
514
498
  'done loading': {actions: emit({type: 'done loading'})},
515
499
  'update behaviors': {actions: 'assign behaviors'},
500
+ 'update key generator': {
501
+ actions: assign({keyGenerator: ({event}) => event.keyGenerator}),
502
+ },
516
503
  'update schema': {actions: 'assign schema'},
517
504
  'update value': {actions: assign({value: ({event}) => event.value})},
518
505
  'update maxBlocks': {
@@ -23,6 +23,21 @@ export type EditorProviderProps = {
23
23
 
24
24
  /**
25
25
  * @public
26
+ * The EditorProvider component is used to set up the editor context and configure the Portable Text Editor.
27
+ * @example
28
+ * ```tsx
29
+ * import {EditorProvider} from '@portabletext/editor'
30
+ *
31
+ * function App() {
32
+ * return (
33
+ * <EditorProvider initialConfig={{ ... }} >
34
+ * ...
35
+ * </EditorProvider>
36
+ * )
37
+ * }
38
+ *
39
+ * ```
40
+ * @group Components
26
41
  */
27
42
  export function EditorProvider(props: EditorProviderProps) {
28
43
  const editor = useCreateEditor(props.initialConfig)
@@ -66,6 +81,18 @@ export function EditorProvider(props: EditorProviderProps) {
66
81
 
67
82
  /**
68
83
  * @public
84
+ * Get the current editor context from the `EditorProvider`.
85
+ * Must be used inside the `EditorProvider` component.
86
+ * @returns The current editor object.
87
+ * @example
88
+ * ```tsx
89
+ * import { useEditor } from '@portabletext/editor'
90
+ *
91
+ * function MyComponent() {
92
+ * const editor = useEditor()
93
+ * }
94
+ * ```
95
+ * @group Hooks
69
96
  */
70
97
  export function useEditor() {
71
98
  const editor = React.useContext(EditorContext)
@@ -17,6 +17,27 @@ export type EditorSelector<TSelected> = (snapshot: EditorSnapshot) => TSelected
17
17
 
18
18
  /**
19
19
  * @public
20
+ * Hook to select a value from the editor state.
21
+ * @example
22
+ * Pass a selector as the second argument
23
+ * ```tsx
24
+ * import { useEditorSelector } from '@portabletext/editor'
25
+ *
26
+ * function MyComponent(editor) {
27
+ * const value = useEditorSelector(editor, selector)
28
+ * }
29
+ * ```
30
+ * @example
31
+ * Pass an inline selector as the second argument.
32
+ * In this case, use the editor context to obtain the schema.
33
+ * ```tsx
34
+ * import { useEditorSelector } from '@portabletext/editor'
35
+ *
36
+ * function MyComponent(editor) {
37
+ * const schema = useEditorSelector(editor, (snapshot) => snapshot.context.schema)
38
+ * }
39
+ * ```
40
+ * @group Hooks
20
41
  */
21
42
  export function useEditorSelector<TSelected>(
22
43
  editor: Editor,
@@ -1,6 +1,10 @@
1
1
  import type {PortableTextBlock} from '@sanity/types'
2
- import type {EditorSelection} from '../types/editor'
2
+ import {toPortableTextRange} from '../internal-utils/ranges'
3
+ import {fromSlateValue} from '../internal-utils/values'
4
+ import {KEY_TO_VALUE_ELEMENT} from '../internal-utils/weakMaps'
5
+ import type {EditorSelection, PortableTextSlateEditor} from '../types/editor'
3
6
  import type {EditorSchema} from './define-schema'
7
+ import {getActiveDecorators} from './get-active-decorators'
4
8
 
5
9
  /**
6
10
  * @public
@@ -19,3 +23,35 @@ export type EditorContext = {
19
23
  export type EditorSnapshot = {
20
24
  context: EditorContext
21
25
  }
26
+
27
+ export function createEditorSnapshot({
28
+ editor,
29
+ keyGenerator,
30
+ schema,
31
+ }: {
32
+ editor: PortableTextSlateEditor
33
+ keyGenerator: () => string
34
+ schema: EditorSchema
35
+ }) {
36
+ const value = fromSlateValue(
37
+ editor.children,
38
+ schema.block.name,
39
+ KEY_TO_VALUE_ELEMENT.get(editor),
40
+ )
41
+ const selection = toPortableTextRange(value, editor.selection, schema)
42
+
43
+ const context = {
44
+ activeDecorators: getActiveDecorators({
45
+ schema,
46
+ slateEditorInstance: editor,
47
+ }),
48
+ keyGenerator,
49
+ schema,
50
+ selection,
51
+ value,
52
+ } satisfies EditorContext
53
+
54
+ return {
55
+ context,
56
+ } satisfies EditorSnapshot
57
+ }
@@ -9,6 +9,7 @@ export type {
9
9
  export type {EditorSchema} from '../editor/define-schema'
10
10
  export {getActiveListItem} from './selector.get-active-list-item'
11
11
  export {getActiveStyle} from './selector.get-active-style'
12
+ export {getSelectedSlice} from './selector.get-selected-slice'
12
13
  export {getSelectedSpans} from './selector.get-selected-spans'
13
14
  export {getSelectionText} from './selector.get-selection-text'
14
15
  export {getBlockTextBefore} from './selector.get-text-before'
@@ -0,0 +1,12 @@
1
+ import type {PortableTextBlock} from '@sanity/types'
2
+ import type {EditorSelector} from '../editor/editor-selector'
3
+ import {sliceBlocks} from '../utils'
4
+
5
+ /**
6
+ * @public
7
+ */
8
+ export const getSelectedSlice: EditorSelector<Array<PortableTextBlock>> = ({
9
+ context,
10
+ }) => {
11
+ return sliceBlocks({blocks: context.value, selection: context.selection})
12
+ }
@@ -9,3 +9,4 @@ export {getTextBlockText} from './util.get-text-block-text'
9
9
  export {isEmptyTextBlock} from './util.is-empty-text-block'
10
10
  export {isKeyedSegment} from './util.is-keyed-segment'
11
11
  export {reverseSelection} from './util.reverse-selection'
12
+ export {sliceBlocks} from './util.slice-blocks'
@@ -0,0 +1,257 @@
1
+ import type {PortableTextBlock, PortableTextTextBlock} from '@sanity/types'
2
+ import {describe, expect, test} from 'vitest'
3
+ import {sliceBlocks} from './util.slice-blocks'
4
+
5
+ const b1: PortableTextTextBlock = {
6
+ _type: 'block',
7
+ _key: 'b1',
8
+ children: [
9
+ {
10
+ _type: 'span',
11
+ _key: 'b1c1',
12
+ text: 'foo',
13
+ },
14
+ {
15
+ _type: 'span',
16
+ _key: 'b1c2',
17
+ text: 'bar',
18
+ },
19
+ ],
20
+ }
21
+ const b2: PortableTextBlock = {
22
+ _type: 'image',
23
+ _key: 'b2',
24
+ src: 'https://example.com/image.jpg',
25
+ alt: 'Example',
26
+ }
27
+ const b3: PortableTextTextBlock = {
28
+ _type: 'block',
29
+ _key: 'b3',
30
+ children: [
31
+ {
32
+ _type: 'span',
33
+ _key: 'b3c1',
34
+ text: 'baz',
35
+ },
36
+ ],
37
+ }
38
+ const b4: PortableTextTextBlock = {
39
+ _type: 'block',
40
+ _key: 'b4',
41
+ children: [
42
+ {
43
+ _type: 'span',
44
+ _key: 'b4c1',
45
+ text: 'fizz',
46
+ },
47
+ {
48
+ _type: 'stock-ticker',
49
+ _key: 'b4c2',
50
+ symbol: 'AAPL',
51
+ },
52
+ {
53
+ _type: 'span',
54
+ _key: 'b4c3',
55
+ text: 'buzz',
56
+ },
57
+ ],
58
+ }
59
+
60
+ const blocks: Array<PortableTextBlock> = [b1, b2, b3, b4]
61
+
62
+ describe(sliceBlocks.name, () => {
63
+ test('sensible defaults', () => {
64
+ expect(sliceBlocks({blocks: [], selection: null})).toEqual([])
65
+ expect(sliceBlocks({blocks, selection: null})).toEqual([])
66
+ })
67
+
68
+ test('slicing a single block', () => {
69
+ expect(
70
+ sliceBlocks({
71
+ blocks,
72
+ selection: {
73
+ anchor: {
74
+ path: [{_key: b1._key}, 'children', {_key: b1.children[0]._key}],
75
+ offset: 0,
76
+ },
77
+ focus: {
78
+ path: [{_key: b1._key}, 'children', {_key: b1.children[0]._key}],
79
+ offset: 3,
80
+ },
81
+ },
82
+ }),
83
+ ).toEqual([
84
+ {
85
+ ...b1,
86
+ children: [b1.children[0]],
87
+ },
88
+ ])
89
+ })
90
+
91
+ test('slicing a single span', () => {
92
+ expect(
93
+ sliceBlocks({
94
+ blocks,
95
+ selection: {
96
+ anchor: {
97
+ path: [{_key: b1._key}, 'children', {_key: b1.children[0]._key}],
98
+ offset: 1,
99
+ },
100
+ focus: {
101
+ path: [{_key: b1._key}, 'children', {_key: b1.children[0]._key}],
102
+ offset: 2,
103
+ },
104
+ },
105
+ }),
106
+ ).toEqual([
107
+ {
108
+ ...b1,
109
+ children: [
110
+ {
111
+ ...b1.children[0],
112
+ text: 'o',
113
+ },
114
+ ],
115
+ },
116
+ ])
117
+ })
118
+
119
+ test('starting and ending selection on a block object', () => {
120
+ expect(
121
+ sliceBlocks({
122
+ blocks,
123
+ selection: {
124
+ anchor: {
125
+ path: [{_key: b2._key}],
126
+ offset: 0,
127
+ },
128
+ focus: {
129
+ path: [{_key: b2._key}],
130
+ offset: 0,
131
+ },
132
+ },
133
+ }),
134
+ ).toEqual([b2])
135
+ })
136
+
137
+ test('ending selection on a block object', () => {
138
+ expect(
139
+ sliceBlocks({
140
+ blocks,
141
+ selection: {
142
+ anchor: {
143
+ path: [{_key: b1._key}, 'children', {_key: b1.children[0]._key}],
144
+ offset: 3,
145
+ },
146
+ focus: {
147
+ path: [{_key: b2._key}],
148
+ offset: 0,
149
+ },
150
+ },
151
+ }),
152
+ ).toEqual([
153
+ {
154
+ ...b1,
155
+ children: [
156
+ {
157
+ ...b1.children[0],
158
+ text: '',
159
+ },
160
+ ...b1.children.slice(1),
161
+ ],
162
+ },
163
+ blocks[1],
164
+ ])
165
+ })
166
+
167
+ test('slicing across block object', () => {
168
+ expect(
169
+ sliceBlocks({
170
+ blocks,
171
+ selection: {
172
+ anchor: {
173
+ path: [{_key: b1._key}, 'children', {_key: b1.children[0]._key}],
174
+ offset: 0,
175
+ },
176
+ focus: {
177
+ path: [{_key: b3._key}, 'children', {_key: b3.children[0]._key}],
178
+ offset: 3,
179
+ },
180
+ },
181
+ }),
182
+ ).toEqual([b1, b2, b3])
183
+ })
184
+
185
+ test('starting and ending mid-span', () => {
186
+ expect(
187
+ sliceBlocks({
188
+ blocks,
189
+ selection: {
190
+ anchor: {
191
+ path: [{_key: b3._key}, 'children', {_key: b3.children[0]._key}],
192
+ offset: 2,
193
+ },
194
+ focus: {
195
+ path: [{_key: b4._key}, 'children', {_key: b4.children[0]._key}],
196
+ offset: 1,
197
+ },
198
+ },
199
+ }),
200
+ ).toEqual([
201
+ {
202
+ ...b3,
203
+ children: [
204
+ {
205
+ ...b3.children[0],
206
+ text: 'z',
207
+ },
208
+ ],
209
+ },
210
+ {
211
+ ...b4,
212
+ children: [
213
+ {
214
+ ...b4.children[0],
215
+ text: 'f',
216
+ },
217
+ ],
218
+ },
219
+ ])
220
+ })
221
+
222
+ test('starting mid-span and ending end-span', () => {
223
+ expect(
224
+ sliceBlocks({
225
+ blocks,
226
+ selection: {
227
+ anchor: {
228
+ path: [{_key: b3._key}, 'children', {_key: b3.children[0]._key}],
229
+ offset: 2,
230
+ },
231
+ focus: {
232
+ path: [{_key: b4._key}, 'children', {_key: b4.children[0]._key}],
233
+ offset: 4,
234
+ },
235
+ },
236
+ }),
237
+ ).toEqual([
238
+ {
239
+ ...b3,
240
+ children: [
241
+ {
242
+ ...b3.children[0],
243
+ text: 'z',
244
+ },
245
+ ],
246
+ },
247
+ {
248
+ ...b4,
249
+ children: [
250
+ {
251
+ ...b4.children[0],
252
+ },
253
+ ],
254
+ },
255
+ ])
256
+ })
257
+ })
@@ -0,0 +1,153 @@
1
+ import {
2
+ isKeySegment,
3
+ isPortableTextSpan,
4
+ isPortableTextTextBlock,
5
+ type PortableTextBlock,
6
+ } from '@sanity/types'
7
+ import type {EditorSelection} from '../selectors'
8
+
9
+ /**
10
+ * @public
11
+ */
12
+ export function sliceBlocks({
13
+ blocks,
14
+ selection,
15
+ }: {
16
+ blocks: Array<PortableTextBlock>
17
+ selection: EditorSelection
18
+ }): Array<PortableTextBlock> {
19
+ const slice: Array<PortableTextBlock> = []
20
+
21
+ if (!selection) {
22
+ return slice
23
+ }
24
+
25
+ let startBlock: PortableTextBlock | undefined
26
+ const middleBlocks: PortableTextBlock[] = []
27
+ let endBlock: PortableTextBlock | undefined
28
+
29
+ const startPoint = selection.backward ? selection.focus : selection.anchor
30
+ const endPoint = selection.backward ? selection.anchor : selection.focus
31
+
32
+ const startBlockKey = isKeySegment(startPoint.path[0])
33
+ ? startPoint.path[0]._key
34
+ : undefined
35
+ const endBlockKey = isKeySegment(endPoint.path[0])
36
+ ? endPoint.path[0]._key
37
+ : undefined
38
+ const startChildKey = isKeySegment(startPoint.path[2])
39
+ ? startPoint.path[2]._key
40
+ : undefined
41
+ const endChildKey = isKeySegment(endPoint.path[2])
42
+ ? endPoint.path[2]._key
43
+ : undefined
44
+
45
+ if (!startBlockKey || !endBlockKey) {
46
+ return slice
47
+ }
48
+
49
+ for (const block of blocks) {
50
+ if (block._key === startBlockKey) {
51
+ if (isPortableTextTextBlock(block) && startChildKey) {
52
+ for (const child of block.children) {
53
+ if (child._key === startChildKey) {
54
+ if (isPortableTextSpan(child)) {
55
+ const text =
56
+ child._key === endChildKey
57
+ ? child.text.slice(startPoint.offset, endPoint.offset)
58
+ : child.text.slice(startPoint.offset)
59
+
60
+ startBlock = {
61
+ ...block,
62
+ children: [
63
+ {
64
+ ...child,
65
+ text,
66
+ },
67
+ ],
68
+ }
69
+ continue
70
+ }
71
+
72
+ startBlock = {
73
+ ...block,
74
+ children: [child],
75
+ }
76
+ }
77
+
78
+ if (startChildKey === endChildKey) {
79
+ break
80
+ }
81
+
82
+ if (startBlock && isPortableTextTextBlock(startBlock)) {
83
+ startBlock.children.push(child)
84
+
85
+ if (
86
+ block._key === endBlockKey &&
87
+ endChildKey &&
88
+ child._key === endChildKey
89
+ ) {
90
+ break
91
+ }
92
+ }
93
+ }
94
+
95
+ if (startBlockKey === endBlockKey) {
96
+ break
97
+ }
98
+
99
+ continue
100
+ }
101
+
102
+ startBlock = block
103
+
104
+ if (startBlockKey === endBlockKey) {
105
+ break
106
+ }
107
+ }
108
+
109
+ if (block._key === endBlockKey) {
110
+ if (isPortableTextTextBlock(block) && endBlockKey) {
111
+ endBlock = {
112
+ ...block,
113
+ children: [],
114
+ }
115
+
116
+ for (const child of block.children) {
117
+ if (endBlock && isPortableTextTextBlock(endBlock)) {
118
+ if (child._key === endChildKey && isPortableTextSpan(child)) {
119
+ endBlock.children.push({
120
+ ...child,
121
+ text: child.text.slice(0, endPoint.offset),
122
+ })
123
+
124
+ break
125
+ }
126
+
127
+ endBlock.children.push(child)
128
+
129
+ if (endChildKey && child._key === endChildKey) {
130
+ break
131
+ }
132
+ }
133
+ }
134
+
135
+ break
136
+ }
137
+
138
+ endBlock = block
139
+
140
+ break
141
+ }
142
+
143
+ if (startBlock) {
144
+ middleBlocks.push(block)
145
+ }
146
+ }
147
+
148
+ return [
149
+ ...(startBlock ? [startBlock] : []),
150
+ ...middleBlocks,
151
+ ...(endBlock ? [endBlock] : []),
152
+ ]
153
+ }
@@ -1 +0,0 @@
1
- {"version":3,"file":"util.get-block-start-point.cjs","sources":["../../src/utils/util.reverse-selection.ts","../../src/utils/util.get-block-start-point.ts"],"sourcesContent":["import type {EditorSelection} from '../types/editor'\n\n/**\n * @public\n */\nexport function reverseSelection(\n selection: NonNullable<EditorSelection>,\n): NonNullable<EditorSelection> {\n if (selection.backward) {\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: false,\n }\n }\n\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: true,\n }\n}\n","import {\n isPortableTextTextBlock,\n type KeyedSegment,\n type PortableTextBlock,\n} from '@sanity/types'\nimport type {EditorSelectionPoint} from '../types/editor'\n\n/**\n * @public\n */\nexport function getBlockStartPoint({\n node,\n path,\n}: {\n node: PortableTextBlock\n path: [KeyedSegment]\n}): EditorSelectionPoint {\n if (isPortableTextTextBlock(node)) {\n return {\n path: [...path, 'children', {_key: node.children[0]._key}],\n offset: 0,\n }\n }\n\n return {\n path,\n offset: 0,\n }\n}\n"],"names":["reverseSelection","selection","backward","anchor","focus","getBlockStartPoint","node","path","isPortableTextTextBlock","_key","children","offset"],"mappings":";;AAKO,SAASA,iBACdC,WAC8B;AAC9B,SAAIA,UAAUC,WACL;AAAA,IACLC,QAAQF,UAAUG;AAAAA,IAClBA,OAAOH,UAAUE;AAAAA,IACjBD,UAAU;AAAA,EAAA,IAIP;AAAA,IACLC,QAAQF,UAAUG;AAAAA,IAClBA,OAAOH,UAAUE;AAAAA,IACjBD,UAAU;AAAA,EACZ;AACF;ACXO,SAASG,mBAAmB;AAAA,EACjCC;AAAAA,EACAC;AAIF,GAAyB;AACnBC,SAAAA,MAAAA,wBAAwBF,IAAI,IACvB;AAAA,IACLC,MAAM,CAAC,GAAGA,MAAM,YAAY;AAAA,MAACE,MAAMH,KAAKI,SAAS,CAAC,EAAED;AAAAA,IAAAA,CAAK;AAAA,IACzDE,QAAQ;AAAA,EAAA,IAIL;AAAA,IACLJ;AAAAA,IACAI,QAAQ;AAAA,EACV;AACF;;;"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"util.get-block-start-point.js","sources":["../../src/utils/util.reverse-selection.ts","../../src/utils/util.get-block-start-point.ts"],"sourcesContent":["import type {EditorSelection} from '../types/editor'\n\n/**\n * @public\n */\nexport function reverseSelection(\n selection: NonNullable<EditorSelection>,\n): NonNullable<EditorSelection> {\n if (selection.backward) {\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: false,\n }\n }\n\n return {\n anchor: selection.focus,\n focus: selection.anchor,\n backward: true,\n }\n}\n","import {\n isPortableTextTextBlock,\n type KeyedSegment,\n type PortableTextBlock,\n} from '@sanity/types'\nimport type {EditorSelectionPoint} from '../types/editor'\n\n/**\n * @public\n */\nexport function getBlockStartPoint({\n node,\n path,\n}: {\n node: PortableTextBlock\n path: [KeyedSegment]\n}): EditorSelectionPoint {\n if (isPortableTextTextBlock(node)) {\n return {\n path: [...path, 'children', {_key: node.children[0]._key}],\n offset: 0,\n }\n }\n\n return {\n path,\n offset: 0,\n }\n}\n"],"names":["reverseSelection","selection","backward","anchor","focus","getBlockStartPoint","node","path","isPortableTextTextBlock","_key","children","offset"],"mappings":";AAKO,SAASA,iBACdC,WAC8B;AAC9B,SAAIA,UAAUC,WACL;AAAA,IACLC,QAAQF,UAAUG;AAAAA,IAClBA,OAAOH,UAAUE;AAAAA,IACjBD,UAAU;AAAA,EAAA,IAIP;AAAA,IACLC,QAAQF,UAAUG;AAAAA,IAClBA,OAAOH,UAAUE;AAAAA,IACjBD,UAAU;AAAA,EACZ;AACF;ACXO,SAASG,mBAAmB;AAAA,EACjCC;AAAAA,EACAC;AAIF,GAAyB;AACnBC,SAAAA,wBAAwBF,IAAI,IACvB;AAAA,IACLC,MAAM,CAAC,GAAGA,MAAM,YAAY;AAAA,MAACE,MAAMH,KAAKI,SAAS,CAAC,EAAED;AAAAA,IAAAA,CAAK;AAAA,IACzDE,QAAQ;AAAA,EAAA,IAIL;AAAA,IACLJ;AAAAA,IACAI,QAAQ;AAAA,EACV;AACF;"}