@portabletext/editor 1.49.10 → 1.49.11

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 (39) hide show
  1. package/lib/behaviors/index.d.cts +160 -2885
  2. package/lib/behaviors/index.d.ts +160 -2885
  3. package/lib/index.cjs +346 -308
  4. package/lib/index.cjs.map +1 -1
  5. package/lib/index.d.cts +170 -2874
  6. package/lib/index.d.ts +170 -2874
  7. package/lib/index.js +349 -311
  8. package/lib/index.js.map +1 -1
  9. package/lib/plugins/index.cjs.map +1 -1
  10. package/lib/plugins/index.d.cts +162 -2879
  11. package/lib/plugins/index.d.ts +162 -2879
  12. package/lib/plugins/index.js.map +1 -1
  13. package/lib/selectors/index.d.cts +160 -2885
  14. package/lib/selectors/index.d.ts +160 -2885
  15. package/lib/utils/index.d.cts +160 -2885
  16. package/lib/utils/index.d.ts +160 -2885
  17. package/package.json +1 -1
  18. package/src/editor/Editable.tsx +14 -12
  19. package/src/editor/PortableTextEditor.tsx +21 -26
  20. package/src/editor/__tests__/self-solving.test.tsx +9 -9
  21. package/src/editor/create-editor.ts +81 -49
  22. package/src/editor/create-slate-editor.tsx +3 -0
  23. package/src/editor/editor-machine.ts +15 -127
  24. package/src/editor/editor-provider.tsx +20 -15
  25. package/src/editor/mutation-machine.ts +125 -7
  26. package/src/editor/plugins/createWithPatches.ts +5 -2
  27. package/src/editor/plugins/createWithPortableTextSelections.ts +4 -2
  28. package/src/editor/plugins/with-plugins.ts +8 -3
  29. package/src/editor/relay-actor-context.ts +4 -0
  30. package/src/editor/relay-machine.ts +89 -0
  31. package/src/editor/route-events-to-changes.tsx +4 -10
  32. package/src/editor/sync-machine.ts +2 -2
  33. package/src/editor-event-listener.tsx +1 -1
  34. package/src/editor.ts +2 -4
  35. package/src/index.ts +3 -6
  36. package/src/internal-utils/__tests__/operationToPatches.test.ts +3 -1
  37. package/src/internal-utils/__tests__/patchToOperations.test.ts +2 -0
  38. package/src/plugins/plugin.event-listener.tsx +1 -1
  39. package/src/types/editor.ts +12 -4
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@portabletext/editor",
3
- "version": "1.49.10",
3
+ "version": "1.49.11",
4
4
  "description": "Portable Text Editor made in React",
5
5
  "keywords": [
6
6
  "sanity",
@@ -64,6 +64,7 @@ import {
64
64
  createDecorate,
65
65
  rangeDecorationsMachine,
66
66
  } from './range-decorations-machine'
67
+ import {RelayActorContext} from './relay-actor-context'
67
68
 
68
69
  const debug = debugWithName('component:Editable')
69
70
 
@@ -160,6 +161,7 @@ export const PortableTextEditable = forwardRef<
160
161
  )
161
162
 
162
163
  const editorActor = useContext(EditorActorContext)
164
+ const relayActor = useContext(RelayActorContext)
163
165
  const readOnly = useSelector(editorActor, (s) =>
164
166
  s.matches({'edit mode': 'read only'}),
165
167
  )
@@ -282,8 +284,8 @@ export const PortableTextEditable = forwardRef<
282
284
  // Output selection here in those cases where the editor selection was the same, and there are no set_selection operations made.
283
285
  // The selection is usually automatically emitted to change$ by the withPortableTextSelections plugin whenever there is a set_selection operation applied.
284
286
  if (!slateEditor.operations.some((o) => o.type === 'set_selection')) {
285
- editorActor.send({
286
- type: 'notify.selection',
287
+ relayActor.send({
288
+ type: 'selection',
287
289
  selection: normalizedSelection,
288
290
  })
289
291
  }
@@ -291,7 +293,7 @@ export const PortableTextEditable = forwardRef<
291
293
  }
292
294
  }
293
295
  }
294
- }, [editorActor, propsSelection, slateEditor])
296
+ }, [editorActor, propsSelection, relayActor, slateEditor])
295
297
 
296
298
  // Restore selection from props when the editor has been initialized properly with it's value
297
299
  useEffect(() => {
@@ -435,7 +437,7 @@ export const PortableTextEditable = forwardRef<
435
437
  event.preventDefault()
436
438
 
437
439
  // Resolve it as promise (can be either async promise or sync return value)
438
- editorActor.send({type: 'notify.loading'})
440
+ relayActor.send({type: 'loading'})
439
441
 
440
442
  Promise.resolve(onPasteResult)
441
443
  .then((result) => {
@@ -498,7 +500,7 @@ export const PortableTextEditable = forwardRef<
498
500
  return error
499
501
  })
500
502
  .finally(() => {
501
- editorActor.send({type: 'notify.done loading'})
503
+ relayActor.send({type: 'done loading'})
502
504
  })
503
505
  } else if (event.nativeEvent.clipboardData) {
504
506
  // Prevent Slate from handling the event
@@ -529,7 +531,7 @@ export const PortableTextEditable = forwardRef<
529
531
 
530
532
  debug('No result from custom paste handler, pasting normally')
531
533
  },
532
- [editorActor, onPaste, portableTextEditor, slateEditor],
534
+ [editorActor, onPaste, portableTextEditor, relayActor, slateEditor],
533
535
  )
534
536
 
535
537
  const handleOnFocus: FocusEventHandler<HTMLDivElement> = useCallback(
@@ -544,18 +546,18 @@ export const PortableTextEditable = forwardRef<
544
546
  Transforms.select(slateEditor, Editor.start(slateEditor, []))
545
547
  slateEditor.onChange()
546
548
  }
547
- editorActor.send({type: 'notify.focused', event})
549
+ relayActor.send({type: 'focused', event})
548
550
  const newSelection = PortableTextEditor.getSelection(portableTextEditor)
549
551
  // If the selection is the same, emit it explicitly here as there is no actual onChange event triggered.
550
552
  if (selection === newSelection) {
551
- editorActor.send({
552
- type: 'notify.selection',
553
+ relayActor.send({
554
+ type: 'selection',
553
555
  selection,
554
556
  })
555
557
  }
556
558
  }
557
559
  },
558
- [editorActor, onFocus, slateEditor, portableTextEditor],
560
+ [onFocus, slateEditor, portableTextEditor, relayActor],
559
561
  )
560
562
 
561
563
  const handleClick = useCallback(
@@ -595,10 +597,10 @@ export const PortableTextEditable = forwardRef<
595
597
  onBlur(event)
596
598
  }
597
599
  if (!event.isPropagationStopped()) {
598
- editorActor.send({type: 'notify.blurred', event})
600
+ relayActor.send({type: 'blurred', event})
599
601
  }
600
602
  },
601
- [editorActor, onBlur],
603
+ [relayActor, onBlur],
602
604
  )
603
605
 
604
606
  const handleOnBeforeInput = useCallback(
@@ -15,7 +15,6 @@ import {
15
15
  import {Subject} from 'rxjs'
16
16
  import {Slate} from 'slate-react'
17
17
  import {debugWithName} from '../internal-utils/debug'
18
- import {compileType} from '../internal-utils/schema'
19
18
  import {stopActor} from '../internal-utils/stop-actor'
20
19
  import type {AddedAnnotationPaths} from '../operations/behavior.operation.annotation.add'
21
20
  import type {
@@ -30,11 +29,11 @@ import type {
30
29
  import {createInternalEditor, type InternalEditor} from './create-editor'
31
30
  import {EditorActorContext} from './editor-actor-context'
32
31
  import type {EditorActor} from './editor-machine'
33
- import {legacySchemaToEditorSchema} from './editor-schema'
34
32
  import {PortableTextEditorContext} from './hooks/usePortableTextEditor'
35
33
  import {PortableTextEditorSelectionProvider} from './hooks/usePortableTextEditorSelection'
36
- import {createLegacySchema} from './legacy-schema'
37
34
  import type {MutationActor} from './mutation-machine'
35
+ import {RelayActorContext} from './relay-actor-context'
36
+ import type {RelayActor} from './relay-machine'
38
37
  import {eventToChange} from './route-events-to-changes'
39
38
  import type {SyncActor} from './sync-machine'
40
39
 
@@ -135,6 +134,7 @@ export class PortableTextEditor extends Component<
135
134
  private actors?: {
136
135
  editorActor: EditorActor
137
136
  mutationActor: MutationActor
137
+ relayActor: RelayActor
138
138
  syncActor: SyncActor
139
139
  }
140
140
 
@@ -162,7 +162,7 @@ export class PortableTextEditor extends Component<
162
162
 
163
163
  this.unsubscribers.push(
164
164
  (() => {
165
- const subscription = actors.editorActor.on('*', (event) => {
165
+ const subscription = actors.relayActor.on('*', (event) => {
166
166
  const change = eventToChange(event)
167
167
 
168
168
  if (change) {
@@ -200,6 +200,7 @@ export class PortableTextEditor extends Component<
200
200
 
201
201
  this.actors.editorActor.start()
202
202
  this.actors.mutationActor.start()
203
+ this.actors.relayActor.start()
203
204
  this.actors.syncActor.start()
204
205
  }
205
206
 
@@ -210,16 +211,7 @@ export class PortableTextEditor extends Component<
210
211
  !prevProps.editor &&
211
212
  this.props.schemaType !== prevProps.schemaType
212
213
  ) {
213
- this.schemaTypes = createLegacySchema(
214
- this.props.schemaType.hasOwnProperty('jsonType')
215
- ? this.props.schemaType
216
- : compileType(this.props.schemaType),
217
- )
218
-
219
- this.editor._internal.editorActor.send({
220
- type: 'update schema',
221
- schema: legacySchemaToEditorSchema(this.schemaTypes),
222
- })
214
+ console.warn('Updating schema type is no longer supported')
223
215
  }
224
216
 
225
217
  if (!this.props.editor && !prevProps.editor) {
@@ -264,6 +256,7 @@ export class PortableTextEditor extends Component<
264
256
  if (this.actors) {
265
257
  stopActor(this.actors.editorActor)
266
258
  stopActor(this.actors.mutationActor)
259
+ stopActor(this.actors.relayActor)
267
260
  stopActor(this.actors.syncActor)
268
261
  }
269
262
  }
@@ -289,18 +282,20 @@ export class PortableTextEditor extends Component<
289
282
  />
290
283
  ) : null}
291
284
  <EditorActorContext.Provider value={this.editor._internal.editorActor}>
292
- <Slate
293
- editor={this.editor._internal.slateEditor.instance}
294
- initialValue={this.editor._internal.slateEditor.initialValue}
295
- >
296
- <PortableTextEditorContext.Provider value={this}>
297
- <PortableTextEditorSelectionProvider
298
- editorActor={this.editor._internal.editorActor}
299
- >
300
- {this.props.children}
301
- </PortableTextEditorSelectionProvider>
302
- </PortableTextEditorContext.Provider>
303
- </Slate>
285
+ <RelayActorContext.Provider value={this.actors!.relayActor}>
286
+ <Slate
287
+ editor={this.editor._internal.slateEditor.instance}
288
+ initialValue={this.editor._internal.slateEditor.initialValue}
289
+ >
290
+ <PortableTextEditorContext.Provider value={this}>
291
+ <PortableTextEditorSelectionProvider
292
+ editorActor={this.editor._internal.editorActor}
293
+ >
294
+ {this.props.children}
295
+ </PortableTextEditorSelectionProvider>
296
+ </PortableTextEditorContext.Provider>
297
+ </Slate>
298
+ </RelayActorContext.Provider>
304
299
  </EditorActorContext.Provider>
305
300
  </>
306
301
  )
@@ -127,23 +127,23 @@ describe('Feature: Self-solving', () => {
127
127
  },
128
128
  })
129
129
  expect(onChange).toHaveBeenNthCalledWith(4, {
130
- type: 'patch',
131
- patch: spanPatch,
130
+ type: 'selection',
131
+ selection: {
132
+ ...getTextSelection(initialValue, 'foo'),
133
+ backward: false,
134
+ },
132
135
  })
133
136
  expect(onChange).toHaveBeenNthCalledWith(5, {
134
137
  type: 'patch',
135
- patch: blockPatch,
138
+ patch: spanPatch,
136
139
  })
137
140
  expect(onChange).toHaveBeenNthCalledWith(6, {
138
141
  type: 'patch',
139
- patch: strongPatch,
142
+ patch: blockPatch,
140
143
  })
141
144
  expect(onChange).toHaveBeenNthCalledWith(7, {
142
- type: 'selection',
143
- selection: {
144
- ...getTextSelection(initialValue, 'foo'),
145
- backward: false,
146
- },
145
+ type: 'patch',
146
+ patch: strongPatch,
147
147
  })
148
148
  expect(onChange).toHaveBeenNthCalledWith(8, {
149
149
  type: 'mutation',
@@ -20,6 +20,7 @@ import {defaultKeyGenerator} from './key-generator'
20
20
  import {createLegacySchema} from './legacy-schema'
21
21
  import {mutationMachine, type MutationActor} from './mutation-machine'
22
22
  import {createEditableAPI} from './plugins/createWithEditableAPI'
23
+ import {relayMachine, type RelayActor} from './relay-machine'
23
24
  import {syncMachine, type SyncActor} from './sync-machine'
24
25
 
25
26
  const debug = debugWithName('setup')
@@ -32,40 +33,11 @@ export type InternalEditor = Editor & {
32
33
  }
33
34
  }
34
35
 
35
- function compileSchemasFromEditorConfig(config: EditorConfig) {
36
- const legacySchema = config.schemaDefinition
37
- ? compileSchemaDefinitionToLegacySchema(config.schemaDefinition)
38
- : createLegacySchema(
39
- config.schema.hasOwnProperty('jsonType')
40
- ? config.schema
41
- : compileType(config.schema),
42
- )
43
- const schema = legacySchemaToEditorSchema(legacySchema)
44
-
45
- return {
46
- legacySchema,
47
- schema,
48
- }
49
- }
50
-
51
- export function editorConfigToMachineInput(config: EditorConfig) {
52
- const {legacySchema, schema} = compileSchemasFromEditorConfig(config)
53
-
54
- return {
55
- converters: createCoreConverters(legacySchema),
56
- getLegacySchema: () => legacySchema,
57
- keyGenerator: config.keyGenerator ?? defaultKeyGenerator,
58
- maxBlocks: config.maxBlocks,
59
- readOnly: config.readOnly,
60
- schema,
61
- initialValue: config.initialValue,
62
- } as const
63
- }
64
-
65
36
  export function createInternalEditor(config: EditorConfig): {
66
37
  actors: {
67
38
  editorActor: EditorActor
68
39
  mutationActor: MutationActor
40
+ relayActor: RelayActor
69
41
  syncActor: SyncActor
70
42
  }
71
43
  editor: InternalEditor
@@ -77,10 +49,16 @@ export function createInternalEditor(config: EditorConfig): {
77
49
  const editorActor = createActor(editorMachine, {
78
50
  input: editorConfigToMachineInput(config),
79
51
  })
80
- const slateEditor = createSlateEditor({editorActor, subscriptions})
52
+ const relayActor = createActor(relayMachine)
53
+ const slateEditor = createSlateEditor({
54
+ editorActor,
55
+ relayActor,
56
+ subscriptions,
57
+ })
81
58
  const editable = createEditableAPI(slateEditor.instance, editorActor)
82
59
  const {mutationActor, syncActor} = createActors({
83
60
  editorActor,
61
+ relayActor,
84
62
  slateEditor: slateEditor.instance,
85
63
  subscriptions,
86
64
  })
@@ -122,10 +100,8 @@ export function createInternalEditor(config: EditorConfig): {
122
100
  syncActor.send(event)
123
101
  break
124
102
 
125
- case 'update key generator':
126
103
  case 'update readOnly':
127
104
  case 'patches':
128
- case 'update schema':
129
105
  case 'update maxBlocks':
130
106
  editorActor.send(event)
131
107
  break
@@ -168,12 +144,11 @@ export function createInternalEditor(config: EditorConfig): {
168
144
  }
169
145
  },
170
146
  on: (event, listener) => {
171
- const subscription = editorActor.on(event, (event) => {
147
+ const subscription = relayActor.on(event, (event) => {
172
148
  switch (event.type) {
173
149
  case 'blurred':
174
150
  case 'done loading':
175
151
  case 'editable':
176
- case 'error':
177
152
  case 'focused':
178
153
  case 'invalid value':
179
154
  case 'loading':
@@ -201,6 +176,7 @@ export function createInternalEditor(config: EditorConfig): {
201
176
  actors: {
202
177
  editorActor,
203
178
  mutationActor,
179
+ relayActor,
204
180
  syncActor,
205
181
  },
206
182
  editor,
@@ -208,18 +184,52 @@ export function createInternalEditor(config: EditorConfig): {
208
184
  }
209
185
  }
210
186
 
187
+ function editorConfigToMachineInput(config: EditorConfig) {
188
+ const {legacySchema, schema} = compileSchemasFromEditorConfig(config)
189
+
190
+ return {
191
+ converters: createCoreConverters(legacySchema),
192
+ getLegacySchema: () => legacySchema,
193
+ keyGenerator: config.keyGenerator ?? defaultKeyGenerator,
194
+ maxBlocks: config.maxBlocks,
195
+ readOnly: config.readOnly,
196
+ schema,
197
+ initialValue: config.initialValue,
198
+ } as const
199
+ }
200
+
201
+ function compileSchemasFromEditorConfig(config: EditorConfig) {
202
+ const legacySchema = config.schemaDefinition
203
+ ? compileSchemaDefinitionToLegacySchema(config.schemaDefinition)
204
+ : createLegacySchema(
205
+ config.schema.hasOwnProperty('jsonType')
206
+ ? config.schema
207
+ : compileType(config.schema),
208
+ )
209
+ const schema = legacySchemaToEditorSchema(legacySchema)
210
+
211
+ return {
212
+ legacySchema,
213
+ schema,
214
+ }
215
+ }
216
+
211
217
  function createActors(config: {
212
218
  editorActor: EditorActor
219
+ relayActor: RelayActor
213
220
  slateEditor: PortableTextSlateEditor
214
221
  subscriptions: Array<() => () => void>
215
222
  }): {
216
- syncActor: SyncActor
217
223
  mutationActor: MutationActor
224
+ syncActor: SyncActor
218
225
  } {
219
226
  debug('Creating new Actors')
220
227
 
221
228
  const mutationActor = createActor(mutationMachine, {
222
229
  input: {
230
+ readOnly: config.editorActor
231
+ .getSnapshot()
232
+ .matches({'edit mode': 'read only'}),
223
233
  schema: config.editorActor.getSnapshot().context.schema,
224
234
  slateEditor: config.slateEditor,
225
235
  },
@@ -239,8 +249,8 @@ function createActors(config: {
239
249
 
240
250
  config.subscriptions.push(() => {
241
251
  const subscription = mutationActor.on('*', (event) => {
242
- if (event.type === 'has pending patches') {
243
- syncActor.send({type: 'has pending patches'})
252
+ if (event.type === 'has pending mutations') {
253
+ syncActor.send({type: 'has pending mutations'})
244
254
  }
245
255
  if (event.type === 'mutation') {
246
256
  syncActor.send({type: 'mutation'})
@@ -251,6 +261,24 @@ function createActors(config: {
251
261
  value: event.snapshot,
252
262
  })
253
263
  }
264
+ if (event.type === 'patch') {
265
+ config.relayActor.send(event)
266
+ }
267
+ })
268
+
269
+ return () => {
270
+ subscription.unsubscribe()
271
+ }
272
+ })
273
+
274
+ config.subscriptions.push(() => {
275
+ const subscription = config.relayActor.on('*', (event) => {
276
+ if (event.type === 'selection') {
277
+ config.editorActor.send({
278
+ type: 'update selection',
279
+ selection: event.selection,
280
+ })
281
+ }
254
282
  })
255
283
 
256
284
  return () => {
@@ -262,16 +290,10 @@ function createActors(config: {
262
290
  const subscription = syncActor.on('*', (event) => {
263
291
  switch (event.type) {
264
292
  case 'invalid value':
265
- config.editorActor.send({
266
- ...event,
267
- type: 'notify.invalid value',
268
- })
293
+ config.relayActor.send(event)
269
294
  break
270
295
  case 'value changed':
271
- config.editorActor.send({
272
- ...event,
273
- type: 'notify.value changed',
274
- })
296
+ config.relayActor.send(event)
275
297
  break
276
298
  case 'patch':
277
299
  config.editorActor.send({
@@ -298,8 +320,10 @@ function createActors(config: {
298
320
  config.subscriptions.push(() => {
299
321
  const subscription = config.editorActor.subscribe((snapshot) => {
300
322
  if (snapshot.matches({'edit mode': 'read only'})) {
323
+ mutationActor.send({type: 'update readOnly', readOnly: true})
301
324
  syncActor.send({type: 'update readOnly', readOnly: true})
302
325
  } else {
326
+ mutationActor.send({type: 'update readOnly', readOnly: false})
303
327
  syncActor.send({type: 'update readOnly', readOnly: false})
304
328
  }
305
329
  })
@@ -311,8 +335,16 @@ function createActors(config: {
311
335
 
312
336
  config.subscriptions.push(() => {
313
337
  const subscription = config.editorActor.on('*', (event) => {
314
- if (event.type === 'internal.patch') {
315
- mutationActor.send({...event, type: 'patch'})
338
+ switch (event.type) {
339
+ case 'editable':
340
+ case 'mutation':
341
+ case 'ready':
342
+ case 'read only':
343
+ config.relayActor.send(event)
344
+ break
345
+ case 'internal.patch':
346
+ mutationActor.send({...event, type: 'patch'})
347
+ break
316
348
  }
317
349
  })
318
350
 
@@ -322,7 +354,7 @@ function createActors(config: {
322
354
  })
323
355
 
324
356
  return {
325
- syncActor,
326
357
  mutationActor,
358
+ syncActor,
327
359
  }
328
360
  }
@@ -8,11 +8,13 @@ import {
8
8
  import type {PortableTextSlateEditor} from '../types/editor'
9
9
  import type {EditorActor} from './editor-machine'
10
10
  import {withPlugins} from './plugins/with-plugins'
11
+ import type {RelayActor} from './relay-machine'
11
12
 
12
13
  const debug = debugWithName('setup')
13
14
 
14
15
  type SlateEditorConfig = {
15
16
  editorActor: EditorActor
17
+ relayActor: RelayActor
16
18
  subscriptions: Array<() => () => void>
17
19
  }
18
20
 
@@ -26,6 +28,7 @@ export function createSlateEditor(config: SlateEditorConfig): SlateEditor {
26
28
 
27
29
  const instance = withPlugins(withReact(createEditor()), {
28
30
  editorActor: config.editorActor,
31
+ relayActor: config.relayActor,
29
32
  subscriptions: config.subscriptions,
30
33
  })
31
34