@portabletext/editor 1.15.3 → 1.16.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/lib/_chunks-cjs/behavior.core.cjs +25 -25
- package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
- package/lib/_chunks-cjs/selector.get-text-before.cjs +14 -14
- package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
- package/lib/_chunks-cjs/{selectors.cjs → selector.is-selection-collapsed.cjs} +8 -8
- package/lib/_chunks-cjs/selector.is-selection-collapsed.cjs.map +1 -0
- package/lib/_chunks-es/behavior.core.js +7 -7
- package/lib/_chunks-es/behavior.core.js.map +1 -1
- package/lib/_chunks-es/selector.get-text-before.js +14 -14
- package/lib/_chunks-es/selector.get-text-before.js.map +1 -1
- package/lib/_chunks-es/{selectors.js → selector.is-selection-collapsed.js} +8 -8
- package/lib/_chunks-es/selector.is-selection-collapsed.js.map +1 -0
- package/lib/behaviors/index.cjs +23 -23
- package/lib/behaviors/index.cjs.map +1 -1
- package/lib/behaviors/index.d.cts +1 -0
- package/lib/behaviors/index.d.ts +1 -0
- package/lib/behaviors/index.js +8 -8
- package/lib/behaviors/index.js.map +1 -1
- package/lib/index.cjs +863 -516
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +3816 -4457
- package/lib/index.d.ts +3816 -4457
- package/lib/index.js +860 -515
- package/lib/index.js.map +1 -1
- package/lib/selectors/index.cjs +166 -16
- package/lib/selectors/index.cjs.map +1 -1
- package/lib/selectors/index.d.cts +54 -5
- package/lib/selectors/index.d.ts +54 -5
- package/lib/selectors/index.js +154 -3
- package/lib/selectors/index.js.map +1 -1
- package/package.json +11 -11
- package/src/behaviors/behavior.code-editor.ts +5 -9
- package/src/behaviors/behavior.core.block-objects.ts +13 -19
- package/src/behaviors/behavior.core.lists.ts +11 -17
- package/src/behaviors/behavior.links.ts +4 -4
- package/src/behaviors/behavior.markdown.ts +16 -21
- package/src/editor/Editable.tsx +11 -4
- package/src/editor/PortableTextEditor.tsx +4 -4
- package/src/editor/{hooks/useSyncValue.test.tsx → __tests__/sync-value.test.tsx} +42 -23
- package/src/editor/components/Synchronizer.tsx +53 -80
- package/src/editor/create-editor.ts +4 -1
- package/src/editor/editor-machine.ts +135 -83
- package/src/editor/editor-provider.tsx +0 -3
- package/src/editor/editor-selector.ts +5 -0
- package/src/editor/editor-snapshot.ts +1 -0
- package/src/editor/get-active-decorators.ts +20 -0
- package/src/editor/mutation-machine.ts +100 -0
- package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +21 -15
- package/src/editor/plugins/createWithMaxBlocks.ts +1 -1
- package/src/editor/plugins/createWithPatches.ts +0 -4
- package/src/editor/plugins/createWithPlaceholderBlock.ts +1 -1
- package/src/editor/plugins/createWithPortableTextSelections.ts +4 -1
- package/src/editor/plugins/createWithUndoRedo.ts +3 -3
- package/src/editor/sync-machine.ts +661 -0
- package/src/editor/withSyncRangeDecorations.ts +17 -5
- package/src/selectors/_exports/index.ts +1 -0
- package/src/selectors/index.ts +9 -1
- package/src/selectors/selector.get-active-style.ts +37 -0
- package/src/selectors/selector.get-selected-spans.ts +136 -0
- package/src/selectors/selector.is-active-annotation.ts +49 -0
- package/src/selectors/selector.is-active-decorator.ts +21 -0
- package/src/selectors/selector.is-active-list-item.ts +13 -0
- package/src/selectors/selector.is-active-style.ts +13 -0
- package/src/selectors/selector.is-selection-collapsed.ts +12 -0
- package/src/selectors/selector.is-selection-expanded.ts +9 -0
- package/src/selectors/selectors.ts +0 -11
- package/src/utils/weakMaps.ts +0 -3
- package/src/utils/withChanges.ts +1 -8
- package/lib/_chunks-cjs/selectors.cjs.map +0 -1
- package/lib/_chunks-es/selectors.js.map +0 -1
- package/src/editor/hooks/useSyncValue.ts +0 -426
|
@@ -1,30 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import {useSelector} from '@xstate/react'
|
|
4
|
-
import {throttle} from 'lodash'
|
|
5
|
-
import {useCallback, useEffect, useRef} from 'react'
|
|
6
|
-
import {Editor} from 'slate'
|
|
1
|
+
import {useActorRef, useSelector} from '@xstate/react'
|
|
2
|
+
import {useEffect} from 'react'
|
|
7
3
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
8
4
|
import {debugWithName} from '../../utils/debug'
|
|
9
|
-
import {IS_PROCESSING_LOCAL_CHANGES} from '../../utils/weakMaps'
|
|
10
5
|
import type {EditorActor} from '../editor-machine'
|
|
11
|
-
import {
|
|
12
|
-
import
|
|
6
|
+
import {mutationMachine} from '../mutation-machine'
|
|
7
|
+
import {syncMachine} from '../sync-machine'
|
|
13
8
|
|
|
14
9
|
const debug = debugWithName('component:PortableTextEditor:Synchronizer')
|
|
15
|
-
const debugVerbose = debug.enabled && false
|
|
16
|
-
|
|
17
|
-
// The editor will commit changes in a throttled fashion in order
|
|
18
|
-
// not to overload the network and degrade performance while typing.
|
|
19
|
-
const FLUSH_PATCHES_THROTTLED_MS = process.env.NODE_ENV === 'test' ? 500 : 1000
|
|
20
10
|
|
|
21
11
|
/**
|
|
22
12
|
* @internal
|
|
23
13
|
*/
|
|
24
14
|
export interface SynchronizerProps {
|
|
25
15
|
editorActor: EditorActor
|
|
26
|
-
getValue: () => Array<PortableTextBlock> | undefined
|
|
27
|
-
portableTextEditor: PortableTextEditor
|
|
28
16
|
slateEditor: PortableTextSlateEditor
|
|
29
17
|
}
|
|
30
18
|
|
|
@@ -33,90 +21,75 @@ export interface SynchronizerProps {
|
|
|
33
21
|
* @internal
|
|
34
22
|
*/
|
|
35
23
|
export function Synchronizer(props: SynchronizerProps) {
|
|
36
|
-
const
|
|
37
|
-
const value = useSelector(props.editorActor, (s) => s.context.value)
|
|
38
|
-
const {editorActor, getValue, portableTextEditor, slateEditor} = props
|
|
39
|
-
const pendingPatches = useRef<Patch[]>([])
|
|
24
|
+
const {editorActor, slateEditor} = props
|
|
40
25
|
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
26
|
+
const value = useSelector(props.editorActor, (s) => s.context.value)
|
|
27
|
+
const readOnly = useSelector(props.editorActor, (s) =>
|
|
28
|
+
s.matches({'edit mode': 'read only'}),
|
|
29
|
+
)
|
|
30
|
+
const syncActorRef = useActorRef(syncMachine, {
|
|
31
|
+
input: {
|
|
32
|
+
keyGenerator: props.editorActor.getSnapshot().context.keyGenerator,
|
|
33
|
+
readOnly: props.editorActor
|
|
34
|
+
.getSnapshot()
|
|
35
|
+
.matches({'edit mode': 'read only'}),
|
|
36
|
+
schema: props.editorActor.getSnapshot().context.schema,
|
|
37
|
+
slateEditor,
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
const mutationActorRef = useActorRef(mutationMachine, {
|
|
41
|
+
input: {
|
|
42
|
+
schema: editorActor.getSnapshot().context.schema,
|
|
43
|
+
slateEditor,
|
|
44
|
+
},
|
|
46
45
|
})
|
|
47
46
|
|
|
48
47
|
useEffect(() => {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
debug(`Patches:\n${JSON.stringify(pendingPatches.current, null, 2)}`)
|
|
48
|
+
const subscription = mutationActorRef.on('*', (event) => {
|
|
49
|
+
if (event.type === 'has pending patches') {
|
|
50
|
+
syncActorRef.send({type: 'has pending patches'})
|
|
51
|
+
}
|
|
52
|
+
if (event.type === 'mutation') {
|
|
53
|
+
syncActorRef.send({type: 'mutation'})
|
|
54
|
+
editorActor.send(event)
|
|
57
55
|
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
snapshot,
|
|
63
|
-
})
|
|
64
|
-
pendingPatches.current = []
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
return () => {
|
|
59
|
+
subscription.unsubscribe()
|
|
65
60
|
}
|
|
66
|
-
|
|
67
|
-
}, [editorActor, slateEditor, getValue])
|
|
61
|
+
}, [mutationActorRef, syncActorRef, editorActor])
|
|
68
62
|
|
|
69
|
-
// Flush pending patches immediately on unmount
|
|
70
63
|
useEffect(() => {
|
|
64
|
+
const subscription = syncActorRef.on('*', (event) => {
|
|
65
|
+
props.editorActor.send(event)
|
|
66
|
+
})
|
|
67
|
+
|
|
71
68
|
return () => {
|
|
72
|
-
|
|
69
|
+
subscription.unsubscribe()
|
|
73
70
|
}
|
|
74
|
-
}, [
|
|
71
|
+
}, [props.editorActor, syncActorRef])
|
|
75
72
|
|
|
76
|
-
// Subscribe to, and handle changes from the editor
|
|
77
73
|
useEffect(() => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
// If the editor is normalizing (each operation) it means that it's not in the middle of a bigger transform,
|
|
81
|
-
// and we can flush these changes immediately.
|
|
82
|
-
if (Editor.isNormalizing(slateEditor)) {
|
|
83
|
-
onFlushPendingPatches()
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
// If it's in the middle of something, try again.
|
|
87
|
-
onFlushPendingPatchesThrottled()
|
|
88
|
-
},
|
|
89
|
-
FLUSH_PATCHES_THROTTLED_MS,
|
|
90
|
-
{
|
|
91
|
-
leading: false,
|
|
92
|
-
trailing: true,
|
|
93
|
-
},
|
|
94
|
-
)
|
|
74
|
+
syncActorRef.send({type: 'update readOnly', readOnly})
|
|
75
|
+
}, [syncActorRef, readOnly])
|
|
95
76
|
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
debug('Value from props changed, syncing new value')
|
|
79
|
+
syncActorRef.send({type: 'update value', value})
|
|
80
|
+
}, [syncActorRef, value])
|
|
81
|
+
|
|
82
|
+
// Subscribe to, and handle changes from the editor
|
|
83
|
+
useEffect(() => {
|
|
96
84
|
debug('Subscribing to patch events')
|
|
97
85
|
const sub = editorActor.on('patch', (event) => {
|
|
98
|
-
|
|
99
|
-
pendingPatches.current.push(event.patch)
|
|
100
|
-
onFlushPendingPatchesThrottled()
|
|
86
|
+
mutationActorRef.send(event)
|
|
101
87
|
})
|
|
102
88
|
return () => {
|
|
103
89
|
debug('Unsubscribing to patch events')
|
|
104
90
|
sub.unsubscribe()
|
|
105
91
|
}
|
|
106
|
-
}, [editorActor,
|
|
107
|
-
|
|
108
|
-
// This hook must be set up after setting up the subscription above, or it will not pick up validation errors from the useSyncValue hook.
|
|
109
|
-
// This will cause the editor to not be able to signal a validation error and offer invalid value resolution of the initial value.
|
|
110
|
-
const isInitialValueFromProps = useRef(true)
|
|
111
|
-
useEffect(() => {
|
|
112
|
-
debug('Value from props changed, syncing new value')
|
|
113
|
-
syncValue(value)
|
|
114
|
-
// Signal that we have our first value, and are ready to roll.
|
|
115
|
-
if (isInitialValueFromProps.current) {
|
|
116
|
-
editorActor.send({type: 'ready'})
|
|
117
|
-
isInitialValueFromProps.current = false
|
|
118
|
-
}
|
|
119
|
-
}, [editorActor, syncValue, value])
|
|
92
|
+
}, [editorActor, mutationActorRef, slateEditor])
|
|
120
93
|
|
|
121
94
|
return null
|
|
122
95
|
}
|
|
@@ -33,6 +33,9 @@ import {createEditableAPI} from './plugins/createWithEditableAPI'
|
|
|
33
33
|
export type EditorConfig = {
|
|
34
34
|
behaviors?: Array<Behavior>
|
|
35
35
|
keyGenerator?: () => string
|
|
36
|
+
/**
|
|
37
|
+
* @deprecated Will be removed in the next major version
|
|
38
|
+
*/
|
|
36
39
|
maxBlocks?: number
|
|
37
40
|
readOnly?: boolean
|
|
38
41
|
initialValue?: Array<PortableTextBlock>
|
|
@@ -64,8 +67,8 @@ export type EditorEvent = PickFromUnion<
|
|
|
64
67
|
| 'list item.toggle'
|
|
65
68
|
| 'style.toggle'
|
|
66
69
|
| 'patches'
|
|
67
|
-
| 'toggle readOnly'
|
|
68
70
|
| 'update behaviors'
|
|
71
|
+
| 'update readOnly'
|
|
69
72
|
| 'update value'
|
|
70
73
|
>
|
|
71
74
|
|
|
@@ -31,6 +31,7 @@ import {fromSlateValue} from '../utils/values'
|
|
|
31
31
|
import {KEY_TO_VALUE_ELEMENT} from '../utils/weakMaps'
|
|
32
32
|
import type {EditorSchema} from './define-schema'
|
|
33
33
|
import type {EditorContext} from './editor-snapshot'
|
|
34
|
+
import {getActiveDecorators} from './get-active-decorators'
|
|
34
35
|
|
|
35
36
|
export * from 'xstate/guards'
|
|
36
37
|
|
|
@@ -68,6 +69,7 @@ export type MutationEvent = {
|
|
|
68
69
|
export type InternalEditorEvent =
|
|
69
70
|
| {type: 'normalizing'}
|
|
70
71
|
| {type: 'done normalizing'}
|
|
72
|
+
| {type: 'done syncing'}
|
|
71
73
|
| {
|
|
72
74
|
type: 'behavior event'
|
|
73
75
|
behaviorEvent: SyntheticBehaviorEvent | NativeBehaviorEvent
|
|
@@ -79,6 +81,10 @@ export type InternalEditorEvent =
|
|
|
79
81
|
editor: PortableTextSlateEditor
|
|
80
82
|
actionIntends: Array<BehaviorActionIntend>
|
|
81
83
|
}
|
|
84
|
+
| {
|
|
85
|
+
type: 'update readOnly'
|
|
86
|
+
readOnly: boolean
|
|
87
|
+
}
|
|
82
88
|
| {
|
|
83
89
|
type: 'update schema'
|
|
84
90
|
schema: EditorSchema
|
|
@@ -91,14 +97,11 @@ export type InternalEditorEvent =
|
|
|
91
97
|
type: 'update value'
|
|
92
98
|
value: Array<PortableTextBlock> | undefined
|
|
93
99
|
}
|
|
94
|
-
| {
|
|
95
|
-
type: 'toggle readOnly'
|
|
96
|
-
}
|
|
97
100
|
| {
|
|
98
101
|
type: 'update maxBlocks'
|
|
99
102
|
maxBlocks: number | undefined
|
|
100
103
|
}
|
|
101
|
-
| OmitFromUnion<InternalEditorEmittedEvent, 'type', '
|
|
104
|
+
| OmitFromUnion<InternalEditorEmittedEvent, 'type', 'read only' | 'editable'>
|
|
102
105
|
|
|
103
106
|
/**
|
|
104
107
|
* @alpha
|
|
@@ -108,13 +111,14 @@ export type EditorEmittedEvent = PickFromUnion<
|
|
|
108
111
|
'type',
|
|
109
112
|
| 'blurred'
|
|
110
113
|
| 'done loading'
|
|
114
|
+
| 'editable'
|
|
111
115
|
| 'error'
|
|
112
116
|
| 'focused'
|
|
113
117
|
| 'invalid value'
|
|
114
118
|
| 'loading'
|
|
115
119
|
| 'mutation'
|
|
116
120
|
| 'patch'
|
|
117
|
-
| '
|
|
121
|
+
| 'read only'
|
|
118
122
|
| 'ready'
|
|
119
123
|
| 'selection'
|
|
120
124
|
| 'value changed'
|
|
@@ -152,7 +156,8 @@ export type InternalEditorEmittedEvent =
|
|
|
152
156
|
| {type: 'focused'; event: FocusEvent<HTMLDivElement, Element>}
|
|
153
157
|
| {type: 'loading'}
|
|
154
158
|
| {type: 'done loading'}
|
|
155
|
-
| {type: '
|
|
159
|
+
| {type: 'read only'}
|
|
160
|
+
| {type: 'editable'}
|
|
156
161
|
| PickFromUnion<
|
|
157
162
|
SyntheticBehaviorEvent,
|
|
158
163
|
'type',
|
|
@@ -180,7 +185,7 @@ export const editorMachine = setup({
|
|
|
180
185
|
keyGenerator: () => string
|
|
181
186
|
pendingEvents: Array<PatchEvent | MutationEvent>
|
|
182
187
|
schema: EditorSchema
|
|
183
|
-
|
|
188
|
+
initialReadOnly: boolean
|
|
184
189
|
maxBlocks: number | undefined
|
|
185
190
|
selection: EditorSelection
|
|
186
191
|
value: Array<PortableTextBlock> | undefined
|
|
@@ -217,6 +222,8 @@ export const editorMachine = setup({
|
|
|
217
222
|
assertEvent(event, 'mutation')
|
|
218
223
|
return event
|
|
219
224
|
}),
|
|
225
|
+
'emit read only': emit({type: 'read only'}),
|
|
226
|
+
'emit editable': emit({type: 'editable'}),
|
|
220
227
|
'defer event': assign({
|
|
221
228
|
pendingEvents: ({context, event}) => {
|
|
222
229
|
assertEvent(event, ['patch', 'mutation'])
|
|
@@ -228,6 +235,7 @@ export const editorMachine = setup({
|
|
|
228
235
|
enqueue(emit(event))
|
|
229
236
|
}
|
|
230
237
|
}),
|
|
238
|
+
'emit ready': emit({type: 'ready'}),
|
|
231
239
|
'clear pending events': assign({
|
|
232
240
|
pendingEvents: [],
|
|
233
241
|
}),
|
|
@@ -276,6 +284,10 @@ export const editorMachine = setup({
|
|
|
276
284
|
)
|
|
277
285
|
|
|
278
286
|
const editorContext = {
|
|
287
|
+
activeDecorators: getActiveDecorators({
|
|
288
|
+
schema: context.schema,
|
|
289
|
+
slateEditorInstance: event.editor,
|
|
290
|
+
}),
|
|
279
291
|
keyGenerator: context.keyGenerator,
|
|
280
292
|
schema: context.schema,
|
|
281
293
|
selection,
|
|
@@ -345,48 +357,11 @@ export const editorMachine = setup({
|
|
|
345
357
|
pendingEvents: [],
|
|
346
358
|
schema: input.schema,
|
|
347
359
|
selection: null,
|
|
348
|
-
|
|
360
|
+
initialReadOnly: input.readOnly ?? false,
|
|
349
361
|
maxBlocks: input.maxBlocks,
|
|
350
362
|
value: input.value,
|
|
351
363
|
}),
|
|
352
364
|
on: {
|
|
353
|
-
'annotation.add': {
|
|
354
|
-
actions: emit(({event}) => event),
|
|
355
|
-
guard: ({context}) => !context.readOnly,
|
|
356
|
-
},
|
|
357
|
-
'annotation.remove': {
|
|
358
|
-
actions: emit(({event}) => event),
|
|
359
|
-
guard: ({context}) => !context.readOnly,
|
|
360
|
-
},
|
|
361
|
-
'annotation.toggle': {
|
|
362
|
-
actions: emit(({event}) => event),
|
|
363
|
-
guard: ({context}) => !context.readOnly,
|
|
364
|
-
},
|
|
365
|
-
'blur': {
|
|
366
|
-
actions: emit(({event}) => event),
|
|
367
|
-
guard: ({context}) => !context.readOnly,
|
|
368
|
-
},
|
|
369
|
-
'decorator.*': {
|
|
370
|
-
actions: emit(({event}) => event),
|
|
371
|
-
guard: ({context}) => !context.readOnly,
|
|
372
|
-
},
|
|
373
|
-
'focus': {
|
|
374
|
-
actions: emit(({event}) => event),
|
|
375
|
-
guard: ({context}) => !context.readOnly,
|
|
376
|
-
},
|
|
377
|
-
'insert.*': {
|
|
378
|
-
actions: emit(({event}) => event),
|
|
379
|
-
guard: ({context}) => !context.readOnly,
|
|
380
|
-
},
|
|
381
|
-
'list item.*': {
|
|
382
|
-
actions: emit(({event}) => event),
|
|
383
|
-
guard: ({context}) => !context.readOnly,
|
|
384
|
-
},
|
|
385
|
-
'style.*': {
|
|
386
|
-
actions: emit(({event}) => event),
|
|
387
|
-
guard: ({context}) => !context.readOnly,
|
|
388
|
-
},
|
|
389
|
-
'ready': {actions: emit(({event}) => event)},
|
|
390
365
|
'unset': {actions: emit(({event}) => event)},
|
|
391
366
|
'value changed': {actions: emit(({event}) => event)},
|
|
392
367
|
'invalid value': {actions: emit(({event}) => event)},
|
|
@@ -405,22 +380,9 @@ export const editorMachine = setup({
|
|
|
405
380
|
'update behaviors': {actions: 'assign behaviors'},
|
|
406
381
|
'update schema': {actions: 'assign schema'},
|
|
407
382
|
'update value': {actions: assign({value: ({event}) => event.value})},
|
|
408
|
-
'toggle readOnly': {
|
|
409
|
-
actions: [
|
|
410
|
-
assign({readOnly: ({context}) => !context.readOnly}),
|
|
411
|
-
emit(({context}) => ({
|
|
412
|
-
type: 'readOnly toggled',
|
|
413
|
-
readOnly: context.readOnly,
|
|
414
|
-
})),
|
|
415
|
-
],
|
|
416
|
-
},
|
|
417
383
|
'update maxBlocks': {
|
|
418
384
|
actions: assign({maxBlocks: ({event}) => event.maxBlocks}),
|
|
419
385
|
},
|
|
420
|
-
'behavior event': {
|
|
421
|
-
actions: 'handle behavior event',
|
|
422
|
-
guard: ({context}) => !context.readOnly,
|
|
423
|
-
},
|
|
424
386
|
'behavior action intends': {
|
|
425
387
|
actions: [
|
|
426
388
|
({context, event}) => {
|
|
@@ -455,49 +417,139 @@ export const editorMachine = setup({
|
|
|
455
417
|
],
|
|
456
418
|
},
|
|
457
419
|
},
|
|
458
|
-
|
|
420
|
+
type: 'parallel',
|
|
459
421
|
states: {
|
|
460
|
-
|
|
461
|
-
initial: '
|
|
422
|
+
'edit mode': {
|
|
423
|
+
initial: 'read only',
|
|
462
424
|
states: {
|
|
463
|
-
|
|
425
|
+
'read only': {
|
|
426
|
+
initial: 'determine initial edit mode',
|
|
427
|
+
states: {
|
|
428
|
+
'determine initial edit mode': {
|
|
429
|
+
on: {
|
|
430
|
+
'done syncing': [
|
|
431
|
+
{
|
|
432
|
+
target: '#editor.edit mode.read only.read only',
|
|
433
|
+
guard: ({context}) => context.initialReadOnly,
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
target: '#editor.edit mode.editable',
|
|
437
|
+
},
|
|
438
|
+
],
|
|
439
|
+
},
|
|
440
|
+
},
|
|
441
|
+
'read only': {
|
|
442
|
+
on: {
|
|
443
|
+
'update readOnly': {
|
|
444
|
+
guard: ({event}) => !event.readOnly,
|
|
445
|
+
target: '#editor.edit mode.editable',
|
|
446
|
+
actions: ['emit editable'],
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
},
|
|
451
|
+
},
|
|
452
|
+
'editable': {
|
|
464
453
|
on: {
|
|
465
|
-
|
|
466
|
-
|
|
454
|
+
'update readOnly': {
|
|
455
|
+
guard: ({event}) => event.readOnly,
|
|
456
|
+
target: '#editor.edit mode.read only.read only',
|
|
457
|
+
actions: ['emit read only'],
|
|
467
458
|
},
|
|
468
|
-
|
|
469
|
-
actions: '
|
|
470
|
-
target: '#editor.dirty',
|
|
459
|
+
'behavior event': {
|
|
460
|
+
actions: 'handle behavior event',
|
|
471
461
|
},
|
|
472
|
-
|
|
473
|
-
actions:
|
|
474
|
-
|
|
462
|
+
'annotation.add': {
|
|
463
|
+
actions: emit(({event}) => event),
|
|
464
|
+
},
|
|
465
|
+
'annotation.remove': {
|
|
466
|
+
actions: emit(({event}) => event),
|
|
467
|
+
},
|
|
468
|
+
'annotation.toggle': {
|
|
469
|
+
actions: emit(({event}) => event),
|
|
470
|
+
},
|
|
471
|
+
'blur': {
|
|
472
|
+
actions: emit(({event}) => event),
|
|
473
|
+
},
|
|
474
|
+
'decorator.*': {
|
|
475
|
+
actions: emit(({event}) => event),
|
|
476
|
+
},
|
|
477
|
+
'focus': {
|
|
478
|
+
actions: emit(({event}) => event),
|
|
479
|
+
},
|
|
480
|
+
'insert.*': {
|
|
481
|
+
actions: emit(({event}) => event),
|
|
482
|
+
},
|
|
483
|
+
'list item.*': {
|
|
484
|
+
actions: emit(({event}) => event),
|
|
485
|
+
},
|
|
486
|
+
'style.*': {
|
|
487
|
+
actions: emit(({event}) => event),
|
|
475
488
|
},
|
|
476
489
|
},
|
|
477
490
|
},
|
|
478
|
-
|
|
491
|
+
},
|
|
492
|
+
},
|
|
493
|
+
'setup': {
|
|
494
|
+
initial: 'setting up',
|
|
495
|
+
states: {
|
|
496
|
+
'setting up': {
|
|
497
|
+
exit: ['emit ready'],
|
|
479
498
|
on: {
|
|
480
|
-
'done normalizing': {
|
|
481
|
-
target: 'idle',
|
|
482
|
-
},
|
|
483
499
|
'patch': {
|
|
484
500
|
actions: 'defer event',
|
|
485
501
|
},
|
|
486
502
|
'mutation': {
|
|
487
503
|
actions: 'defer event',
|
|
488
504
|
},
|
|
505
|
+
'done syncing': {
|
|
506
|
+
target: 'pristine',
|
|
507
|
+
},
|
|
489
508
|
},
|
|
490
509
|
},
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
510
|
+
'pristine': {
|
|
511
|
+
initial: 'idle',
|
|
512
|
+
states: {
|
|
513
|
+
idle: {
|
|
514
|
+
on: {
|
|
515
|
+
normalizing: {
|
|
516
|
+
target: 'normalizing',
|
|
517
|
+
},
|
|
518
|
+
patch: {
|
|
519
|
+
actions: 'defer event',
|
|
520
|
+
target: '#editor.setup.dirty',
|
|
521
|
+
},
|
|
522
|
+
mutation: {
|
|
523
|
+
actions: 'defer event',
|
|
524
|
+
target: '#editor.setup.dirty',
|
|
525
|
+
},
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
normalizing: {
|
|
529
|
+
on: {
|
|
530
|
+
'done normalizing': {
|
|
531
|
+
target: 'idle',
|
|
532
|
+
},
|
|
533
|
+
'patch': {
|
|
534
|
+
actions: 'defer event',
|
|
535
|
+
},
|
|
536
|
+
'mutation': {
|
|
537
|
+
actions: 'defer event',
|
|
538
|
+
},
|
|
539
|
+
},
|
|
540
|
+
},
|
|
541
|
+
},
|
|
498
542
|
},
|
|
499
|
-
|
|
500
|
-
|
|
543
|
+
'dirty': {
|
|
544
|
+
entry: ['emit pending events', 'clear pending events'],
|
|
545
|
+
on: {
|
|
546
|
+
patch: {
|
|
547
|
+
actions: 'emit patch event',
|
|
548
|
+
},
|
|
549
|
+
mutation: {
|
|
550
|
+
actions: 'emit mutation event',
|
|
551
|
+
},
|
|
552
|
+
},
|
|
501
553
|
},
|
|
502
554
|
},
|
|
503
555
|
},
|
|
@@ -28,7 +28,6 @@ export function EditorProvider(props: EditorProviderProps) {
|
|
|
28
28
|
const editor = useCreateEditor(props.initialConfig)
|
|
29
29
|
const editorActor = editor._internal.editorActor
|
|
30
30
|
const slateEditor = editor._internal.slateEditor
|
|
31
|
-
const editable = editor._internal.editable
|
|
32
31
|
const portableTextEditor = useMemo(
|
|
33
32
|
() =>
|
|
34
33
|
new PortableTextEditor({
|
|
@@ -47,8 +46,6 @@ export function EditorProvider(props: EditorProviderProps) {
|
|
|
47
46
|
/>
|
|
48
47
|
<Synchronizer
|
|
49
48
|
editorActor={editorActor}
|
|
50
|
-
getValue={editable.getValue}
|
|
51
|
-
portableTextEditor={portableTextEditor}
|
|
52
49
|
slateEditor={slateEditor.instance}
|
|
53
50
|
/>
|
|
54
51
|
<EditorActorContext.Provider value={editorActor}>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {useSelector} from '@xstate/react'
|
|
2
2
|
import type {Editor} from './create-editor'
|
|
3
3
|
import type {EditorSnapshot} from './editor-snapshot'
|
|
4
|
+
import {getActiveDecorators} from './get-active-decorators'
|
|
4
5
|
import {getValue} from './get-value'
|
|
5
6
|
|
|
6
7
|
function defaultCompare<T>(a: T, b: T) {
|
|
@@ -24,6 +25,10 @@ export function useEditorSelector<TSelected>(
|
|
|
24
25
|
editor._internal.editorActor,
|
|
25
26
|
(snapshot) => {
|
|
26
27
|
const context = {
|
|
28
|
+
activeDecorators: getActiveDecorators({
|
|
29
|
+
schema: snapshot.context.schema,
|
|
30
|
+
slateEditorInstance: editor._internal.slateEditor.instance,
|
|
31
|
+
}),
|
|
27
32
|
keyGenerator: snapshot.context.keyGenerator,
|
|
28
33
|
schema: snapshot.context.schema,
|
|
29
34
|
selection: snapshot.context.selection,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import {Editor} from 'slate'
|
|
2
|
+
import type {PortableTextSlateEditor} from '../types/editor'
|
|
3
|
+
import type {EditorSchema} from './define-schema'
|
|
4
|
+
|
|
5
|
+
export function getActiveDecorators({
|
|
6
|
+
schema,
|
|
7
|
+
slateEditorInstance,
|
|
8
|
+
}: {
|
|
9
|
+
schema: EditorSchema
|
|
10
|
+
slateEditorInstance: PortableTextSlateEditor
|
|
11
|
+
}) {
|
|
12
|
+
const decorators = schema.decorators.map((decorator) => decorator.value)
|
|
13
|
+
|
|
14
|
+
const marks =
|
|
15
|
+
{
|
|
16
|
+
...(Editor.marks(slateEditorInstance) ?? {}),
|
|
17
|
+
}.marks ?? []
|
|
18
|
+
|
|
19
|
+
return marks.filter((mark) => decorators.includes(mark))
|
|
20
|
+
}
|