@portabletext/editor 2.20.0 → 2.21.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "2.20.0",
3
+ "version": "2.21.1",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -73,7 +73,7 @@
73
73
  "slate-dom": "^0.118.1",
74
74
  "slate-react": "0.118.2",
75
75
  "xstate": "^5.24.0",
76
- "@portabletext/block-tools": "^4.0.1",
76
+ "@portabletext/block-tools": "^4.0.2",
77
77
  "@portabletext/keyboard-shortcuts": "^2.1.0",
78
78
  "@portabletext/patches": "^2.0.0",
79
79
  "@portabletext/schema": "^2.0.0"
@@ -81,8 +81,8 @@
81
81
  "devDependencies": {
82
82
  "@sanity/diff-match-patch": "^3.2.0",
83
83
  "@sanity/pkg-utils": "^9.0.3",
84
- "@sanity/schema": "^4.14.1",
85
- "@sanity/types": "^4.14.1",
84
+ "@sanity/schema": "^4.14.2",
85
+ "@sanity/types": "^4.14.2",
86
86
  "@types/debug": "^4.1.12",
87
87
  "@types/lodash": "^4.17.20",
88
88
  "@types/lodash.startcase": "^4.4.9",
@@ -106,14 +106,14 @@
106
106
  "vite": "^7.1.12",
107
107
  "vitest": "^4.0.6",
108
108
  "vitest-browser-react": "^2.0.2",
109
- "@portabletext/sanity-bridge": "1.2.1",
109
+ "@portabletext/sanity-bridge": "1.2.2",
110
110
  "@portabletext/test": "^1.0.0",
111
111
  "racejar": "2.0.0"
112
112
  },
113
113
  "peerDependencies": {
114
- "@portabletext/sanity-bridge": "^1.2.1",
115
- "@sanity/schema": "^4.14.1",
116
- "@sanity/types": "^4.14.1",
114
+ "@portabletext/sanity-bridge": "^1.2.2",
115
+ "@sanity/schema": "^4.14.2",
116
+ "@sanity/types": "^4.14.2",
117
117
  "react": "^18.3 || ^19",
118
118
  "rxjs": "^7.8.2"
119
119
  },
@@ -158,6 +158,7 @@ export type SyntheticBehaviorEvent =
158
158
  block: BlockWithOptionalKey
159
159
  placement: InsertPlacement
160
160
  select?: 'start' | 'end' | 'none'
161
+ at?: NonNullable<EditorSelection>
161
162
  }
162
163
  | {
163
164
  type: StrictExtract<SyntheticBehaviorEventType, 'insert.child'>
@@ -25,7 +25,7 @@ import {
25
25
  slateRangeToSelection,
26
26
  } from '../../internal-utils/slate-utils'
27
27
  import {toSlateRange} from '../../internal-utils/to-slate-range'
28
- import {fromSlateValue, toSlateValue} from '../../internal-utils/values'
28
+ import {fromSlateValue} from '../../internal-utils/values'
29
29
  import {getActiveAnnotationsMarks} from '../../selectors/selector.get-active-annotation-marks'
30
30
  import {getActiveDecorators} from '../../selectors/selector.get-active-decorators'
31
31
  import {getFocusBlock} from '../../selectors/selector.get-focus-block'
@@ -187,83 +187,17 @@ export function createEditableAPI(
187
187
  type: TSchemaType,
188
188
  value?: {[prop: string]: any},
189
189
  ): Path => {
190
- if (type.name !== types.span.name) {
191
- editorActor.send({
192
- type: 'behavior event',
193
- behaviorEvent: {
194
- type: 'insert.inline object',
195
- inlineObject: {
196
- name: type.name,
197
- value,
198
- },
199
- },
200
- editor,
201
- })
202
-
203
- return editor.selection
204
- ? (slateRangeToSelection({
205
- schema: editorActor.getSnapshot().context.schema,
206
- editor,
207
- range: editor.selection,
208
- })?.focus.path ?? [])
209
- : []
210
- }
211
-
212
- if (!editor.selection) {
213
- throw new Error('The editor has no selection')
214
- }
215
- const [focusBlock] = Array.from(
216
- Editor.nodes(editor, {
217
- at: editor.selection.focus.path.slice(0, 1),
218
- match: (n) => n._type === types.block.name,
219
- }),
220
- )[0] || [undefined]
221
- if (!focusBlock) {
222
- throw new Error('No focused text block')
223
- }
224
- if (
225
- type.name !== types.span.name &&
226
- !types.inlineObjects.some((t) => t.name === type.name)
227
- ) {
228
- throw new Error(
229
- 'This type cannot be inserted as a child to a text block',
230
- )
231
- }
232
- const block = toSlateValue(
233
- [
234
- {
235
- _key: editorActor.getSnapshot().context.keyGenerator(),
236
- _type: types.block.name,
237
- children: [
238
- {
239
- _key: editorActor.getSnapshot().context.keyGenerator(),
240
- _type: type.name,
241
- ...(value ? value : {}),
242
- },
243
- ],
190
+ editorActor.send({
191
+ type: 'behavior event',
192
+ behaviorEvent: {
193
+ type: 'insert.child',
194
+ child: {
195
+ _type: type.name,
196
+ ...(value ? value : {}),
244
197
  },
245
- ],
246
- {schemaTypes: editorActor.getSnapshot().context.schema},
247
- )[0] as unknown as SlateElement
248
- const child = block.children[0]
249
- const focusChildPath = editor.selection.focus.path.slice(0, 2)
250
- const isSpanNode = child._type === types.span.name
251
- const focusNode = Node.get(editor, focusChildPath)
252
-
253
- // If we are inserting a span, and currently have focus on an inline object,
254
- // move the selection to the next span (guaranteed by normalizing rules) before inserting it.
255
- if (isSpanNode && focusNode._type !== types.span.name) {
256
- debug(
257
- 'Inserting span child next to inline object child, moving selection + 1',
258
- )
259
- editor.move({distance: 1, unit: 'character'})
260
- }
261
-
262
- Transforms.insertNodes(editor, child, {
263
- select: true,
264
- at: editor.selection,
198
+ },
199
+ editor,
265
200
  })
266
- editor.onChange()
267
201
 
268
202
  return editor.selection
269
203
  ? (slateRangeToSelection({
@@ -1,4 +1,4 @@
1
- import {toSlateValue} from '../../internal-utils/values'
1
+ import {toSlateBlock} from '../../internal-utils/values'
2
2
  import type {PortableTextSlateEditor} from '../../types/editor'
3
3
  import type {EditorActor} from '../editor-machine'
4
4
 
@@ -19,36 +19,33 @@ export function createWithUtils({editorActor}: Options) {
19
19
  listItem?: string
20
20
  level?: number
21
21
  }) => {
22
- const block = toSlateValue(
23
- [
24
- {
25
- _type: editorActor.getSnapshot().context.schema.block.name,
26
- _key: editorActor.getSnapshot().context.keyGenerator(),
27
- style:
28
- editorActor.getSnapshot().context.schema.styles[0].name ||
29
- 'normal',
30
- ...(options.listItem ? {listItem: options.listItem} : {}),
31
- ...(options.level ? {level: options.level} : {}),
32
- markDefs: [],
33
- children: [
34
- {
35
- _type: 'span',
36
- _key: editorActor.getSnapshot().context.keyGenerator(),
37
- text: '',
38
- marks: options.decorators.filter((decorator) =>
39
- editorActor
40
- .getSnapshot()
41
- .context.schema.decorators.find(
42
- ({name}) => name === decorator,
43
- ),
44
- ),
45
- },
46
- ],
47
- },
48
- ],
22
+ return toSlateBlock(
23
+ {
24
+ _type: editorActor.getSnapshot().context.schema.block.name,
25
+ _key: editorActor.getSnapshot().context.keyGenerator(),
26
+ style:
27
+ editorActor.getSnapshot().context.schema.styles[0].name || 'normal',
28
+ ...(options.listItem ? {listItem: options.listItem} : {}),
29
+ ...(options.level ? {level: options.level} : {}),
30
+ markDefs: [],
31
+ children: [
32
+ {
33
+ _type: 'span',
34
+ _key: editorActor.getSnapshot().context.keyGenerator(),
35
+ text: '',
36
+ marks: options.decorators.filter((decorator) =>
37
+ editorActor
38
+ .getSnapshot()
39
+ .context.schema.decorators.find(
40
+ ({name}) => name === decorator,
41
+ ),
42
+ ),
43
+ },
44
+ ],
45
+ },
46
+
49
47
  {schemaTypes: editorActor.getSnapshot().context.schema},
50
- )[0]
51
- return block
48
+ )
52
49
  }
53
50
  return editor
54
51
  }
@@ -2,7 +2,7 @@ import {compileSchemaDefinitionToPortableTextMemberSchemaTypes} from '@portablet
2
2
  import {compileSchema, defineSchema} from '@portabletext/schema'
3
3
  import type {PortableTextTextBlock} from '@sanity/types'
4
4
  import {createEditor, type Descendant} from 'slate'
5
- import {beforeEach, describe, expect, it} from 'vitest'
5
+ import {beforeEach, describe, expect, it, test} from 'vitest'
6
6
  import {createActor} from 'xstate'
7
7
  import {editorMachine} from '../editor/editor-machine'
8
8
  import {withPlugins} from '../editor/plugins/with-plugins'
@@ -59,6 +59,66 @@ const createDefaultValue = () =>
59
59
  },
60
60
  ] as Descendant[]
61
61
 
62
+ describe(insertNodePatch.name, () => {
63
+ test('Scenario: Inserting block object on empty editor', () => {
64
+ expect(
65
+ insertNodePatch(
66
+ compileSchema(defineSchema({blockObjects: [{name: 'image'}]})),
67
+ [
68
+ {
69
+ _key: 'k2',
70
+ _type: 'image',
71
+ children: [
72
+ {
73
+ _key: 'void-child',
74
+ _type: 'span',
75
+ marks: [],
76
+ text: '',
77
+ },
78
+ ],
79
+ value: {},
80
+ },
81
+ ],
82
+ {
83
+ type: 'insert_node',
84
+ path: [0],
85
+ node: {
86
+ _key: 'k2',
87
+ _type: 'image',
88
+ children: [
89
+ {
90
+ _key: 'void-child',
91
+ _type: 'span',
92
+ marks: [],
93
+ text: '',
94
+ },
95
+ ],
96
+ value: {},
97
+ },
98
+ },
99
+ [],
100
+ ),
101
+ ).toEqual([
102
+ {
103
+ path: [],
104
+ type: 'setIfMissing',
105
+ value: [],
106
+ },
107
+ {
108
+ path: [0],
109
+ type: 'insert',
110
+ items: [
111
+ {
112
+ _key: 'k2',
113
+ _type: 'image',
114
+ },
115
+ ],
116
+ position: 'before',
117
+ },
118
+ ])
119
+ })
120
+ })
121
+
62
122
  describe('operationToPatches', () => {
63
123
  beforeEach(() => {
64
124
  editor.children = createDefaultValue()