@portabletext/editor 1.10.2 → 1.11.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/README.md +21 -27
- package/lib/index.d.mts +531 -206
- package/lib/index.d.ts +531 -206
- package/lib/index.esm.js +440 -386
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +483 -429
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +440 -386
- package/lib/index.mjs.map +1 -1
- package/package.json +10 -10
- package/src/editor/Editable.tsx +1 -1
- package/src/editor/PortableTextEditor.tsx +122 -95
- package/src/editor/behavior/behavior.types.ts +9 -0
- package/src/editor/components/Synchronizer.tsx +13 -68
- package/src/editor/create-slate-editor.tsx +2 -14
- package/src/editor/editor-event-listener.tsx +24 -0
- package/src/editor/editor-machine.ts +34 -4
- package/src/editor/editor-provider.tsx +81 -0
- package/src/editor/hooks/useSyncValue.ts +2 -3
- package/src/editor/plugins/createWithMaxBlocks.ts +1 -0
- package/src/editor/plugins/createWithPlaceholderBlock.ts +1 -0
- package/src/editor/plugins/createWithUndoRedo.ts +1 -0
- package/src/editor/plugins/with-plugins.ts +0 -27
- package/src/editor/use-editor.ts +89 -20
- package/src/index.ts +12 -4
- package/src/types/editor.ts +0 -1
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import React, {useMemo} from 'react'
|
|
2
|
+
import {Slate} from 'slate-react'
|
|
3
|
+
import {Synchronizer} from './components/Synchronizer'
|
|
4
|
+
import {EditorActorContext} from './editor-actor-context'
|
|
5
|
+
import {PortableTextEditorContext} from './hooks/usePortableTextEditor'
|
|
6
|
+
import {PortableTextEditorSelectionProvider} from './hooks/usePortableTextEditorSelection'
|
|
7
|
+
import {
|
|
8
|
+
PortableTextEditor,
|
|
9
|
+
RouteEventsToChanges,
|
|
10
|
+
type PortableTextEditorProps,
|
|
11
|
+
} from './PortableTextEditor'
|
|
12
|
+
import {useEditor, type Editor, type EditorConfig} from './use-editor'
|
|
13
|
+
|
|
14
|
+
const EditorContext = React.createContext<Editor | undefined>(undefined)
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @alpha
|
|
18
|
+
*/
|
|
19
|
+
export type EditorProviderProps = {
|
|
20
|
+
config: EditorConfig
|
|
21
|
+
children?: React.ReactNode
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @alpha
|
|
26
|
+
*/
|
|
27
|
+
export function EditorProvider(props: EditorProviderProps) {
|
|
28
|
+
const editor = useEditor(props.config)
|
|
29
|
+
const editorActor = editor._internal.editorActor
|
|
30
|
+
const slateEditor = editor._internal.slateEditor
|
|
31
|
+
const editable = editor.editable
|
|
32
|
+
const portableTextEditor = useMemo(
|
|
33
|
+
() =>
|
|
34
|
+
new PortableTextEditor({
|
|
35
|
+
editor,
|
|
36
|
+
} as unknown as PortableTextEditorProps),
|
|
37
|
+
[editor],
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<EditorContext.Provider value={editor}>
|
|
42
|
+
<RouteEventsToChanges
|
|
43
|
+
editorActor={editorActor}
|
|
44
|
+
onChange={(change) => {
|
|
45
|
+
portableTextEditor.change$.next(change)
|
|
46
|
+
}}
|
|
47
|
+
/>
|
|
48
|
+
<Synchronizer
|
|
49
|
+
editorActor={editorActor}
|
|
50
|
+
getValue={editable.getValue}
|
|
51
|
+
portableTextEditor={portableTextEditor}
|
|
52
|
+
slateEditor={slateEditor.instance}
|
|
53
|
+
/>
|
|
54
|
+
<EditorActorContext.Provider value={editorActor}>
|
|
55
|
+
<Slate
|
|
56
|
+
editor={slateEditor.instance}
|
|
57
|
+
initialValue={slateEditor.initialValue}
|
|
58
|
+
>
|
|
59
|
+
<PortableTextEditorContext.Provider value={portableTextEditor}>
|
|
60
|
+
<PortableTextEditorSelectionProvider editorActor={editorActor}>
|
|
61
|
+
{props.children}
|
|
62
|
+
</PortableTextEditorSelectionProvider>
|
|
63
|
+
</PortableTextEditorContext.Provider>
|
|
64
|
+
</Slate>
|
|
65
|
+
</EditorActorContext.Provider>
|
|
66
|
+
</EditorContext.Provider>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* @alpha
|
|
72
|
+
*/
|
|
73
|
+
export function useEditorContext() {
|
|
74
|
+
const editor = React.useContext(EditorContext)
|
|
75
|
+
|
|
76
|
+
if (!editor) {
|
|
77
|
+
throw new Error('No Editor set. Use EditorProvider to set one.')
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return editor
|
|
81
|
+
}
|
|
@@ -2,7 +2,6 @@ import type {PortableTextBlock} from '@sanity/types'
|
|
|
2
2
|
import {debounce, isEqual} from 'lodash'
|
|
3
3
|
import {useCallback, useMemo, useRef} from 'react'
|
|
4
4
|
import {Editor, Text, Transforms, type Descendant, type Node} from 'slate'
|
|
5
|
-
import {useSlate} from 'slate-react'
|
|
6
5
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
7
6
|
import {debugWithName} from '../../utils/debug'
|
|
8
7
|
import {validateValue} from '../../utils/validateValue'
|
|
@@ -26,6 +25,7 @@ export interface UseSyncValueProps {
|
|
|
26
25
|
editorActor: EditorActor
|
|
27
26
|
portableTextEditor: PortableTextEditor
|
|
28
27
|
readOnly: boolean
|
|
28
|
+
slateEditor: PortableTextSlateEditor
|
|
29
29
|
}
|
|
30
30
|
|
|
31
31
|
const CURRENT_VALUE = new WeakMap<
|
|
@@ -51,10 +51,9 @@ export function useSyncValue(
|
|
|
51
51
|
value: PortableTextBlock[] | undefined,
|
|
52
52
|
userCallbackFn?: () => void,
|
|
53
53
|
) => void {
|
|
54
|
-
const {editorActor, portableTextEditor, readOnly} = props
|
|
54
|
+
const {editorActor, portableTextEditor, readOnly, slateEditor} = props
|
|
55
55
|
const schemaTypes = editorActor.getSnapshot().context.schema
|
|
56
56
|
const previousValue = useRef<PortableTextBlock[] | undefined>()
|
|
57
|
-
const slateEditor = useSlate()
|
|
58
57
|
const updateValueFunctionRef =
|
|
59
58
|
useRef<(value: PortableTextBlock[] | undefined) => void>()
|
|
60
59
|
|
|
@@ -21,11 +21,6 @@ export interface OriginalEditorFunctions {
|
|
|
21
21
|
normalizeNode: (entry: NodeEntry<Node>) => void
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
const originalFnMap = new WeakMap<
|
|
25
|
-
PortableTextSlateEditor,
|
|
26
|
-
OriginalEditorFunctions
|
|
27
|
-
>()
|
|
28
|
-
|
|
29
24
|
type PluginsOptions = {
|
|
30
25
|
editorActor: EditorActor
|
|
31
26
|
subscriptions: Array<() => () => void>
|
|
@@ -38,17 +33,6 @@ export const withPlugins = <T extends Editor>(
|
|
|
38
33
|
const e = editor as T & PortableTextSlateEditor
|
|
39
34
|
const {editorActor} = options
|
|
40
35
|
const schemaTypes = editorActor.getSnapshot().context.schema
|
|
41
|
-
if (e.destroy) {
|
|
42
|
-
e.destroy()
|
|
43
|
-
} else {
|
|
44
|
-
// Save a copy of the original editor functions here before they were changed by plugins.
|
|
45
|
-
// We will put them back when .destroy is called (see below).
|
|
46
|
-
originalFnMap.set(e, {
|
|
47
|
-
apply: e.apply,
|
|
48
|
-
onChange: e.onChange,
|
|
49
|
-
normalizeNode: e.normalizeNode,
|
|
50
|
-
})
|
|
51
|
-
}
|
|
52
36
|
const operationToPatches = createOperationToPatches(schemaTypes)
|
|
53
37
|
const withObjectKeys = createWithObjectKeys(editorActor, schemaTypes)
|
|
54
38
|
const withSchemaTypes = createWithSchemaTypes({
|
|
@@ -92,17 +76,6 @@ export const withPlugins = <T extends Editor>(
|
|
|
92
76
|
options.subscriptions,
|
|
93
77
|
)
|
|
94
78
|
|
|
95
|
-
e.destroy = () => {
|
|
96
|
-
const originalFunctions = originalFnMap.get(e)
|
|
97
|
-
if (!originalFunctions) {
|
|
98
|
-
throw new Error('Could not find pristine versions of editor functions')
|
|
99
|
-
}
|
|
100
|
-
e.apply = originalFunctions.apply
|
|
101
|
-
e.history = {undos: [], redos: []}
|
|
102
|
-
e.normalizeNode = originalFunctions.normalizeNode
|
|
103
|
-
e.onChange = originalFunctions.onChange
|
|
104
|
-
}
|
|
105
|
-
|
|
106
79
|
// Ordering is important here, selection dealing last, data manipulation in the middle and core model stuff first.
|
|
107
80
|
return withEventListeners(
|
|
108
81
|
withSchemaTypes(
|
package/src/editor/use-editor.ts
CHANGED
|
@@ -3,7 +3,15 @@ import type {
|
|
|
3
3
|
ArraySchemaType,
|
|
4
4
|
PortableTextBlock,
|
|
5
5
|
} from '@sanity/types'
|
|
6
|
-
import {useActorRef
|
|
6
|
+
import {useActorRef} from '@xstate/react'
|
|
7
|
+
import {useCallback, useMemo} from 'react'
|
|
8
|
+
import {
|
|
9
|
+
createActor,
|
|
10
|
+
type ActorRef,
|
|
11
|
+
type EventObject,
|
|
12
|
+
type Snapshot,
|
|
13
|
+
} from 'xstate'
|
|
14
|
+
import type {EditableAPI} from '../types/editor'
|
|
7
15
|
import {getPortableTextMemberSchemaTypes} from '../utils/getPortableTextMemberSchemaTypes'
|
|
8
16
|
import {compileType} from '../utils/schema'
|
|
9
17
|
import type {Behavior, PickFromUnion} from './behavior/behavior.types'
|
|
@@ -12,9 +20,11 @@ import {compileSchemaDefinition, type SchemaDefinition} from './define-schema'
|
|
|
12
20
|
import {
|
|
13
21
|
editorMachine,
|
|
14
22
|
type EditorActor,
|
|
23
|
+
type EditorEmittedEvent,
|
|
15
24
|
type InternalEditorEvent,
|
|
16
25
|
} from './editor-machine'
|
|
17
26
|
import {defaultKeyGenerator} from './key-generator'
|
|
27
|
+
import {createEditableAPI} from './plugins/createWithEditableAPI'
|
|
18
28
|
|
|
19
29
|
/**
|
|
20
30
|
* @alpha
|
|
@@ -22,6 +32,8 @@ import {defaultKeyGenerator} from './key-generator'
|
|
|
22
32
|
export type EditorConfig = {
|
|
23
33
|
behaviors?: Array<Behavior>
|
|
24
34
|
keyGenerator?: () => string
|
|
35
|
+
maxBlocks?: number
|
|
36
|
+
readOnly?: boolean
|
|
25
37
|
initialValue?: Array<PortableTextBlock>
|
|
26
38
|
} & (
|
|
27
39
|
| {
|
|
@@ -53,8 +65,8 @@ export type EditorEvent = PickFromUnion<
|
|
|
53
65
|
*/
|
|
54
66
|
export type Editor = {
|
|
55
67
|
send: (event: EditorEvent) => void
|
|
56
|
-
on:
|
|
57
|
-
|
|
68
|
+
on: ActorRef<Snapshot<unknown>, EventObject, EditorEmittedEvent>['on']
|
|
69
|
+
editable: EditableAPI
|
|
58
70
|
_internal: {
|
|
59
71
|
editorActor: EditorActor
|
|
60
72
|
slateEditor: SlateEditor
|
|
@@ -64,33 +76,90 @@ export type Editor = {
|
|
|
64
76
|
/**
|
|
65
77
|
* @alpha
|
|
66
78
|
*/
|
|
67
|
-
export function
|
|
68
|
-
const editorActor =
|
|
69
|
-
input:
|
|
70
|
-
behaviors: config.behaviors,
|
|
71
|
-
keyGenerator: config.keyGenerator ?? defaultKeyGenerator,
|
|
72
|
-
schema: config.schemaDefinition
|
|
73
|
-
? compileSchemaDefinition(config.schemaDefinition)
|
|
74
|
-
: getPortableTextMemberSchemaTypes(
|
|
75
|
-
config.schema.hasOwnProperty('jsonType')
|
|
76
|
-
? config.schema
|
|
77
|
-
: compileType(config.schema),
|
|
78
|
-
),
|
|
79
|
-
value: config.initialValue,
|
|
80
|
-
},
|
|
79
|
+
export function createEditor(config: EditorConfig): Editor {
|
|
80
|
+
const editorActor = createActor(editorMachine, {
|
|
81
|
+
input: editorConfigToMachineInput(config),
|
|
81
82
|
})
|
|
83
|
+
|
|
84
|
+
editorActor.start()
|
|
85
|
+
|
|
82
86
|
const slateEditor = createSlateEditor({editorActor})
|
|
83
|
-
const
|
|
87
|
+
const editable = createEditableAPI(slateEditor.instance, editorActor)
|
|
84
88
|
|
|
85
89
|
return {
|
|
86
90
|
send: (event) => {
|
|
87
91
|
editorActor.send(event)
|
|
88
92
|
},
|
|
89
|
-
on: (event, listener) =>
|
|
90
|
-
|
|
93
|
+
on: (event, listener) =>
|
|
94
|
+
editorActor.on(
|
|
95
|
+
event,
|
|
96
|
+
// @ts-ignore
|
|
97
|
+
listener,
|
|
98
|
+
),
|
|
99
|
+
editable,
|
|
91
100
|
_internal: {
|
|
92
101
|
editorActor,
|
|
93
102
|
slateEditor,
|
|
94
103
|
},
|
|
95
104
|
}
|
|
96
105
|
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* @alpha
|
|
109
|
+
*/
|
|
110
|
+
export function useEditor(config: EditorConfig): Editor {
|
|
111
|
+
const editorActor = useActorRef(editorMachine, {
|
|
112
|
+
input: editorConfigToMachineInput(config),
|
|
113
|
+
})
|
|
114
|
+
const slateEditor = createSlateEditor({editorActor})
|
|
115
|
+
const editable = useMemo(
|
|
116
|
+
() => createEditableAPI(slateEditor.instance, editorActor),
|
|
117
|
+
[slateEditor.instance, editorActor],
|
|
118
|
+
)
|
|
119
|
+
const send = useCallback(
|
|
120
|
+
(event: EditorEvent) => {
|
|
121
|
+
editorActor.send(event)
|
|
122
|
+
},
|
|
123
|
+
[editorActor],
|
|
124
|
+
)
|
|
125
|
+
const on = useCallback<Editor['on']>(
|
|
126
|
+
(event, listener) =>
|
|
127
|
+
editorActor.on(
|
|
128
|
+
event,
|
|
129
|
+
// @ts-ignore
|
|
130
|
+
listener,
|
|
131
|
+
),
|
|
132
|
+
[editorActor],
|
|
133
|
+
)
|
|
134
|
+
const editor: Editor = useMemo(
|
|
135
|
+
() => ({
|
|
136
|
+
send,
|
|
137
|
+
on,
|
|
138
|
+
editable,
|
|
139
|
+
_internal: {
|
|
140
|
+
editorActor,
|
|
141
|
+
slateEditor,
|
|
142
|
+
},
|
|
143
|
+
}),
|
|
144
|
+
[send, on, editable, editorActor, slateEditor],
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
return editor
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function editorConfigToMachineInput(config: EditorConfig) {
|
|
151
|
+
return {
|
|
152
|
+
behaviors: config.behaviors,
|
|
153
|
+
keyGenerator: config.keyGenerator ?? defaultKeyGenerator,
|
|
154
|
+
maxBlocks: config.maxBlocks,
|
|
155
|
+
readOnly: config.readOnly,
|
|
156
|
+
schema: config.schemaDefinition
|
|
157
|
+
? compileSchemaDefinition(config.schemaDefinition)
|
|
158
|
+
: getPortableTextMemberSchemaTypes(
|
|
159
|
+
config.schema.hasOwnProperty('jsonType')
|
|
160
|
+
? config.schema
|
|
161
|
+
: compileType(config.schema),
|
|
162
|
+
),
|
|
163
|
+
value: config.initialValue,
|
|
164
|
+
} as const
|
|
165
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
export type {Patch} from '@portabletext/patches'
|
|
2
2
|
export type {PortableTextBlock, PortableTextChild} from '@sanity/types'
|
|
3
3
|
export {coreBehavior, coreBehaviors} from './editor/behavior/behavior.core'
|
|
4
|
-
export {
|
|
5
|
-
createMarkdownBehaviors,
|
|
6
|
-
type MarkdownBehaviorsConfig,
|
|
7
|
-
} from './editor/behavior/behavior.markdown'
|
|
8
4
|
export {
|
|
9
5
|
createLinkBehaviors,
|
|
10
6
|
type LinkBehaviorsConfig,
|
|
11
7
|
} from './editor/behavior/behavior.links'
|
|
8
|
+
export {
|
|
9
|
+
createMarkdownBehaviors,
|
|
10
|
+
type MarkdownBehaviorsConfig,
|
|
11
|
+
} from './editor/behavior/behavior.markdown'
|
|
12
12
|
export {
|
|
13
13
|
defineBehavior,
|
|
14
14
|
type Behavior,
|
|
@@ -17,6 +17,7 @@ export {
|
|
|
17
17
|
type BehaviorContext,
|
|
18
18
|
type BehaviorEvent,
|
|
19
19
|
type BehaviorGuard,
|
|
20
|
+
type OmitFromUnion,
|
|
20
21
|
type PickFromUnion,
|
|
21
22
|
} from './editor/behavior/behavior.types'
|
|
22
23
|
export type {SlateEditor} from './editor/create-slate-editor'
|
|
@@ -27,15 +28,22 @@ export {
|
|
|
27
28
|
} from './editor/define-schema'
|
|
28
29
|
export {PortableTextEditable} from './editor/Editable'
|
|
29
30
|
export type {PortableTextEditableProps} from './editor/Editable'
|
|
31
|
+
export {EditorEventListener} from './editor/editor-event-listener'
|
|
30
32
|
export {
|
|
31
33
|
editorMachine,
|
|
32
34
|
type EditorActor,
|
|
35
|
+
type EditorEmittedEvent,
|
|
33
36
|
type InternalEditorEmittedEvent,
|
|
34
37
|
type InternalEditorEvent,
|
|
35
38
|
type MutationEvent,
|
|
36
39
|
type PatchEvent,
|
|
37
40
|
type PatchesEvent,
|
|
38
41
|
} from './editor/editor-machine'
|
|
42
|
+
export {
|
|
43
|
+
EditorProvider,
|
|
44
|
+
useEditorContext,
|
|
45
|
+
type EditorProviderProps,
|
|
46
|
+
} from './editor/editor-provider'
|
|
39
47
|
export {usePortableTextEditor} from './editor/hooks/usePortableTextEditor'
|
|
40
48
|
export {usePortableTextEditorSelection} from './editor/hooks/usePortableTextEditorSelection'
|
|
41
49
|
export {defaultKeyGenerator as keyGenerator} from './editor/key-generator'
|
package/src/types/editor.ts
CHANGED