@portabletext/editor 1.3.0 → 1.4.0
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/index.d.mts +2805 -44
- package/lib/index.d.ts +2805 -44
- package/lib/index.esm.js +866 -372
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +928 -434
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +866 -372
- package/lib/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/editor/PortableTextEditor.tsx +160 -99
- package/src/editor/behavior/behavior.markdown.ts +203 -0
- package/src/editor/components/SlateContainer.tsx +2 -13
- package/src/editor/components/Synchronizer.tsx +25 -28
- package/src/editor/editor-machine.ts +27 -2
- package/src/editor/plugins/createWithPatches.ts +8 -13
- package/src/editor/plugins/createWithUndoRedo.ts +34 -33
- package/src/editor/plugins/index.ts +2 -4
- package/src/editor/use-editor.ts +45 -0
- package/src/index.ts +15 -8
- package/src/types/options.ts +0 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"@sanity/ui": "^2.8.17",
|
|
68
68
|
"@sanity/util": "^3.62.3",
|
|
69
69
|
"@testing-library/dom": "^10.4.0",
|
|
70
|
-
"@testing-library/jest-dom": "^6.6.
|
|
70
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
71
71
|
"@testing-library/react": "^16.0.1",
|
|
72
72
|
"@testing-library/user-event": "^14.5.2",
|
|
73
73
|
"@types/debug": "^4.1.5",
|
|
@@ -9,7 +9,12 @@ import type {
|
|
|
9
9
|
PortableTextObject,
|
|
10
10
|
SpanSchemaType,
|
|
11
11
|
} from '@sanity/types'
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
Component,
|
|
14
|
+
useEffect,
|
|
15
|
+
type MutableRefObject,
|
|
16
|
+
type PropsWithChildren,
|
|
17
|
+
} from 'react'
|
|
13
18
|
import {Subject} from 'rxjs'
|
|
14
19
|
import {createActor} from 'xstate'
|
|
15
20
|
import type {
|
|
@@ -24,7 +29,6 @@ import type {
|
|
|
24
29
|
import {debugWithName} from '../utils/debug'
|
|
25
30
|
import {getPortableTextMemberSchemaTypes} from '../utils/getPortableTextMemberSchemaTypes'
|
|
26
31
|
import {compileType} from '../utils/schema'
|
|
27
|
-
import {coreBehaviors} from './behavior/behavior.core'
|
|
28
32
|
import {SlateContainer} from './components/SlateContainer'
|
|
29
33
|
import {Synchronizer} from './components/Synchronizer'
|
|
30
34
|
import {EditorActorContext} from './editor-actor-context'
|
|
@@ -33,6 +37,7 @@ import {PortableTextEditorContext} from './hooks/usePortableTextEditor'
|
|
|
33
37
|
import {PortableTextEditorSelectionProvider} from './hooks/usePortableTextEditorSelection'
|
|
34
38
|
import {PortableTextEditorReadOnlyContext} from './hooks/usePortableTextReadOnly'
|
|
35
39
|
import {defaultKeyGenerator} from './key-generator'
|
|
40
|
+
import type {Editor} from './use-editor'
|
|
36
41
|
|
|
37
42
|
const debug = debugWithName('component:PortableTextEditor')
|
|
38
43
|
|
|
@@ -41,58 +46,73 @@ const debug = debugWithName('component:PortableTextEditor')
|
|
|
41
46
|
*
|
|
42
47
|
* @public
|
|
43
48
|
*/
|
|
44
|
-
export type PortableTextEditorProps
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
+
export type PortableTextEditorProps<
|
|
50
|
+
TEditor extends Editor | undefined = undefined,
|
|
51
|
+
> = PropsWithChildren<
|
|
52
|
+
(TEditor extends Editor
|
|
53
|
+
? {
|
|
54
|
+
/**
|
|
55
|
+
* @alpha
|
|
56
|
+
*/
|
|
57
|
+
editor: TEditor
|
|
58
|
+
}
|
|
59
|
+
: {
|
|
60
|
+
editor?: undefined
|
|
49
61
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Function that gets called when the editor changes the value
|
|
64
|
+
*/
|
|
65
|
+
onChange: (change: EditorChange) => void
|
|
54
66
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
/**
|
|
68
|
+
* Schema type for the portable text field
|
|
69
|
+
*/
|
|
70
|
+
schemaType: ArraySchemaType<PortableTextBlock> | ArrayDefinition
|
|
59
71
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Maximum number of blocks to allow within the editor
|
|
74
|
+
*/
|
|
75
|
+
maxBlocks?: number | string
|
|
64
76
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Function used to generate keys for array items (`_key`)
|
|
79
|
+
*/
|
|
80
|
+
keyGenerator?: () => string
|
|
69
81
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
82
|
+
/**
|
|
83
|
+
* Observable of local and remote patches for the edited value.
|
|
84
|
+
*/
|
|
85
|
+
patches$?: PatchObservable
|
|
74
86
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Backward compatibility (renamed to patches$).
|
|
89
|
+
*/
|
|
90
|
+
incomingPatches$?: PatchObservable
|
|
91
|
+
}) & {
|
|
92
|
+
/**
|
|
93
|
+
* Whether or not the editor should be in read-only mode
|
|
94
|
+
*/
|
|
95
|
+
readOnly?: boolean
|
|
79
96
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
97
|
+
/**
|
|
98
|
+
* The current value of the portable text field
|
|
99
|
+
*/
|
|
100
|
+
value?: PortableTextBlock[]
|
|
84
101
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
102
|
+
/**
|
|
103
|
+
* A ref to the editor instance
|
|
104
|
+
*/
|
|
105
|
+
editorRef?: MutableRefObject<PortableTextEditor | null>
|
|
106
|
+
}
|
|
107
|
+
>
|
|
90
108
|
|
|
91
109
|
/**
|
|
92
110
|
* The main Portable Text Editor component.
|
|
93
111
|
* @public
|
|
94
112
|
*/
|
|
95
|
-
export class PortableTextEditor extends Component<
|
|
113
|
+
export class PortableTextEditor extends Component<
|
|
114
|
+
PortableTextEditorProps<Editor | undefined>
|
|
115
|
+
> {
|
|
96
116
|
public static displayName = 'PortableTextEditor'
|
|
97
117
|
/**
|
|
98
118
|
* An observable of all the editor changes.
|
|
@@ -111,35 +131,46 @@ export class PortableTextEditor extends Component<PortableTextEditorProps> {
|
|
|
111
131
|
constructor(props: PortableTextEditorProps) {
|
|
112
132
|
super(props)
|
|
113
133
|
|
|
114
|
-
if (
|
|
115
|
-
|
|
116
|
-
|
|
134
|
+
if (props.editor) {
|
|
135
|
+
this.editorActor = props.editor
|
|
136
|
+
this.editorActor.start()
|
|
137
|
+
this.schemaTypes = this.editorActor.getSnapshot().context.schema
|
|
138
|
+
} else {
|
|
139
|
+
if (!props.schemaType) {
|
|
140
|
+
throw new Error('PortableTextEditor: missing "schemaType" property')
|
|
141
|
+
}
|
|
117
142
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
143
|
+
if (props.incomingPatches$) {
|
|
144
|
+
console.warn(
|
|
145
|
+
`The prop 'incomingPatches$' is deprecated and renamed to 'patches$'`,
|
|
146
|
+
)
|
|
147
|
+
}
|
|
123
148
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
149
|
+
this.schemaTypes = getPortableTextMemberSchemaTypes(
|
|
150
|
+
props.schemaType.hasOwnProperty('jsonType')
|
|
151
|
+
? props.schemaType
|
|
152
|
+
: compileType(props.schemaType),
|
|
153
|
+
)
|
|
129
154
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
155
|
+
this.editorActor =
|
|
156
|
+
props.editor ??
|
|
157
|
+
createActor(editorMachine, {
|
|
158
|
+
input: {
|
|
159
|
+
keyGenerator: props.keyGenerator || defaultKeyGenerator,
|
|
160
|
+
schema: this.schemaTypes,
|
|
161
|
+
},
|
|
162
|
+
})
|
|
163
|
+
this.editorActor.start()
|
|
164
|
+
}
|
|
138
165
|
}
|
|
139
166
|
|
|
140
167
|
componentDidUpdate(prevProps: PortableTextEditorProps) {
|
|
141
168
|
// Set up the schema type lookup table again if the source schema type changes
|
|
142
|
-
if (
|
|
169
|
+
if (
|
|
170
|
+
!this.props.editor &&
|
|
171
|
+
!prevProps.editor &&
|
|
172
|
+
this.props.schemaType !== prevProps.schemaType
|
|
173
|
+
) {
|
|
143
174
|
this.schemaTypes = getPortableTextMemberSchemaTypes(
|
|
144
175
|
this.props.schemaType.hasOwnProperty('jsonType')
|
|
145
176
|
? this.props.schemaType
|
|
@@ -170,49 +201,59 @@ export class PortableTextEditor extends Component<PortableTextEditorProps> {
|
|
|
170
201
|
}
|
|
171
202
|
|
|
172
203
|
render() {
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
const maxBlocks =
|
|
177
|
-
typeof this.props.maxBlocks === 'undefined'
|
|
204
|
+
const maxBlocks = !this.props.editor
|
|
205
|
+
? typeof this.props.maxBlocks === 'undefined'
|
|
178
206
|
? undefined
|
|
179
207
|
: Number.parseInt(this.props.maxBlocks.toString(), 10) || undefined
|
|
208
|
+
: undefined
|
|
180
209
|
|
|
181
210
|
const readOnly = Boolean(this.props.readOnly)
|
|
211
|
+
const legacyPatches = !this.props.editor
|
|
212
|
+
? (this.props.incomingPatches$ ?? this.props.patches$)
|
|
213
|
+
: undefined
|
|
182
214
|
|
|
183
215
|
return (
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
>
|
|
192
|
-
<
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
216
|
+
<>
|
|
217
|
+
{legacyPatches ? (
|
|
218
|
+
<RoutePatchesObservableToEditorActor
|
|
219
|
+
editorActor={this.editorActor}
|
|
220
|
+
patches$={legacyPatches}
|
|
221
|
+
/>
|
|
222
|
+
) : null}
|
|
223
|
+
<EditorActorContext.Provider value={this.editorActor}>
|
|
224
|
+
<SlateContainer
|
|
225
|
+
editorActor={this.editorActor}
|
|
226
|
+
maxBlocks={maxBlocks}
|
|
227
|
+
portableTextEditor={this}
|
|
228
|
+
readOnly={readOnly}
|
|
229
|
+
>
|
|
230
|
+
<PortableTextEditorContext.Provider value={this}>
|
|
231
|
+
<PortableTextEditorReadOnlyContext.Provider value={readOnly}>
|
|
232
|
+
<PortableTextEditorSelectionProvider
|
|
198
233
|
editorActor={this.editorActor}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
this.
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
234
|
+
>
|
|
235
|
+
<Synchronizer
|
|
236
|
+
editorActor={this.editorActor}
|
|
237
|
+
getValue={this.getValue}
|
|
238
|
+
onChange={(change) => {
|
|
239
|
+
if (!this.props.editor) {
|
|
240
|
+
this.props.onChange(change)
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* For backwards compatibility, we relay all changes to the
|
|
244
|
+
* `change$` Subject as well.
|
|
245
|
+
*/
|
|
246
|
+
this.change$.next(change)
|
|
247
|
+
}}
|
|
248
|
+
value={this.props.value}
|
|
249
|
+
/>
|
|
250
|
+
{this.props.children}
|
|
251
|
+
</PortableTextEditorSelectionProvider>
|
|
252
|
+
</PortableTextEditorReadOnlyContext.Provider>
|
|
253
|
+
</PortableTextEditorContext.Provider>
|
|
254
|
+
</SlateContainer>
|
|
255
|
+
</EditorActorContext.Provider>
|
|
256
|
+
</>
|
|
216
257
|
)
|
|
217
258
|
}
|
|
218
259
|
|
|
@@ -378,3 +419,23 @@ export class PortableTextEditor extends Component<PortableTextEditorProps> {
|
|
|
378
419
|
return editor.editable?.isSelectionsOverlapping(selectionA, selectionB)
|
|
379
420
|
}
|
|
380
421
|
}
|
|
422
|
+
|
|
423
|
+
function RoutePatchesObservableToEditorActor(props: {
|
|
424
|
+
editorActor: EditorActor
|
|
425
|
+
patches$: PatchObservable
|
|
426
|
+
}) {
|
|
427
|
+
useEffect(() => {
|
|
428
|
+
const subscription = props.patches$.subscribe((payload) => {
|
|
429
|
+
props.editorActor.send({
|
|
430
|
+
type: 'patches',
|
|
431
|
+
...payload,
|
|
432
|
+
})
|
|
433
|
+
})
|
|
434
|
+
|
|
435
|
+
return () => {
|
|
436
|
+
subscription.unsubscribe()
|
|
437
|
+
}
|
|
438
|
+
}, [props.editorActor, props.patches$])
|
|
439
|
+
|
|
440
|
+
return null
|
|
441
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import type {PortableTextMemberSchemaTypes} from '../../types/editor'
|
|
2
|
+
import {defineBehavior} from './behavior.types'
|
|
3
|
+
import {
|
|
4
|
+
getFocusSpan,
|
|
5
|
+
getFocusTextBlock,
|
|
6
|
+
selectionIsCollapsed,
|
|
7
|
+
} from './behavior.utils'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @alpha
|
|
11
|
+
*/
|
|
12
|
+
export type MarkdownBehaviorsConfig = {
|
|
13
|
+
mapDefaultStyle: (schema: PortableTextMemberSchemaTypes) => string | undefined
|
|
14
|
+
mapHeadingStyle: (
|
|
15
|
+
schema: PortableTextMemberSchemaTypes,
|
|
16
|
+
level: number,
|
|
17
|
+
) => string | undefined
|
|
18
|
+
mapBlockquoteStyle: (
|
|
19
|
+
schema: PortableTextMemberSchemaTypes,
|
|
20
|
+
) => string | undefined
|
|
21
|
+
mapUnorderedListStyle: (
|
|
22
|
+
schema: PortableTextMemberSchemaTypes,
|
|
23
|
+
) => string | undefined
|
|
24
|
+
mapOrderedListStyle: (
|
|
25
|
+
schema: PortableTextMemberSchemaTypes,
|
|
26
|
+
) => string | undefined
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @alpha
|
|
31
|
+
*/
|
|
32
|
+
export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
|
|
33
|
+
const automaticStyleOnSpace = defineBehavior({
|
|
34
|
+
on: 'insert text',
|
|
35
|
+
guard: ({context, event}) => {
|
|
36
|
+
const isSpace = event.text === ' '
|
|
37
|
+
|
|
38
|
+
if (!isSpace) {
|
|
39
|
+
return false
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const selectionCollapsed = selectionIsCollapsed(context)
|
|
43
|
+
const focusTextBlock = getFocusTextBlock(context)
|
|
44
|
+
const focusSpan = getFocusSpan(context)
|
|
45
|
+
|
|
46
|
+
if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
|
|
47
|
+
return false
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const looksLikeMarkdownHeading = /^#+/.test(focusSpan.node.text)
|
|
51
|
+
const headingStyle = config.mapHeadingStyle(
|
|
52
|
+
context.schema,
|
|
53
|
+
focusSpan.node.text.length,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
const looksLikeMarkdownQuote = /^>/.test(focusSpan.node.text)
|
|
57
|
+
const blockquoteStyle = config.mapBlockquoteStyle(context.schema)
|
|
58
|
+
|
|
59
|
+
if (looksLikeMarkdownHeading && headingStyle !== undefined) {
|
|
60
|
+
return {focusTextBlock, focusSpan, style: headingStyle}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (looksLikeMarkdownQuote && blockquoteStyle !== undefined) {
|
|
64
|
+
return {focusTextBlock, focusSpan, style: blockquoteStyle}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return false
|
|
68
|
+
},
|
|
69
|
+
actions: [
|
|
70
|
+
() => [
|
|
71
|
+
{
|
|
72
|
+
type: 'insert text',
|
|
73
|
+
text: ' ',
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
(_, {focusTextBlock, focusSpan, style}) => [
|
|
77
|
+
{
|
|
78
|
+
type: 'set block',
|
|
79
|
+
style,
|
|
80
|
+
paths: [focusTextBlock.path],
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
type: 'delete',
|
|
84
|
+
selection: {
|
|
85
|
+
anchor: {path: focusSpan.path, offset: 0},
|
|
86
|
+
focus: {
|
|
87
|
+
path: focusSpan.path,
|
|
88
|
+
offset: focusSpan.node.text.length + 1,
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
],
|
|
94
|
+
})
|
|
95
|
+
const clearStyleOnBackspace = defineBehavior({
|
|
96
|
+
on: 'delete backward',
|
|
97
|
+
guard: ({context}) => {
|
|
98
|
+
const selectionCollapsed = selectionIsCollapsed(context)
|
|
99
|
+
const focusTextBlock = getFocusTextBlock(context)
|
|
100
|
+
const focusSpan = getFocusSpan(context)
|
|
101
|
+
|
|
102
|
+
if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
|
|
103
|
+
return false
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const defaultStyle = config.mapDefaultStyle(context.schema)
|
|
107
|
+
|
|
108
|
+
if (
|
|
109
|
+
defaultStyle &&
|
|
110
|
+
focusTextBlock.node.children.length === 1 &&
|
|
111
|
+
focusTextBlock.node.style !== config.mapDefaultStyle(context.schema) &&
|
|
112
|
+
focusSpan.node.text === ''
|
|
113
|
+
) {
|
|
114
|
+
return {defaultStyle, focusTextBlock}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return false
|
|
118
|
+
},
|
|
119
|
+
actions: [
|
|
120
|
+
(_, {defaultStyle, focusTextBlock}) => [
|
|
121
|
+
{
|
|
122
|
+
type: 'set block',
|
|
123
|
+
style: defaultStyle,
|
|
124
|
+
paths: [focusTextBlock.path],
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
],
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
const automaticListOnSpace = defineBehavior({
|
|
131
|
+
on: 'insert text',
|
|
132
|
+
guard: ({context, event}) => {
|
|
133
|
+
const isSpace = event.text === ' '
|
|
134
|
+
|
|
135
|
+
if (!isSpace) {
|
|
136
|
+
return false
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const selectionCollapsed = selectionIsCollapsed(context)
|
|
140
|
+
const focusTextBlock = getFocusTextBlock(context)
|
|
141
|
+
const focusSpan = getFocusSpan(context)
|
|
142
|
+
|
|
143
|
+
if (!selectionCollapsed || !focusTextBlock || !focusSpan) {
|
|
144
|
+
return false
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const looksLikeUnorderedList = /^-/.test(focusSpan.node.text)
|
|
148
|
+
const unorderedListStyle = config.mapUnorderedListStyle(context.schema)
|
|
149
|
+
|
|
150
|
+
if (looksLikeUnorderedList && unorderedListStyle !== undefined) {
|
|
151
|
+
return {focusTextBlock, focusSpan, listItem: unorderedListStyle}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const looksLikeOrderedList = /^1./.test(focusSpan.node.text)
|
|
155
|
+
const orderedListStyle = config.mapOrderedListStyle(context.schema)
|
|
156
|
+
|
|
157
|
+
if (looksLikeOrderedList && orderedListStyle !== undefined) {
|
|
158
|
+
return {focusTextBlock, focusSpan, listItem: orderedListStyle}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return false
|
|
162
|
+
},
|
|
163
|
+
actions: [
|
|
164
|
+
() => [
|
|
165
|
+
{
|
|
166
|
+
type: 'insert text',
|
|
167
|
+
text: ' ',
|
|
168
|
+
},
|
|
169
|
+
],
|
|
170
|
+
(_, {focusTextBlock, focusSpan, listItem}) => [
|
|
171
|
+
{
|
|
172
|
+
type: 'unset block',
|
|
173
|
+
props: ['style'],
|
|
174
|
+
paths: [focusTextBlock.path],
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
type: 'set block',
|
|
178
|
+
listItem,
|
|
179
|
+
level: 1,
|
|
180
|
+
paths: [focusTextBlock.path],
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
type: 'delete',
|
|
184
|
+
selection: {
|
|
185
|
+
anchor: {path: focusSpan.path, offset: 0},
|
|
186
|
+
focus: {
|
|
187
|
+
path: focusSpan.path,
|
|
188
|
+
offset: focusSpan.node.text.length + 1,
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
],
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
const markdownBehaviors = [
|
|
197
|
+
automaticStyleOnSpace,
|
|
198
|
+
clearStyleOnBackspace,
|
|
199
|
+
automaticListOnSpace,
|
|
200
|
+
]
|
|
201
|
+
|
|
202
|
+
return markdownBehaviors
|
|
203
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import {useEffect, useMemo, useState, type PropsWithChildren} from 'react'
|
|
2
2
|
import {createEditor} from 'slate'
|
|
3
3
|
import {Slate, withReact} from 'slate-react'
|
|
4
|
-
import type {PatchObservable} from '../../types/editor'
|
|
5
4
|
import {debugWithName} from '../../utils/debug'
|
|
6
5
|
import {KEY_TO_SLATE_ELEMENT, KEY_TO_VALUE_ELEMENT} from '../../utils/weakMaps'
|
|
7
6
|
import type {EditorActor} from '../editor-machine'
|
|
@@ -16,7 +15,6 @@ const debug = debugWithName('component:PortableTextEditor:SlateContainer')
|
|
|
16
15
|
export interface SlateContainerProps extends PropsWithChildren {
|
|
17
16
|
editorActor: EditorActor
|
|
18
17
|
maxBlocks: number | undefined
|
|
19
|
-
patches$?: PatchObservable
|
|
20
18
|
portableTextEditor: PortableTextEditor
|
|
21
19
|
readOnly: boolean
|
|
22
20
|
}
|
|
@@ -26,7 +24,7 @@ export interface SlateContainerProps extends PropsWithChildren {
|
|
|
26
24
|
* @internal
|
|
27
25
|
*/
|
|
28
26
|
export function SlateContainer(props: SlateContainerProps) {
|
|
29
|
-
const {editorActor,
|
|
27
|
+
const {editorActor, portableTextEditor, readOnly, maxBlocks} = props
|
|
30
28
|
|
|
31
29
|
// Create the slate instance, using `useState` ensures setup is only run once, initially
|
|
32
30
|
const [[slateEditor, subscribe]] = useState(() => {
|
|
@@ -34,7 +32,6 @@ export function SlateContainer(props: SlateContainerProps) {
|
|
|
34
32
|
const {editor, subscribe: _sub} = withPlugins(withReact(createEditor()), {
|
|
35
33
|
editorActor,
|
|
36
34
|
maxBlocks,
|
|
37
|
-
patches$,
|
|
38
35
|
portableTextEditor,
|
|
39
36
|
readOnly,
|
|
40
37
|
})
|
|
@@ -56,18 +53,10 @@ export function SlateContainer(props: SlateContainerProps) {
|
|
|
56
53
|
withPlugins(slateEditor, {
|
|
57
54
|
editorActor,
|
|
58
55
|
maxBlocks,
|
|
59
|
-
patches$,
|
|
60
56
|
portableTextEditor,
|
|
61
57
|
readOnly,
|
|
62
58
|
})
|
|
63
|
-
}, [
|
|
64
|
-
editorActor,
|
|
65
|
-
portableTextEditor,
|
|
66
|
-
maxBlocks,
|
|
67
|
-
readOnly,
|
|
68
|
-
patches$,
|
|
69
|
-
slateEditor,
|
|
70
|
-
])
|
|
59
|
+
}, [editorActor, portableTextEditor, maxBlocks, readOnly, slateEditor])
|
|
71
60
|
|
|
72
61
|
const initialValue = useMemo(() => {
|
|
73
62
|
return [slateEditor.pteCreateTextBlock({decorators: []})]
|