@portabletext/editor 3.0.7 → 3.0.8

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": "3.0.7",
3
+ "version": "3.0.8",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -73,7 +73,7 @@
73
73
  "slate-dom": "^0.119.0",
74
74
  "slate-react": "0.119.0",
75
75
  "xstate": "^5.24.0",
76
- "@portabletext/block-tools": "^4.1.2",
76
+ "@portabletext/block-tools": "^4.1.3",
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.18.0",
85
- "@sanity/types": "^4.18.0",
84
+ "@sanity/schema": "^4.19.0",
85
+ "@sanity/types": "^4.19.0",
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.9",
108
108
  "vitest-browser-react": "^2.0.2",
109
- "@portabletext/sanity-bridge": "1.2.5",
109
+ "@portabletext/sanity-bridge": "1.2.6",
110
110
  "@portabletext/test": "^1.0.0",
111
111
  "racejar": "2.0.0"
112
112
  },
113
113
  "peerDependencies": {
114
- "@portabletext/sanity-bridge": "^1.2.5",
115
- "@sanity/schema": "^4.18.0",
116
- "@sanity/types": "^4.18.0",
114
+ "@portabletext/sanity-bridge": "^1.2.6",
115
+ "@sanity/schema": "^4.19.0",
116
+ "@sanity/types": "^4.19.0",
117
117
  "react": "^18.3 || ^19",
118
118
  "rxjs": "^7.8.2"
119
119
  },
@@ -81,7 +81,6 @@ describe(converterPortableText.deserialize, () => {
81
81
  marks: [],
82
82
  },
83
83
  ],
84
- markDefs: [],
85
84
  },
86
85
  ],
87
86
  })
@@ -117,7 +116,6 @@ describe(converterPortableText.deserialize, () => {
117
116
  marks: [],
118
117
  },
119
118
  ],
120
- markDefs: [],
121
119
  },
122
120
  ],
123
121
  })
@@ -263,8 +261,6 @@ describe(converterPortableText.deserialize, () => {
263
261
  marks: [],
264
262
  },
265
263
  ],
266
- markDefs: [],
267
- style: 'normal',
268
264
  },
269
265
  ])
270
266
  })
@@ -299,8 +295,6 @@ describe(converterPortableText.deserialize, () => {
299
295
  marks: [],
300
296
  },
301
297
  ],
302
- markDefs: [],
303
- style: 'normal',
304
298
  },
305
299
  ])
306
300
  })
@@ -336,8 +330,6 @@ describe(converterPortableText.deserialize, () => {
336
330
  marks: [],
337
331
  },
338
332
  ],
339
- markDefs: [],
340
- style: 'normal',
341
333
  },
342
334
  ])
343
335
  })
@@ -377,7 +369,6 @@ describe(converterPortableText.deserialize, () => {
377
369
  marks: [],
378
370
  },
379
371
  ],
380
- markDefs: [],
381
372
  style: 'h1',
382
373
  },
383
374
  ])
@@ -415,9 +406,7 @@ describe(converterPortableText.deserialize, () => {
415
406
  marks: [],
416
407
  },
417
408
  ],
418
- markDefs: [],
419
409
  level: 1,
420
- style: 'normal',
421
410
  },
422
411
  ])
423
412
  })
@@ -458,10 +447,8 @@ describe(converterPortableText.deserialize, () => {
458
447
  marks: [],
459
448
  },
460
449
  ],
461
- markDefs: [],
462
450
  listItem: 'bullet',
463
451
  level: 1,
464
- style: 'normal',
465
452
  },
466
453
  ])
467
454
  })
@@ -30,6 +30,9 @@ export function createWithPortableTextMarkModel(
30
30
  const decorators = editorActor
31
31
  .getSnapshot()
32
32
  .context.schema.decorators.map((t) => t.name)
33
+ const defaultStyle = editorActor
34
+ .getSnapshot()
35
+ .context.schema.styles.at(0)?.name
33
36
 
34
37
  // Extend Slate's default normalization. Merge spans with same set of .marks when doing merge_node operations, and clean up markDefs / marks
35
38
  editor.normalizeNode = (nodeEntry) => {
@@ -74,6 +77,22 @@ export function createWithPortableTextMarkModel(
74
77
  return
75
78
  }
76
79
 
80
+ /**
81
+ * Add missing .style to block nodes
82
+ */
83
+ if (
84
+ defaultStyle &&
85
+ editor.isTextBlock(node) &&
86
+ typeof node.style === 'undefined'
87
+ ) {
88
+ debug('Adding .style to block node')
89
+
90
+ withNormalizeNode(editor, () => {
91
+ Transforms.setNodes(editor, {style: defaultStyle}, {at: path})
92
+ })
93
+ return
94
+ }
95
+
77
96
  /**
78
97
  * Add missing .marks to span nodes
79
98
  */
@@ -51,7 +51,6 @@ describe(toSlateBlock.name, () => {
51
51
  text: '123',
52
52
  },
53
53
  ],
54
- style: 'normal',
55
54
  })
56
55
  })
57
56
 
@@ -106,7 +105,6 @@ describe(toSlateBlock.name, () => {
106
105
  },
107
106
  },
108
107
  ],
109
- style: 'normal',
110
108
  })
111
109
  })
112
110
  })
@@ -32,7 +32,6 @@ describe(toSlateBlock.name, () => {
32
32
  text: 'foo',
33
33
  },
34
34
  ],
35
- style: 'normal',
36
35
  })
37
36
  })
38
37
 
@@ -62,7 +61,6 @@ describe(toSlateBlock.name, () => {
62
61
  text: 'foo',
63
62
  },
64
63
  ],
65
- style: 'normal',
66
64
  })
67
65
  })
68
66
 
@@ -101,7 +99,6 @@ describe(toSlateBlock.name, () => {
101
99
  __inline: true,
102
100
  },
103
101
  ],
104
- style: 'normal',
105
102
  })
106
103
  })
107
104
  })
@@ -148,7 +145,6 @@ describe(toSlateBlock.name, () => {
148
145
  },
149
146
  },
150
147
  ],
151
- style: 'normal',
152
148
  })
153
149
  })
154
150
 
@@ -191,7 +187,6 @@ describe(toSlateBlock.name, () => {
191
187
  },
192
188
  },
193
189
  ],
194
- style: 'normal',
195
190
  })
196
191
  })
197
192
  })
@@ -238,7 +233,6 @@ describe(toSlateBlock.name, () => {
238
233
  },
239
234
  },
240
235
  ],
241
- style: 'normal',
242
236
  })
243
237
  })
244
238
 
@@ -281,7 +275,6 @@ describe(toSlateBlock.name, () => {
281
275
  },
282
276
  },
283
277
  ],
284
- style: 'normal',
285
278
  })
286
279
  })
287
280
  })
@@ -35,7 +35,6 @@ export function toSlateBlock(
35
35
  if (isPortableText) {
36
36
  const textBlock = block as PortableTextTextBlock
37
37
  let hasInlines = false
38
- const hasMissingStyle = typeof textBlock.style === 'undefined'
39
38
  const hasMissingMarkDefs = typeof textBlock.markDefs === 'undefined'
40
39
  const hasMissingChildren = typeof textBlock.children === 'undefined'
41
40
 
@@ -86,7 +85,6 @@ export function toSlateBlock(
86
85
 
87
86
  // Return original block
88
87
  if (
89
- !hasMissingStyle &&
90
88
  !hasMissingMarkDefs &&
91
89
  !hasMissingChildren &&
92
90
  !hasInlines &&
@@ -96,11 +94,6 @@ export function toSlateBlock(
96
94
  return block
97
95
  }
98
96
 
99
- // TODO: remove this when we have a better way to handle missing style
100
- if (hasMissingStyle) {
101
- rest.style = schemaTypes.styles[0].name
102
- }
103
-
104
97
  return keepObjectEquality(
105
98
  {_type, _key, ...rest, children},
106
99
  keyMap,
@@ -176,25 +169,76 @@ export function fromSlateBlock(
176
169
  }
177
170
 
178
171
  export function isEqualToEmptyEditor(
179
- children: Descendant[] | PortableTextBlock[],
172
+ blocks: Array<Descendant> | Array<PortableTextBlock>,
180
173
  schemaTypes: EditorSchema,
181
174
  ): boolean {
182
- return (
183
- children === undefined ||
184
- (children && Array.isArray(children) && children.length === 0) ||
185
- (children &&
186
- Array.isArray(children) &&
187
- children.length === 1 &&
188
- Element.isElement(children[0]) &&
189
- children[0]._type === schemaTypes.block.name &&
190
- 'style' in children[0] &&
191
- children[0].style === schemaTypes.styles[0].name &&
192
- !('listItem' in children[0]) &&
193
- Array.isArray(children[0].children) &&
194
- children[0].children.length === 1 &&
195
- Text.isText(children[0].children[0]) &&
196
- children[0].children[0]._type === 'span' &&
197
- !children[0].children[0].marks?.join('') &&
198
- children[0].children[0].text === '')
199
- )
175
+ // Must have exactly one block
176
+ if (blocks.length !== 1) {
177
+ return false
178
+ }
179
+
180
+ const firstBlock = blocks.at(0)
181
+
182
+ if (!firstBlock) {
183
+ return true
184
+ }
185
+
186
+ if (!Element.isElement(firstBlock)) {
187
+ return false
188
+ }
189
+
190
+ // Must be a text block
191
+ if (firstBlock._type !== schemaTypes.block.name) {
192
+ return false
193
+ }
194
+
195
+ // Must not be a list item
196
+ if ('listItem' in firstBlock) {
197
+ return false
198
+ }
199
+
200
+ // Style must exist and be the default style
201
+ if (
202
+ !('style' in firstBlock) ||
203
+ firstBlock.style !== schemaTypes.styles.at(0)?.name
204
+ ) {
205
+ return false
206
+ }
207
+
208
+ // Must have children array
209
+ if (!Array.isArray(firstBlock.children)) {
210
+ return false
211
+ }
212
+
213
+ // Must have exactly one child
214
+ if (firstBlock.children.length !== 1) {
215
+ return false
216
+ }
217
+
218
+ const firstChild = firstBlock.children.at(0)
219
+
220
+ if (!firstChild) {
221
+ return false
222
+ }
223
+
224
+ if (!Text.isText(firstChild)) {
225
+ return false
226
+ }
227
+
228
+ // Must be a span type
229
+ if (!('_type' in firstChild) || firstChild._type !== schemaTypes.span.name) {
230
+ return false
231
+ }
232
+
233
+ // Must have empty text
234
+ if (firstChild.text !== '') {
235
+ return false
236
+ }
237
+
238
+ // Must have no marks (marks can be undefined or empty array)
239
+ if (firstChild.marks?.join('')) {
240
+ return false
241
+ }
242
+
243
+ return true
200
244
  }
@@ -129,8 +129,6 @@ describe(parseBlock.name, () => {
129
129
  marks: [],
130
130
  },
131
131
  ],
132
- markDefs: [],
133
- style: 'normal',
134
132
  })
135
133
  })
136
134
 
@@ -160,8 +158,6 @@ describe(parseBlock.name, () => {
160
158
  marks: [],
161
159
  },
162
160
  ],
163
- markDefs: [],
164
- style: 'normal',
165
161
  })
166
162
  })
167
163
 
@@ -271,8 +267,6 @@ describe(parseBlock.name, () => {
271
267
  marks: ['em'],
272
268
  },
273
269
  ],
274
- markDefs: [],
275
- style: 'normal',
276
270
  })
277
271
  })
278
272
 
@@ -301,9 +295,7 @@ describe(parseBlock.name, () => {
301
295
  marks: [],
302
296
  },
303
297
  ],
304
- markDefs: [],
305
298
  listItem: 'bullet',
306
- style: 'normal',
307
299
  })
308
300
  })
309
301
 
@@ -332,8 +324,6 @@ describe(parseBlock.name, () => {
332
324
  marks: [],
333
325
  },
334
326
  ],
335
- markDefs: [],
336
- style: 'normal',
337
327
  })
338
328
  })
339
329
 
@@ -363,8 +353,6 @@ describe(parseBlock.name, () => {
363
353
  marks: [],
364
354
  },
365
355
  ],
366
- markDefs: [],
367
- style: 'normal',
368
356
  })
369
357
  })
370
358
 
@@ -398,8 +386,6 @@ describe(parseBlock.name, () => {
398
386
  marks: [],
399
387
  },
400
388
  ],
401
- markDefs: [],
402
- style: 'normal',
403
389
  })
404
390
  })
405
391
 
@@ -432,8 +418,6 @@ describe(parseBlock.name, () => {
432
418
  marks: [],
433
419
  },
434
420
  ],
435
- markDefs: [],
436
- style: 'normal',
437
421
  })
438
422
  })
439
423
  })
@@ -249,25 +249,20 @@ export function parseTextBlock({
249
249
  _type: context.schema.block.name,
250
250
  _key,
251
251
  children: normalizedChildren,
252
- markDefs: options.removeUnusedMarkDefs
253
- ? markDefs.filter((markDef) => marks.includes(markDef._key))
254
- : markDefs,
255
252
  ...customFields,
256
253
  }
257
254
 
255
+ if (typeof block.markDefs === 'object' && block.markDefs !== null) {
256
+ parsedBlock.markDefs = options.removeUnusedMarkDefs
257
+ ? markDefs.filter((markDef) => marks.includes(markDef._key))
258
+ : markDefs
259
+ }
260
+
258
261
  if (
259
262
  typeof block.style === 'string' &&
260
263
  context.schema.styles.find((style) => style.name === block.style)
261
264
  ) {
262
265
  parsedBlock.style = block.style
263
- } else {
264
- const defaultStyle = context.schema.styles.at(0)?.name
265
-
266
- if (defaultStyle !== undefined) {
267
- parsedBlock.style = defaultStyle
268
- } else {
269
- console.error('Expected default style')
270
- }
271
266
  }
272
267
 
273
268
  if (