@portabletext/editor 1.49.7 → 1.49.9
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 -272
- package/lib/behaviors/index.d.ts +24 -272
- package/lib/index.cjs +5487 -5431
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +35 -277
- package/lib/index.d.ts +35 -277
- package/lib/index.js +5745 -5689
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.d.cts +31 -277
- package/lib/plugins/index.d.ts +31 -277
- package/lib/selectors/index.d.cts +24 -272
- package/lib/selectors/index.d.ts +24 -272
- package/lib/utils/index.d.cts +24 -272
- package/lib/utils/index.d.ts +24 -272
- package/package.json +1 -1
- package/src/editor/Editable.tsx +1 -0
- package/src/editor/PortableTextEditor.tsx +73 -127
- package/src/editor/__tests__/PortableTextEditor.test.tsx +1 -0
- package/src/editor/create-editor.ts +159 -5
- package/src/editor/create-slate-editor.tsx +4 -21
- package/src/editor/editor-machine.ts +2 -9
- package/src/editor/editor-provider.tsx +44 -29
- package/src/editor/mutation-machine.ts +3 -0
- package/src/editor/route-events-to-changes.tsx +81 -0
- package/src/editor/sync-machine.ts +34 -0
- package/src/editor.ts +7 -1
- package/src/internal-utils/applyPatch.ts +21 -4
- package/src/internal-utils/stop-actor.ts +43 -0
- package/src/internal-utils/text-selection.ts +3 -1
- package/src/internal-utils/use-constant.ts +15 -0
- package/src/editor/__tests__/pteWarningsSelfSolving.test.tsx +0 -364
- package/src/editor/components/Synchronizer.tsx +0 -134
|
@@ -14,11 +14,9 @@ import {
|
|
|
14
14
|
} from 'react'
|
|
15
15
|
import {Subject} from 'rxjs'
|
|
16
16
|
import {Slate} from 'slate-react'
|
|
17
|
-
import {useEffectEvent} from 'use-effect-event'
|
|
18
|
-
import {createActor} from 'xstate'
|
|
19
|
-
import {createCoreConverters} from '../converters/converters.core'
|
|
20
17
|
import {debugWithName} from '../internal-utils/debug'
|
|
21
18
|
import {compileType} from '../internal-utils/schema'
|
|
19
|
+
import {stopActor} from '../internal-utils/stop-actor'
|
|
22
20
|
import type {AddedAnnotationPaths} from '../operations/behavior.operation.annotation.add'
|
|
23
21
|
import type {
|
|
24
22
|
EditableAPI,
|
|
@@ -29,15 +27,16 @@ import type {
|
|
|
29
27
|
PatchObservable,
|
|
30
28
|
PortableTextMemberSchemaTypes,
|
|
31
29
|
} from '../types/editor'
|
|
32
|
-
import {Synchronizer} from './components/Synchronizer'
|
|
33
30
|
import {createInternalEditor, type InternalEditor} from './create-editor'
|
|
34
31
|
import {EditorActorContext} from './editor-actor-context'
|
|
35
|
-
import
|
|
32
|
+
import type {EditorActor} from './editor-machine'
|
|
36
33
|
import {legacySchemaToEditorSchema} from './editor-schema'
|
|
37
34
|
import {PortableTextEditorContext} from './hooks/usePortableTextEditor'
|
|
38
35
|
import {PortableTextEditorSelectionProvider} from './hooks/usePortableTextEditorSelection'
|
|
39
|
-
import {defaultKeyGenerator} from './key-generator'
|
|
40
36
|
import {createLegacySchema} from './legacy-schema'
|
|
37
|
+
import type {MutationActor} from './mutation-machine'
|
|
38
|
+
import {eventToChange} from './route-events-to-changes'
|
|
39
|
+
import type {SyncActor} from './sync-machine'
|
|
41
40
|
|
|
42
41
|
const debug = debugWithName('component:PortableTextEditor')
|
|
43
42
|
|
|
@@ -133,6 +132,14 @@ export class PortableTextEditor extends Component<
|
|
|
133
132
|
*/
|
|
134
133
|
private editable: EditableAPI
|
|
135
134
|
|
|
135
|
+
private actors?: {
|
|
136
|
+
editorActor: EditorActor
|
|
137
|
+
mutationActor: MutationActor
|
|
138
|
+
syncActor: SyncActor
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private unsubscribers: Array<() => void> = []
|
|
142
|
+
|
|
136
143
|
constructor(props: PortableTextEditorProps) {
|
|
137
144
|
super(props)
|
|
138
145
|
|
|
@@ -142,35 +149,60 @@ export class PortableTextEditor extends Component<
|
|
|
142
149
|
.getSnapshot()
|
|
143
150
|
.context.getLegacySchema()
|
|
144
151
|
} else {
|
|
145
|
-
const
|
|
146
|
-
props.
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
getLegacySchema: () => legacySchema,
|
|
155
|
-
initialValue: props.value,
|
|
156
|
-
keyGenerator: props.keyGenerator ?? defaultKeyGenerator,
|
|
157
|
-
maxBlocks:
|
|
158
|
-
props.maxBlocks === undefined
|
|
159
|
-
? undefined
|
|
160
|
-
: Number.parseInt(props.maxBlocks.toString(), 10),
|
|
161
|
-
readOnly: props.readOnly,
|
|
162
|
-
schema,
|
|
163
|
-
},
|
|
152
|
+
const {actors, editor, subscriptions} = createInternalEditor({
|
|
153
|
+
initialValue: props.value,
|
|
154
|
+
keyGenerator: props.keyGenerator,
|
|
155
|
+
maxBlocks:
|
|
156
|
+
props.maxBlocks === undefined
|
|
157
|
+
? undefined
|
|
158
|
+
: Number.parseInt(props.maxBlocks.toString(), 10),
|
|
159
|
+
readOnly: props.readOnly,
|
|
160
|
+
schema: props.schemaType,
|
|
164
161
|
})
|
|
165
|
-
editorActor.start()
|
|
166
162
|
|
|
167
|
-
this.
|
|
168
|
-
|
|
163
|
+
this.unsubscribers.push(
|
|
164
|
+
(() => {
|
|
165
|
+
const subscription = actors.editorActor.on('*', (event) => {
|
|
166
|
+
const change = eventToChange(event)
|
|
167
|
+
|
|
168
|
+
if (change) {
|
|
169
|
+
props.onChange(change)
|
|
170
|
+
|
|
171
|
+
this.change$.next(change)
|
|
172
|
+
}
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
return () => {
|
|
176
|
+
subscription.unsubscribe()
|
|
177
|
+
}
|
|
178
|
+
})(),
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
for (const subscription of subscriptions) {
|
|
182
|
+
this.unsubscribers.push(subscription())
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
this.actors = actors
|
|
186
|
+
|
|
187
|
+
this.editor = editor
|
|
188
|
+
this.schemaTypes = actors.editorActor
|
|
189
|
+
.getSnapshot()
|
|
190
|
+
.context.getLegacySchema()
|
|
169
191
|
}
|
|
170
192
|
|
|
171
193
|
this.editable = this.editor._internal.editable
|
|
172
194
|
}
|
|
173
195
|
|
|
196
|
+
componentDidMount(): void {
|
|
197
|
+
if (!this.actors) {
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this.actors.editorActor.start()
|
|
202
|
+
this.actors.mutationActor.start()
|
|
203
|
+
this.actors.syncActor.start()
|
|
204
|
+
}
|
|
205
|
+
|
|
174
206
|
componentDidUpdate(prevProps: PortableTextEditorProps) {
|
|
175
207
|
// Set up the schema type lookup table again if the source schema type changes
|
|
176
208
|
if (
|
|
@@ -209,7 +241,7 @@ export class PortableTextEditor extends Component<
|
|
|
209
241
|
}
|
|
210
242
|
|
|
211
243
|
if (this.props.value !== prevProps.value) {
|
|
212
|
-
this.editor.
|
|
244
|
+
this.editor.send({
|
|
213
245
|
type: 'update value',
|
|
214
246
|
value: this.props.value,
|
|
215
247
|
})
|
|
@@ -224,6 +256,18 @@ export class PortableTextEditor extends Component<
|
|
|
224
256
|
}
|
|
225
257
|
}
|
|
226
258
|
|
|
259
|
+
componentWillUnmount(): void {
|
|
260
|
+
for (const unsubscribe of this.unsubscribers) {
|
|
261
|
+
unsubscribe()
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
if (this.actors) {
|
|
265
|
+
stopActor(this.actors.editorActor)
|
|
266
|
+
stopActor(this.actors.mutationActor)
|
|
267
|
+
stopActor(this.actors.syncActor)
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
227
271
|
public setEditable = (editable: EditableAPI) => {
|
|
228
272
|
this.editor._internal.editable = {
|
|
229
273
|
...this.editor._internal.editable,
|
|
@@ -244,23 +288,6 @@ export class PortableTextEditor extends Component<
|
|
|
244
288
|
patches$={legacyPatches}
|
|
245
289
|
/>
|
|
246
290
|
) : null}
|
|
247
|
-
<RouteEventsToChanges
|
|
248
|
-
editorActor={this.editor._internal.editorActor}
|
|
249
|
-
onChange={(change) => {
|
|
250
|
-
if (!this.props.editor) {
|
|
251
|
-
this.props.onChange(change)
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* For backwards compatibility, we relay all changes to the
|
|
255
|
-
* `change$` Subject as well.
|
|
256
|
-
*/
|
|
257
|
-
this.change$.next(change)
|
|
258
|
-
}}
|
|
259
|
-
/>
|
|
260
|
-
<Synchronizer
|
|
261
|
-
editorActor={this.editor._internal.editorActor}
|
|
262
|
-
slateEditor={this.editor._internal.slateEditor.instance}
|
|
263
|
-
/>
|
|
264
291
|
<EditorActorContext.Provider value={this.editor._internal.editorActor}>
|
|
265
292
|
<Slate
|
|
266
293
|
editor={this.editor._internal.slateEditor.instance}
|
|
@@ -775,84 +802,3 @@ function RoutePatchesObservableToEditorActor(props: {
|
|
|
775
802
|
|
|
776
803
|
return null
|
|
777
804
|
}
|
|
778
|
-
|
|
779
|
-
export function RouteEventsToChanges(props: {
|
|
780
|
-
editorActor: EditorActor
|
|
781
|
-
onChange: (change: EditorChange) => void
|
|
782
|
-
}) {
|
|
783
|
-
// We want to ensure that _when_ `props.onChange` is called, it uses the current value.
|
|
784
|
-
// But we don't want to have the `useEffect` run setup + teardown + setup every time the prop might change, as that's unnecessary.
|
|
785
|
-
// So we use our own polyfill that lets us use an upcoming React hook that solves this exact problem.
|
|
786
|
-
// https://19.react.dev/learn/separating-events-from-effects#declaring-an-effect-event
|
|
787
|
-
const handleChange = useEffectEvent((change: EditorChange) =>
|
|
788
|
-
props.onChange(change),
|
|
789
|
-
)
|
|
790
|
-
|
|
791
|
-
useEffect(() => {
|
|
792
|
-
debug('Subscribing to editor changes')
|
|
793
|
-
const sub = props.editorActor.on('*', (event) => {
|
|
794
|
-
switch (event.type) {
|
|
795
|
-
case 'blurred': {
|
|
796
|
-
handleChange({type: 'blur', event: event.event})
|
|
797
|
-
break
|
|
798
|
-
}
|
|
799
|
-
case 'patch':
|
|
800
|
-
handleChange(event)
|
|
801
|
-
break
|
|
802
|
-
case 'loading': {
|
|
803
|
-
handleChange({type: 'loading', isLoading: true})
|
|
804
|
-
break
|
|
805
|
-
}
|
|
806
|
-
case 'done loading': {
|
|
807
|
-
handleChange({type: 'loading', isLoading: false})
|
|
808
|
-
break
|
|
809
|
-
}
|
|
810
|
-
case 'focused': {
|
|
811
|
-
handleChange({type: 'focus', event: event.event})
|
|
812
|
-
break
|
|
813
|
-
}
|
|
814
|
-
case 'value changed': {
|
|
815
|
-
handleChange({type: 'value', value: event.value})
|
|
816
|
-
break
|
|
817
|
-
}
|
|
818
|
-
case 'invalid value': {
|
|
819
|
-
handleChange({
|
|
820
|
-
type: 'invalidValue',
|
|
821
|
-
resolution: event.resolution,
|
|
822
|
-
value: event.value,
|
|
823
|
-
})
|
|
824
|
-
break
|
|
825
|
-
}
|
|
826
|
-
case 'error': {
|
|
827
|
-
handleChange({
|
|
828
|
-
...event,
|
|
829
|
-
level: 'warning',
|
|
830
|
-
})
|
|
831
|
-
break
|
|
832
|
-
}
|
|
833
|
-
case 'mutation': {
|
|
834
|
-
handleChange(event)
|
|
835
|
-
break
|
|
836
|
-
}
|
|
837
|
-
case 'ready': {
|
|
838
|
-
handleChange(event)
|
|
839
|
-
break
|
|
840
|
-
}
|
|
841
|
-
case 'selection': {
|
|
842
|
-
handleChange(event)
|
|
843
|
-
break
|
|
844
|
-
}
|
|
845
|
-
case 'unset': {
|
|
846
|
-
handleChange(event)
|
|
847
|
-
break
|
|
848
|
-
}
|
|
849
|
-
}
|
|
850
|
-
})
|
|
851
|
-
return () => {
|
|
852
|
-
debug('Unsubscribing to changes')
|
|
853
|
-
sub.unsubscribe()
|
|
854
|
-
}
|
|
855
|
-
}, [props.editorActor])
|
|
856
|
-
|
|
857
|
-
return null
|
|
858
|
-
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import {createActor} from 'xstate'
|
|
1
2
|
import {createCoreConverters} from '../converters/converters.core'
|
|
2
3
|
import type {Editor, EditorConfig} from '../editor'
|
|
4
|
+
import {debugWithName} from '../internal-utils/debug'
|
|
3
5
|
import {compileType} from '../internal-utils/schema'
|
|
6
|
+
import {fromSlateValue} from '../internal-utils/values'
|
|
7
|
+
import {KEY_TO_VALUE_ELEMENT} from '../internal-utils/weakMaps'
|
|
4
8
|
import {corePriority} from '../priority/priority.core'
|
|
5
9
|
import {createEditorPriority} from '../priority/priority.types'
|
|
6
|
-
import type {EditableAPI} from '../types/editor'
|
|
10
|
+
import type {EditableAPI, PortableTextSlateEditor} from '../types/editor'
|
|
7
11
|
import {createSlateEditor, type SlateEditor} from './create-slate-editor'
|
|
8
12
|
import type {EditorActor} from './editor-machine'
|
|
13
|
+
import {editorMachine} from './editor-machine'
|
|
9
14
|
import {
|
|
10
15
|
compileSchemaDefinitionToLegacySchema,
|
|
11
16
|
legacySchemaToEditorSchema,
|
|
@@ -13,7 +18,11 @@ import {
|
|
|
13
18
|
import {getEditorSnapshot} from './editor-selector'
|
|
14
19
|
import {defaultKeyGenerator} from './key-generator'
|
|
15
20
|
import {createLegacySchema} from './legacy-schema'
|
|
21
|
+
import {mutationMachine, type MutationActor} from './mutation-machine'
|
|
16
22
|
import {createEditableAPI} from './plugins/createWithEditableAPI'
|
|
23
|
+
import {syncMachine, type SyncActor} from './sync-machine'
|
|
24
|
+
|
|
25
|
+
const debug = debugWithName('setup')
|
|
17
26
|
|
|
18
27
|
export type InternalEditor = Editor & {
|
|
19
28
|
_internal: {
|
|
@@ -53,11 +62,30 @@ export function editorConfigToMachineInput(config: EditorConfig) {
|
|
|
53
62
|
} as const
|
|
54
63
|
}
|
|
55
64
|
|
|
56
|
-
export function createInternalEditor(
|
|
57
|
-
|
|
65
|
+
export function createInternalEditor(config: EditorConfig): {
|
|
66
|
+
actors: {
|
|
67
|
+
editorActor: EditorActor
|
|
68
|
+
mutationActor: MutationActor
|
|
69
|
+
syncActor: SyncActor
|
|
70
|
+
}
|
|
71
|
+
editor: InternalEditor
|
|
72
|
+
subscriptions: Array<() => () => void>
|
|
73
|
+
} {
|
|
74
|
+
debug('Creating new Editor instance')
|
|
75
|
+
|
|
76
|
+
const subscriptions: Array<() => () => void> = []
|
|
77
|
+
const editorActor = createActor(editorMachine, {
|
|
78
|
+
input: editorConfigToMachineInput(config),
|
|
79
|
+
})
|
|
80
|
+
const slateEditor = createSlateEditor({editorActor, subscriptions})
|
|
58
81
|
const editable = createEditableAPI(slateEditor.instance, editorActor)
|
|
82
|
+
const {mutationActor, syncActor} = createActors({
|
|
83
|
+
editorActor,
|
|
84
|
+
slateEditor: slateEditor.instance,
|
|
85
|
+
subscriptions,
|
|
86
|
+
})
|
|
59
87
|
|
|
60
|
-
|
|
88
|
+
const editor = {
|
|
61
89
|
getSnapshot: () =>
|
|
62
90
|
getEditorSnapshot({
|
|
63
91
|
editorActorSnapshot: editorActor.getSnapshot(),
|
|
@@ -90,10 +118,13 @@ export function createInternalEditor(editorActor: EditorActor): InternalEditor {
|
|
|
90
118
|
},
|
|
91
119
|
send: (event) => {
|
|
92
120
|
switch (event.type) {
|
|
121
|
+
case 'update value':
|
|
122
|
+
syncActor.send(event)
|
|
123
|
+
break
|
|
124
|
+
|
|
93
125
|
case 'update key generator':
|
|
94
126
|
case 'update readOnly':
|
|
95
127
|
case 'patches':
|
|
96
|
-
case 'update value':
|
|
97
128
|
case 'update schema':
|
|
98
129
|
case 'update maxBlocks':
|
|
99
130
|
editorActor.send(event)
|
|
@@ -164,5 +195,128 @@ export function createInternalEditor(editorActor: EditorActor): InternalEditor {
|
|
|
164
195
|
editorActor,
|
|
165
196
|
slateEditor,
|
|
166
197
|
},
|
|
198
|
+
} satisfies InternalEditor
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
actors: {
|
|
202
|
+
editorActor,
|
|
203
|
+
mutationActor,
|
|
204
|
+
syncActor,
|
|
205
|
+
},
|
|
206
|
+
editor,
|
|
207
|
+
subscriptions,
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function createActors(config: {
|
|
212
|
+
editorActor: EditorActor
|
|
213
|
+
slateEditor: PortableTextSlateEditor
|
|
214
|
+
subscriptions: Array<() => () => void>
|
|
215
|
+
}): {
|
|
216
|
+
syncActor: SyncActor
|
|
217
|
+
mutationActor: MutationActor
|
|
218
|
+
} {
|
|
219
|
+
debug('Creating new Actors')
|
|
220
|
+
|
|
221
|
+
const mutationActor = createActor(mutationMachine, {
|
|
222
|
+
input: {
|
|
223
|
+
schema: config.editorActor.getSnapshot().context.schema,
|
|
224
|
+
slateEditor: config.slateEditor,
|
|
225
|
+
},
|
|
226
|
+
})
|
|
227
|
+
|
|
228
|
+
const syncActor = createActor(syncMachine, {
|
|
229
|
+
input: {
|
|
230
|
+
initialValue: config.editorActor.getSnapshot().context.initialValue,
|
|
231
|
+
keyGenerator: config.editorActor.getSnapshot().context.keyGenerator,
|
|
232
|
+
readOnly: config.editorActor
|
|
233
|
+
.getSnapshot()
|
|
234
|
+
.matches({'edit mode': 'read only'}),
|
|
235
|
+
schema: config.editorActor.getSnapshot().context.schema,
|
|
236
|
+
slateEditor: config.slateEditor,
|
|
237
|
+
},
|
|
238
|
+
})
|
|
239
|
+
|
|
240
|
+
config.subscriptions.push(() => {
|
|
241
|
+
const subscription = mutationActor.on('*', (event) => {
|
|
242
|
+
if (event.type === 'has pending patches') {
|
|
243
|
+
syncActor.send({type: 'has pending patches'})
|
|
244
|
+
}
|
|
245
|
+
if (event.type === 'mutation') {
|
|
246
|
+
syncActor.send({type: 'mutation'})
|
|
247
|
+
config.editorActor.send({
|
|
248
|
+
type: 'mutation',
|
|
249
|
+
patches: event.patches,
|
|
250
|
+
snapshot: event.snapshot,
|
|
251
|
+
value: event.snapshot,
|
|
252
|
+
})
|
|
253
|
+
}
|
|
254
|
+
})
|
|
255
|
+
|
|
256
|
+
return () => {
|
|
257
|
+
subscription.unsubscribe()
|
|
258
|
+
}
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
config.subscriptions.push(() => {
|
|
262
|
+
const subscription = syncActor.on('*', (event) => {
|
|
263
|
+
switch (event.type) {
|
|
264
|
+
case 'invalid value':
|
|
265
|
+
config.editorActor.send({
|
|
266
|
+
...event,
|
|
267
|
+
type: 'notify.invalid value',
|
|
268
|
+
})
|
|
269
|
+
break
|
|
270
|
+
case 'value changed':
|
|
271
|
+
config.editorActor.send({
|
|
272
|
+
...event,
|
|
273
|
+
type: 'notify.value changed',
|
|
274
|
+
})
|
|
275
|
+
break
|
|
276
|
+
case 'patch':
|
|
277
|
+
config.editorActor.send({
|
|
278
|
+
...event,
|
|
279
|
+
type: 'internal.patch',
|
|
280
|
+
value: fromSlateValue(
|
|
281
|
+
config.slateEditor.children,
|
|
282
|
+
config.editorActor.getSnapshot().context.schema.block.name,
|
|
283
|
+
KEY_TO_VALUE_ELEMENT.get(config.slateEditor),
|
|
284
|
+
),
|
|
285
|
+
})
|
|
286
|
+
break
|
|
287
|
+
|
|
288
|
+
default:
|
|
289
|
+
config.editorActor.send(event)
|
|
290
|
+
}
|
|
291
|
+
})
|
|
292
|
+
|
|
293
|
+
return () => {
|
|
294
|
+
subscription.unsubscribe()
|
|
295
|
+
}
|
|
296
|
+
})
|
|
297
|
+
|
|
298
|
+
config.subscriptions.push(() => {
|
|
299
|
+
const subscription = config.editorActor.on('*', (event) => {
|
|
300
|
+
if (
|
|
301
|
+
config.editorActor.getSnapshot().matches({'edit mode': 'read only'})
|
|
302
|
+
) {
|
|
303
|
+
syncActor.send({type: 'update readOnly', readOnly: true})
|
|
304
|
+
} else {
|
|
305
|
+
syncActor.send({type: 'update readOnly', readOnly: false})
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (event.type === 'internal.patch') {
|
|
309
|
+
mutationActor.send({...event, type: 'patch'})
|
|
310
|
+
}
|
|
311
|
+
})
|
|
312
|
+
|
|
313
|
+
return () => {
|
|
314
|
+
subscription.unsubscribe()
|
|
315
|
+
}
|
|
316
|
+
})
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
syncActor,
|
|
320
|
+
mutationActor,
|
|
167
321
|
}
|
|
168
322
|
}
|
|
@@ -9,10 +9,11 @@ import type {PortableTextSlateEditor} from '../types/editor'
|
|
|
9
9
|
import type {EditorActor} from './editor-machine'
|
|
10
10
|
import {withPlugins} from './plugins/with-plugins'
|
|
11
11
|
|
|
12
|
-
const debug = debugWithName('
|
|
12
|
+
const debug = debugWithName('setup')
|
|
13
13
|
|
|
14
14
|
type SlateEditorConfig = {
|
|
15
15
|
editorActor: EditorActor
|
|
16
|
+
subscriptions: Array<() => () => void>
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export type SlateEditor = {
|
|
@@ -20,33 +21,17 @@ export type SlateEditor = {
|
|
|
20
21
|
initialValue: Array<Descendant>
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
const slateEditors = new WeakMap<EditorActor, SlateEditor>()
|
|
24
|
-
|
|
25
24
|
export function createSlateEditor(config: SlateEditorConfig): SlateEditor {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (existingSlateEditor) {
|
|
29
|
-
debug('Reusing existing Slate editor instance', config.editorActor.id)
|
|
30
|
-
return existingSlateEditor
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
debug('Creating new Slate editor instance', config.editorActor.id)
|
|
34
|
-
|
|
35
|
-
const unsubscriptions: Array<() => void> = []
|
|
36
|
-
const subscriptions: Array<() => () => void> = []
|
|
25
|
+
debug('Creating new Slate editor instance')
|
|
37
26
|
|
|
38
27
|
const instance = withPlugins(withReact(createEditor()), {
|
|
39
28
|
editorActor: config.editorActor,
|
|
40
|
-
subscriptions,
|
|
29
|
+
subscriptions: config.subscriptions,
|
|
41
30
|
})
|
|
42
31
|
|
|
43
32
|
KEY_TO_VALUE_ELEMENT.set(instance, {})
|
|
44
33
|
KEY_TO_SLATE_ELEMENT.set(instance, {})
|
|
45
34
|
|
|
46
|
-
for (const subscription of subscriptions) {
|
|
47
|
-
unsubscriptions.push(subscription())
|
|
48
|
-
}
|
|
49
|
-
|
|
50
35
|
const initialValue = [instance.pteCreateTextBlock({decorators: []})]
|
|
51
36
|
|
|
52
37
|
const slateEditor: SlateEditor = {
|
|
@@ -54,7 +39,5 @@ export function createSlateEditor(config: SlateEditorConfig): SlateEditor {
|
|
|
54
39
|
initialValue,
|
|
55
40
|
}
|
|
56
41
|
|
|
57
|
-
slateEditors.set(config.editorActor, slateEditor)
|
|
58
|
-
|
|
59
42
|
return slateEditor
|
|
60
43
|
}
|
|
@@ -71,10 +71,6 @@ export type ExternalEditorEvent =
|
|
|
71
71
|
type: 'update key generator'
|
|
72
72
|
keyGenerator: () => string
|
|
73
73
|
}
|
|
74
|
-
| {
|
|
75
|
-
type: 'update value'
|
|
76
|
-
value: Array<PortableTextBlock> | undefined
|
|
77
|
-
}
|
|
78
74
|
| {
|
|
79
75
|
type: 'update maxBlocks'
|
|
80
76
|
maxBlocks: number | undefined
|
|
@@ -227,7 +223,7 @@ export const editorMachine = setup({
|
|
|
227
223
|
initialReadOnly: boolean
|
|
228
224
|
maxBlocks: number | undefined
|
|
229
225
|
selection: EditorSelection
|
|
230
|
-
|
|
226
|
+
initialValue: Array<PortableTextBlock> | undefined
|
|
231
227
|
internalDrag?: {
|
|
232
228
|
ghost?: HTMLElement
|
|
233
229
|
origin: Pick<EventPosition, 'selection'>
|
|
@@ -402,7 +398,7 @@ export const editorMachine = setup({
|
|
|
402
398
|
selection: null,
|
|
403
399
|
initialReadOnly: input.readOnly ?? false,
|
|
404
400
|
maxBlocks: input.maxBlocks,
|
|
405
|
-
|
|
401
|
+
initialValue: input.initialValue,
|
|
406
402
|
}),
|
|
407
403
|
on: {
|
|
408
404
|
'notify.blurred': {
|
|
@@ -434,9 +430,6 @@ export const editorMachine = setup({
|
|
|
434
430
|
actions: assign({keyGenerator: ({event}) => event.keyGenerator}),
|
|
435
431
|
},
|
|
436
432
|
'update schema': {actions: 'assign schema'},
|
|
437
|
-
'update value': {
|
|
438
|
-
actions: assign({incomingValue: ({event}) => event.value}),
|
|
439
|
-
},
|
|
440
433
|
'update maxBlocks': {
|
|
441
434
|
actions: assign({maxBlocks: ({event}) => event.maxBlocks}),
|
|
442
435
|
},
|
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import {useActorRef} from '@xstate/react'
|
|
2
1
|
import type React from 'react'
|
|
3
|
-
import {
|
|
2
|
+
import {useEffect} from 'react'
|
|
4
3
|
import {Slate} from 'slate-react'
|
|
5
4
|
import type {EditorConfig} from '../editor'
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
5
|
+
import {stopActor} from '../internal-utils/stop-actor'
|
|
6
|
+
import useConstant from '../internal-utils/use-constant'
|
|
7
|
+
import {createInternalEditor} from './create-editor'
|
|
8
8
|
import {EditorActorContext} from './editor-actor-context'
|
|
9
9
|
import {EditorContext} from './editor-context'
|
|
10
|
-
import {editorMachine} from './editor-machine'
|
|
11
10
|
import {PortableTextEditorContext} from './hooks/usePortableTextEditor'
|
|
12
11
|
import {PortableTextEditorSelectionProvider} from './hooks/usePortableTextEditorSelection'
|
|
13
12
|
import {
|
|
14
13
|
PortableTextEditor,
|
|
15
|
-
RouteEventsToChanges,
|
|
16
14
|
type PortableTextEditorProps,
|
|
17
15
|
} from './PortableTextEditor'
|
|
16
|
+
import {RouteEventsToChanges} from './route-events-to-changes'
|
|
18
17
|
|
|
19
18
|
/**
|
|
20
19
|
* @public
|
|
@@ -43,40 +42,56 @@ export type EditorProviderProps = {
|
|
|
43
42
|
* @group Components
|
|
44
43
|
*/
|
|
45
44
|
export function EditorProvider(props: EditorProviderProps) {
|
|
46
|
-
const
|
|
47
|
-
|
|
45
|
+
const {internalEditor, portableTextEditor} = useConstant(() => {
|
|
46
|
+
const internalEditor = createInternalEditor(props.initialConfig)
|
|
47
|
+
const portableTextEditor = new PortableTextEditor({
|
|
48
|
+
editor: internalEditor.editor,
|
|
49
|
+
} as unknown as PortableTextEditorProps)
|
|
50
|
+
|
|
51
|
+
return {internalEditor, portableTextEditor}
|
|
48
52
|
})
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
[
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
|
|
54
|
+
useEffect(() => {
|
|
55
|
+
const unsubscribers: Array<() => void> = []
|
|
56
|
+
|
|
57
|
+
for (const subscription of internalEditor.subscriptions) {
|
|
58
|
+
unsubscribers.push(subscription())
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
internalEditor.actors.editorActor.start()
|
|
62
|
+
internalEditor.actors.mutationActor.start()
|
|
63
|
+
internalEditor.actors.syncActor.start()
|
|
64
|
+
|
|
65
|
+
return () => {
|
|
66
|
+
for (const unsubscribe of unsubscribers) {
|
|
67
|
+
unsubscribe()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
stopActor(internalEditor.actors.editorActor)
|
|
71
|
+
stopActor(internalEditor.actors.mutationActor)
|
|
72
|
+
stopActor(internalEditor.actors.syncActor)
|
|
73
|
+
}
|
|
74
|
+
}, [internalEditor])
|
|
60
75
|
|
|
61
76
|
return (
|
|
62
|
-
<EditorContext.Provider value={internalEditor}>
|
|
77
|
+
<EditorContext.Provider value={internalEditor.editor}>
|
|
63
78
|
<RouteEventsToChanges
|
|
64
|
-
editorActor={editorActor}
|
|
79
|
+
editorActor={internalEditor.actors.editorActor}
|
|
65
80
|
onChange={(change) => {
|
|
66
81
|
portableTextEditor.change$.next(change)
|
|
67
82
|
}}
|
|
68
83
|
/>
|
|
69
|
-
<
|
|
70
|
-
editorActor={editorActor}
|
|
71
|
-
slateEditor={internalEditor._internal.slateEditor.instance}
|
|
72
|
-
/>
|
|
73
|
-
<EditorActorContext.Provider value={editorActor}>
|
|
84
|
+
<EditorActorContext.Provider value={internalEditor.actors.editorActor}>
|
|
74
85
|
<Slate
|
|
75
|
-
editor={internalEditor._internal.slateEditor.instance}
|
|
76
|
-
initialValue={
|
|
86
|
+
editor={internalEditor.editor._internal.slateEditor.instance}
|
|
87
|
+
initialValue={
|
|
88
|
+
internalEditor.editor._internal.slateEditor.initialValue
|
|
89
|
+
}
|
|
77
90
|
>
|
|
78
91
|
<PortableTextEditorContext.Provider value={portableTextEditor}>
|
|
79
|
-
<PortableTextEditorSelectionProvider
|
|
92
|
+
<PortableTextEditorSelectionProvider
|
|
93
|
+
editorActor={internalEditor.actors.editorActor}
|
|
94
|
+
>
|
|
80
95
|
{props.children}
|
|
81
96
|
</PortableTextEditorSelectionProvider>
|
|
82
97
|
</PortableTextEditorContext.Provider>
|
|
@@ -13,9 +13,12 @@ import {
|
|
|
13
13
|
stateIn,
|
|
14
14
|
type AnyEventObject,
|
|
15
15
|
} from 'xstate'
|
|
16
|
+
import type {ActorRefFrom} from 'xstate'
|
|
16
17
|
import type {PortableTextSlateEditor} from '../types/editor'
|
|
17
18
|
import type {EditorSchema} from './editor-schema'
|
|
18
19
|
|
|
20
|
+
export type MutationActor = ActorRefFrom<typeof mutationMachine>
|
|
21
|
+
|
|
19
22
|
/**
|
|
20
23
|
* Makes sure editor mutation events are debounced
|
|
21
24
|
*/
|