@portabletext/editor 1.49.3 → 1.49.5
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/lib/behaviors/index.d.cts +24 -0
- package/lib/behaviors/index.d.ts +24 -0
- package/lib/index.cjs +323 -247
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +24 -0
- package/lib/index.d.ts +24 -0
- package/lib/index.js +324 -248
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.d.cts +24 -0
- package/lib/plugins/index.d.ts +24 -0
- package/lib/selectors/index.d.cts +24 -0
- package/lib/selectors/index.d.ts +24 -0
- package/lib/utils/index.d.cts +24 -0
- package/lib/utils/index.d.ts +24 -0
- package/package.json +1 -1
- package/src/editor/Editable.tsx +0 -2
- package/src/editor/editor-machine.ts +131 -1
- package/src/editor/sync-machine.ts +202 -182
|
@@ -3,10 +3,12 @@ import type {PortableTextBlock} from '@sanity/types'
|
|
|
3
3
|
import {isEqual} from 'lodash'
|
|
4
4
|
import {Editor, Text, Transforms, type Descendant, type Node} from 'slate'
|
|
5
5
|
import {
|
|
6
|
+
and,
|
|
6
7
|
assertEvent,
|
|
7
8
|
assign,
|
|
8
9
|
emit,
|
|
9
10
|
fromCallback,
|
|
11
|
+
not,
|
|
10
12
|
setup,
|
|
11
13
|
type AnyEventObject,
|
|
12
14
|
type CallbackLogicFunction,
|
|
@@ -173,6 +175,11 @@ export const syncMachine = setup({
|
|
|
173
175
|
|
|
174
176
|
return isBusy
|
|
175
177
|
},
|
|
178
|
+
'is new value': ({context, event}) => {
|
|
179
|
+
return (
|
|
180
|
+
event.type === 'update value' && context.previousValue !== event.value
|
|
181
|
+
)
|
|
182
|
+
},
|
|
176
183
|
'value changed while syncing': ({context, event}) => {
|
|
177
184
|
assertEvent(event, 'done syncing')
|
|
178
185
|
return context.pendingValue !== event.value
|
|
@@ -211,176 +218,148 @@ export const syncMachine = setup({
|
|
|
211
218
|
actions: ['assign readOnly'],
|
|
212
219
|
},
|
|
213
220
|
},
|
|
214
|
-
|
|
221
|
+
initial: 'idle',
|
|
215
222
|
states: {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
entry: [
|
|
221
|
-
() => {
|
|
222
|
-
debug('entry: syncing initial value')
|
|
223
|
-
},
|
|
224
|
-
],
|
|
225
|
-
exit: [
|
|
226
|
-
() => {
|
|
227
|
-
debug('exit: syncing initial value')
|
|
228
|
-
},
|
|
229
|
-
],
|
|
230
|
-
always: {
|
|
231
|
-
guard: 'initial value synced',
|
|
232
|
-
target: 'done syncing initial value',
|
|
233
|
-
},
|
|
223
|
+
idle: {
|
|
224
|
+
entry: [
|
|
225
|
+
() => {
|
|
226
|
+
debug('entry: syncing->idle')
|
|
234
227
|
},
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
debug('entry: done syncing initial value')
|
|
240
|
-
},
|
|
241
|
-
],
|
|
242
|
-
exit: [
|
|
243
|
-
() => {
|
|
244
|
-
debug('exit: done syncing initial value')
|
|
245
|
-
},
|
|
246
|
-
],
|
|
247
|
-
type: 'final',
|
|
228
|
+
],
|
|
229
|
+
exit: [
|
|
230
|
+
() => {
|
|
231
|
+
debug('exit: syncing->idle')
|
|
248
232
|
},
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
{
|
|
268
|
-
guard: 'is busy',
|
|
269
|
-
target: 'busy',
|
|
270
|
-
actions: ['assign pending value'],
|
|
271
|
-
},
|
|
272
|
-
{
|
|
273
|
-
target: 'syncing',
|
|
274
|
-
actions: ['assign pending value'],
|
|
233
|
+
],
|
|
234
|
+
on: {
|
|
235
|
+
'update value': [
|
|
236
|
+
{
|
|
237
|
+
guard: and(['is busy', 'is new value']),
|
|
238
|
+
target: 'busy',
|
|
239
|
+
actions: ['assign pending value'],
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
guard: 'is new value',
|
|
243
|
+
target: 'syncing',
|
|
244
|
+
actions: ['assign pending value'],
|
|
245
|
+
},
|
|
246
|
+
{
|
|
247
|
+
guard: not('initial value synced'),
|
|
248
|
+
actions: [
|
|
249
|
+
() => {
|
|
250
|
+
debug('no new value – setting initial value as synced')
|
|
275
251
|
},
|
|
252
|
+
'assign initial value synced',
|
|
253
|
+
'emit done syncing value',
|
|
276
254
|
],
|
|
277
255
|
},
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
debug('entry: syncing->busy')
|
|
283
|
-
},
|
|
284
|
-
],
|
|
285
|
-
exit: [
|
|
286
|
-
() => {
|
|
287
|
-
debug('exit: syncing->busy')
|
|
288
|
-
},
|
|
289
|
-
],
|
|
290
|
-
after: {
|
|
291
|
-
1000: [
|
|
292
|
-
{
|
|
293
|
-
guard: 'is busy',
|
|
294
|
-
target: '.',
|
|
295
|
-
reenter: true,
|
|
296
|
-
actions: [
|
|
297
|
-
() => {
|
|
298
|
-
debug('reenter: syncing->busy')
|
|
299
|
-
},
|
|
300
|
-
],
|
|
301
|
-
},
|
|
302
|
-
{
|
|
303
|
-
target: 'syncing',
|
|
256
|
+
{
|
|
257
|
+
actions: [
|
|
258
|
+
() => {
|
|
259
|
+
debug('no new value and initial value already synced')
|
|
304
260
|
},
|
|
305
261
|
],
|
|
306
262
|
},
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
263
|
+
],
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
busy: {
|
|
267
|
+
entry: [
|
|
268
|
+
() => {
|
|
269
|
+
debug('entry: syncing->busy')
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
exit: [
|
|
273
|
+
() => {
|
|
274
|
+
debug('exit: syncing->busy')
|
|
275
|
+
},
|
|
276
|
+
],
|
|
277
|
+
after: {
|
|
278
|
+
1000: [
|
|
279
|
+
{
|
|
280
|
+
guard: 'is busy',
|
|
281
|
+
target: '.',
|
|
282
|
+
reenter: true,
|
|
283
|
+
actions: [
|
|
284
|
+
() => {
|
|
285
|
+
debug('reenter: syncing->busy')
|
|
311
286
|
},
|
|
312
287
|
],
|
|
313
288
|
},
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
entry: [
|
|
317
|
-
() => {
|
|
318
|
-
debug('entry: syncing->syncing')
|
|
319
|
-
},
|
|
320
|
-
'emit syncing value',
|
|
321
|
-
],
|
|
322
|
-
exit: [
|
|
323
|
-
() => {
|
|
324
|
-
debug('exit: syncing->syncing')
|
|
325
|
-
},
|
|
326
|
-
'emit done syncing value',
|
|
327
|
-
],
|
|
328
|
-
always: {
|
|
329
|
-
guard: 'pending value equals previous value',
|
|
330
|
-
target: 'idle',
|
|
331
|
-
actions: ['clear pending value', 'assign initial value synced'],
|
|
289
|
+
{
|
|
290
|
+
target: 'syncing',
|
|
332
291
|
},
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
previousValue: context.previousValue,
|
|
341
|
-
readOnly: context.readOnly,
|
|
342
|
-
schema: context.schema,
|
|
343
|
-
},
|
|
344
|
-
slateEditor: context.slateEditor,
|
|
345
|
-
streamBlocks: !context.initialValueSynced,
|
|
346
|
-
value: context.pendingValue,
|
|
347
|
-
}
|
|
348
|
-
},
|
|
292
|
+
],
|
|
293
|
+
},
|
|
294
|
+
on: {
|
|
295
|
+
'update value': [
|
|
296
|
+
{
|
|
297
|
+
guard: 'is new value',
|
|
298
|
+
actions: ['assign pending value'],
|
|
349
299
|
},
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
300
|
+
],
|
|
301
|
+
},
|
|
302
|
+
},
|
|
303
|
+
syncing: {
|
|
304
|
+
entry: [
|
|
305
|
+
() => {
|
|
306
|
+
debug('entry: syncing->syncing')
|
|
307
|
+
},
|
|
308
|
+
'emit syncing value',
|
|
309
|
+
],
|
|
310
|
+
exit: [
|
|
311
|
+
() => {
|
|
312
|
+
debug('exit: syncing->syncing')
|
|
313
|
+
},
|
|
314
|
+
'emit done syncing value',
|
|
315
|
+
],
|
|
316
|
+
invoke: {
|
|
317
|
+
src: 'sync value',
|
|
318
|
+
id: 'sync value',
|
|
319
|
+
input: ({context}) => {
|
|
320
|
+
return {
|
|
321
|
+
context: {
|
|
322
|
+
keyGenerator: context.keyGenerator,
|
|
323
|
+
previousValue: context.previousValue,
|
|
324
|
+
readOnly: context.readOnly,
|
|
325
|
+
schema: context.schema,
|
|
362
326
|
},
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
327
|
+
slateEditor: context.slateEditor,
|
|
328
|
+
streamBlocks: !context.initialValueSynced,
|
|
329
|
+
value: context.pendingValue,
|
|
330
|
+
}
|
|
331
|
+
},
|
|
332
|
+
},
|
|
333
|
+
on: {
|
|
334
|
+
'update value': {
|
|
335
|
+
guard: 'is new value',
|
|
336
|
+
actions: ['assign pending value'],
|
|
337
|
+
},
|
|
338
|
+
'patch': {
|
|
339
|
+
actions: [emit(({event}) => event)],
|
|
340
|
+
},
|
|
341
|
+
'invalid value': {
|
|
342
|
+
actions: [emit(({event}) => event)],
|
|
343
|
+
},
|
|
344
|
+
'value changed': {
|
|
345
|
+
actions: [emit(({event}) => event)],
|
|
346
|
+
},
|
|
347
|
+
'done syncing': [
|
|
348
|
+
{
|
|
349
|
+
guard: 'value changed while syncing',
|
|
350
|
+
actions: ['assign previous value', 'assign initial value synced'],
|
|
351
|
+
target: 'syncing',
|
|
352
|
+
reenter: true,
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
target: 'idle',
|
|
356
|
+
actions: [
|
|
357
|
+
'clear pending value',
|
|
358
|
+
'assign previous value',
|
|
359
|
+
'assign initial value synced',
|
|
381
360
|
],
|
|
382
361
|
},
|
|
383
|
-
|
|
362
|
+
],
|
|
384
363
|
},
|
|
385
364
|
},
|
|
386
365
|
},
|
|
@@ -444,48 +423,69 @@ async function updateValue({
|
|
|
444
423
|
schemaTypes: context.schema,
|
|
445
424
|
})
|
|
446
425
|
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
426
|
+
if (streamBlocks) {
|
|
427
|
+
await new Promise<void>((resolve) => {
|
|
428
|
+
Editor.withoutNormalizing(slateEditor, () => {
|
|
429
|
+
withRemoteChanges(slateEditor, () => {
|
|
430
|
+
withoutPatching(slateEditor, async () => {
|
|
431
|
+
isChanged = removeExtraBlocks({
|
|
432
|
+
slateEditor,
|
|
433
|
+
slateValueFromProps,
|
|
434
|
+
})
|
|
452
435
|
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
436
|
+
for await (const [
|
|
437
|
+
currentBlock,
|
|
438
|
+
currentBlockIndex,
|
|
439
|
+
] of getStreamedBlocks({
|
|
440
|
+
slateValue: slateValueFromProps,
|
|
441
|
+
})) {
|
|
442
|
+
const {blockChanged, blockValid} = syncBlock({
|
|
443
|
+
context,
|
|
444
|
+
sendBack,
|
|
445
|
+
block: currentBlock,
|
|
446
|
+
index: currentBlockIndex,
|
|
447
|
+
slateEditor,
|
|
448
|
+
value,
|
|
462
449
|
})
|
|
450
|
+
|
|
451
|
+
isChanged = blockChanged || isChanged
|
|
452
|
+
isValid = isValid && blockValid
|
|
463
453
|
}
|
|
464
|
-
isChanged = true
|
|
465
|
-
}
|
|
466
454
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
455
|
+
resolve()
|
|
456
|
+
})
|
|
457
|
+
})
|
|
458
|
+
})
|
|
459
|
+
})
|
|
460
|
+
} else {
|
|
461
|
+
Editor.withoutNormalizing(slateEditor, () => {
|
|
462
|
+
withRemoteChanges(slateEditor, () => {
|
|
463
|
+
withoutPatching(slateEditor, () => {
|
|
464
|
+
isChanged = removeExtraBlocks({
|
|
465
|
+
slateEditor,
|
|
466
|
+
slateValueFromProps,
|
|
467
|
+
})
|
|
468
|
+
|
|
469
|
+
let index = 0
|
|
470
|
+
|
|
471
|
+
for (const currentBlock of slateValueFromProps) {
|
|
472
472
|
const {blockChanged, blockValid} = syncBlock({
|
|
473
473
|
context,
|
|
474
474
|
sendBack,
|
|
475
475
|
block: currentBlock,
|
|
476
|
-
index
|
|
476
|
+
index,
|
|
477
477
|
slateEditor,
|
|
478
478
|
value,
|
|
479
479
|
})
|
|
480
|
+
|
|
480
481
|
isChanged = blockChanged || isChanged
|
|
481
482
|
isValid = isValid && blockValid
|
|
483
|
+
index++
|
|
482
484
|
}
|
|
483
|
-
|
|
484
|
-
resolve()
|
|
485
485
|
})
|
|
486
486
|
})
|
|
487
487
|
})
|
|
488
|
-
}
|
|
488
|
+
}
|
|
489
489
|
}
|
|
490
490
|
|
|
491
491
|
if (!isValid) {
|
|
@@ -523,16 +523,36 @@ async function updateValue({
|
|
|
523
523
|
sendBack({type: 'done syncing', value})
|
|
524
524
|
}
|
|
525
525
|
|
|
526
|
-
|
|
526
|
+
function removeExtraBlocks({
|
|
527
|
+
slateEditor,
|
|
528
|
+
slateValueFromProps,
|
|
529
|
+
}: {
|
|
530
|
+
slateEditor: PortableTextSlateEditor
|
|
531
|
+
slateValueFromProps: Array<Descendant>
|
|
532
|
+
}) {
|
|
533
|
+
let isChanged = false
|
|
534
|
+
const childrenLength = slateEditor.children.length
|
|
535
|
+
|
|
536
|
+
// Remove blocks that have become superfluous
|
|
537
|
+
if (slateValueFromProps.length < childrenLength) {
|
|
538
|
+
for (let i = childrenLength - 1; i > slateValueFromProps.length - 1; i--) {
|
|
539
|
+
Transforms.removeNodes(slateEditor, {
|
|
540
|
+
at: [i],
|
|
541
|
+
})
|
|
542
|
+
}
|
|
543
|
+
isChanged = true
|
|
544
|
+
}
|
|
545
|
+
return isChanged
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
async function* getStreamedBlocks({
|
|
527
549
|
slateValue,
|
|
528
|
-
streamBlocks,
|
|
529
550
|
}: {
|
|
530
551
|
slateValue: Array<Descendant>
|
|
531
|
-
streamBlocks: boolean
|
|
532
552
|
}) {
|
|
533
553
|
let index = 0
|
|
534
554
|
for await (const block of slateValue) {
|
|
535
|
-
if (
|
|
555
|
+
if (index % 10 === 0) {
|
|
536
556
|
await new Promise<void>((resolve) => setTimeout(resolve, 0))
|
|
537
557
|
}
|
|
538
558
|
yield [block, index] as const
|