@portabletext/editor 1.13.0 → 1.14.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 +1 -1
- package/lib/_chunks-cjs/selector.get-text-before.cjs +320 -0
- package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -0
- package/lib/_chunks-es/selector.get-text-before.js +321 -0
- package/lib/_chunks-es/selector.get-text-before.js.map +1 -0
- package/lib/{index.esm.js → index.cjs} +1703 -1431
- package/lib/index.cjs.map +1 -0
- package/lib/{index.d.mts → index.d.cts} +4038 -313
- package/lib/index.d.ts +4038 -313
- package/lib/index.js +1724 -1407
- package/lib/index.js.map +1 -1
- package/lib/selectors/index.cjs +35 -0
- package/lib/selectors/index.cjs.map +1 -0
- package/lib/selectors/index.d.cts +243 -0
- package/lib/selectors/index.d.ts +243 -0
- package/lib/selectors/index.js +36 -0
- package/lib/selectors/index.js.map +1 -0
- package/package.json +21 -13
- package/src/editor/Editable.tsx +1 -1
- package/src/editor/PortableTextEditor.tsx +19 -4
- package/src/editor/__tests__/handleClick.test.tsx +4 -4
- package/src/editor/behavior/behavior.action.insert-block-object.ts +1 -1
- package/src/editor/behavior/behavior.action.insert-break.ts +3 -3
- package/src/editor/behavior/behavior.action.insert-inline-object.ts +58 -0
- package/src/editor/behavior/behavior.action.insert-span.ts +1 -1
- package/src/editor/behavior/behavior.action.list-item.ts +100 -0
- package/src/editor/behavior/behavior.action.style.ts +108 -0
- package/src/editor/behavior/behavior.action.text-block.set.ts +25 -0
- package/src/editor/behavior/behavior.action.text-block.unset.ts +17 -0
- package/src/editor/behavior/behavior.actions.ts +178 -109
- package/src/editor/behavior/behavior.code-editor.ts +30 -40
- package/src/editor/behavior/behavior.core.block-objects.ts +26 -26
- package/src/editor/behavior/behavior.core.decorators.ts +9 -6
- package/src/editor/behavior/behavior.core.lists.ts +139 -17
- package/src/editor/behavior/behavior.core.ts +5 -2
- package/src/editor/behavior/behavior.guards.ts +28 -0
- package/src/editor/behavior/behavior.links.ts +7 -7
- package/src/editor/behavior/behavior.markdown.ts +68 -79
- package/src/editor/behavior/behavior.types.ts +86 -60
- package/src/editor/{use-editor.ts → create-editor.ts} +13 -8
- package/src/editor/editor-event-listener.tsx +2 -2
- package/src/editor/editor-machine.ts +54 -15
- package/src/editor/editor-provider.tsx +5 -5
- package/src/editor/editor-selector.ts +49 -0
- package/src/editor/editor-snapshot.ts +22 -0
- package/src/editor/get-value.ts +11 -0
- package/src/editor/plugins/create-with-event-listeners.ts +93 -5
- package/src/editor/plugins/createWithEditableAPI.ts +69 -20
- package/src/editor/plugins/createWithHotKeys.ts +0 -54
- package/src/editor/plugins/createWithPortableTextBlockStyle.ts +1 -55
- package/src/editor/plugins/with-plugins.ts +4 -8
- package/src/editor/{behavior/behavior.utils.block-offset.test.ts → utils/utils.block-offset.test.ts} +1 -1
- package/src/editor/{behavior/behavior.utils.block-offset.ts → utils/utils.block-offset.ts} +1 -8
- package/src/editor/{behavior/behavior.utils.reverse-selection.ts → utils/utils.reverse-selection.ts} +3 -5
- package/src/editor/utils/utils.ts +21 -0
- package/src/index.ts +13 -13
- package/src/selectors/index.ts +15 -0
- package/src/selectors/selector.get-active-list-item.ts +37 -0
- package/src/{editor/behavior/behavior.utils.get-selection-text.ts → selectors/selector.get-selection-text.ts} +10 -15
- package/src/selectors/selector.get-text-before.ts +41 -0
- package/src/selectors/selectors.ts +329 -0
- package/src/types/editor.ts +0 -60
- package/src/utils/is-hotkey.test.ts +2 -0
- package/src/utils/operationToPatches.ts +5 -0
- package/src/utils/paths.ts +4 -11
- package/src/utils/ranges.ts +3 -3
- package/lib/index.esm.js.map +0 -1
- package/lib/index.mjs +0 -7541
- package/lib/index.mjs.map +0 -1
- package/src/editor/behavior/behavior.utils.ts +0 -218
- package/src/editor/behavior/behavior.utilts.get-text-before.ts +0 -31
- package/src/editor/plugins/createWithPortableTextLists.ts +0 -172
- /package/src/editor/{behavior/behavior.utils.get-start-point.ts → utils/utils.get-start-point.ts} +0 -0
- /package/src/editor/{behavior/behavior.utils.is-keyed-segment.ts → utils/utils.is-keyed-segment.ts} +0 -0
|
@@ -16,6 +16,7 @@ import type {
|
|
|
16
16
|
PortableTextMemberSchemaTypes,
|
|
17
17
|
PortableTextSlateEditor,
|
|
18
18
|
} from '../types/editor'
|
|
19
|
+
import debug from '../utils/debug'
|
|
19
20
|
import {toPortableTextRange} from '../utils/ranges'
|
|
20
21
|
import {fromSlateValue} from '../utils/values'
|
|
21
22
|
import {KEY_TO_VALUE_ELEMENT} from '../utils/weakMaps'
|
|
@@ -25,11 +26,11 @@ import type {
|
|
|
25
26
|
Behavior,
|
|
26
27
|
BehaviorAction,
|
|
27
28
|
BehaviorActionIntend,
|
|
28
|
-
BehaviorContext,
|
|
29
29
|
BehaviorEvent,
|
|
30
30
|
OmitFromUnion,
|
|
31
31
|
PickFromUnion,
|
|
32
32
|
} from './behavior/behavior.types'
|
|
33
|
+
import type {EditorContext} from './editor-snapshot'
|
|
33
34
|
|
|
34
35
|
export * from 'xstate/guards'
|
|
35
36
|
|
|
@@ -105,10 +106,10 @@ export type InternalEditorEvent =
|
|
|
105
106
|
export type EditorEmittedEvent = PickFromUnion<
|
|
106
107
|
InternalEditorEmittedEvent,
|
|
107
108
|
'type',
|
|
108
|
-
| '
|
|
109
|
+
| 'blurred'
|
|
109
110
|
| 'done loading'
|
|
110
111
|
| 'error'
|
|
111
|
-
| '
|
|
112
|
+
| 'focused'
|
|
112
113
|
| 'invalid value'
|
|
113
114
|
| 'loading'
|
|
114
115
|
| 'mutation'
|
|
@@ -147,7 +148,7 @@ export type InternalEditorEmittedEvent =
|
|
|
147
148
|
data: unknown
|
|
148
149
|
}
|
|
149
150
|
| {type: 'selection'; selection: EditorSelection}
|
|
150
|
-
| {type: '
|
|
151
|
+
| {type: 'blurred'; event: FocusEvent<HTMLDivElement, Element>}
|
|
151
152
|
| {type: 'focused'; event: FocusEvent<HTMLDivElement, Element>}
|
|
152
153
|
| {type: 'loading'}
|
|
153
154
|
| {type: 'done loading'}
|
|
@@ -155,7 +156,18 @@ export type InternalEditorEmittedEvent =
|
|
|
155
156
|
| PickFromUnion<
|
|
156
157
|
BehaviorEvent,
|
|
157
158
|
'type',
|
|
158
|
-
|
|
159
|
+
| 'annotation.add'
|
|
160
|
+
| 'annotation.remove'
|
|
161
|
+
| 'annotation.toggle'
|
|
162
|
+
| 'blur'
|
|
163
|
+
| 'decorator.add'
|
|
164
|
+
| 'decorator.remove'
|
|
165
|
+
| 'decorator.toggle'
|
|
166
|
+
| 'insert.block object'
|
|
167
|
+
| 'insert.inline object'
|
|
168
|
+
| 'list item.toggle'
|
|
169
|
+
| 'focus'
|
|
170
|
+
| 'style.toggle'
|
|
159
171
|
>
|
|
160
172
|
|
|
161
173
|
/**
|
|
@@ -170,6 +182,7 @@ export const editorMachine = setup({
|
|
|
170
182
|
schema: PortableTextMemberSchemaTypes
|
|
171
183
|
readOnly: boolean
|
|
172
184
|
maxBlocks: number | undefined
|
|
185
|
+
selection: NonNullable<EditorSelection> | undefined
|
|
173
186
|
value: Array<PortableTextBlock> | undefined
|
|
174
187
|
},
|
|
175
188
|
events: {} as InternalEditorEvent,
|
|
@@ -221,6 +234,8 @@ export const editorMachine = setup({
|
|
|
221
234
|
'handle behavior event': enqueueActions(({context, event, enqueue}) => {
|
|
222
235
|
assertEvent(event, ['behavior event'])
|
|
223
236
|
|
|
237
|
+
debug('Behavior event', event)
|
|
238
|
+
|
|
224
239
|
const defaultAction = {
|
|
225
240
|
...event.behaviorEvent,
|
|
226
241
|
editor: event.editor,
|
|
@@ -262,11 +277,12 @@ export const editorMachine = setup({
|
|
|
262
277
|
return
|
|
263
278
|
}
|
|
264
279
|
|
|
265
|
-
const
|
|
280
|
+
const editorContext = {
|
|
281
|
+
keyGenerator: context.keyGenerator,
|
|
266
282
|
schema: context.schema,
|
|
267
|
-
value,
|
|
268
283
|
selection,
|
|
269
|
-
|
|
284
|
+
value,
|
|
285
|
+
} satisfies EditorContext
|
|
270
286
|
|
|
271
287
|
let behaviorOverwritten = false
|
|
272
288
|
|
|
@@ -274,7 +290,7 @@ export const editorMachine = setup({
|
|
|
274
290
|
const shouldRun =
|
|
275
291
|
eventBehavior.guard === undefined ||
|
|
276
292
|
eventBehavior.guard({
|
|
277
|
-
context:
|
|
293
|
+
context: editorContext,
|
|
278
294
|
event: event.behaviorEvent,
|
|
279
295
|
})
|
|
280
296
|
|
|
@@ -283,10 +299,7 @@ export const editorMachine = setup({
|
|
|
283
299
|
}
|
|
284
300
|
|
|
285
301
|
const actionIntendSets = eventBehavior.actions.map((actionSet) =>
|
|
286
|
-
actionSet(
|
|
287
|
-
{context: behaviorContext, event: event.behaviorEvent},
|
|
288
|
-
shouldRun,
|
|
289
|
-
),
|
|
302
|
+
actionSet(shouldRun),
|
|
290
303
|
)
|
|
291
304
|
|
|
292
305
|
for (const actionIntends of actionIntendSets) {
|
|
@@ -326,6 +339,7 @@ export const editorMachine = setup({
|
|
|
326
339
|
keyGenerator: input.keyGenerator,
|
|
327
340
|
pendingEvents: [],
|
|
328
341
|
schema: input.schema,
|
|
342
|
+
selection: undefined,
|
|
329
343
|
readOnly: input.readOnly ?? false,
|
|
330
344
|
maxBlocks: input.maxBlocks,
|
|
331
345
|
value: input.value,
|
|
@@ -343,17 +357,42 @@ export const editorMachine = setup({
|
|
|
343
357
|
actions: emit(({event}) => event),
|
|
344
358
|
guard: ({context}) => !context.readOnly,
|
|
345
359
|
},
|
|
360
|
+
'blur': {
|
|
361
|
+
actions: emit(({event}) => event),
|
|
362
|
+
guard: ({context}) => !context.readOnly,
|
|
363
|
+
},
|
|
364
|
+
'decorator.*': {
|
|
365
|
+
actions: emit(({event}) => event),
|
|
366
|
+
guard: ({context}) => !context.readOnly,
|
|
367
|
+
},
|
|
346
368
|
'focus': {
|
|
347
369
|
actions: emit(({event}) => event),
|
|
348
370
|
guard: ({context}) => !context.readOnly,
|
|
349
371
|
},
|
|
372
|
+
'insert.*': {
|
|
373
|
+
actions: emit(({event}) => event),
|
|
374
|
+
guard: ({context}) => !context.readOnly,
|
|
375
|
+
},
|
|
376
|
+
'list item.*': {
|
|
377
|
+
actions: emit(({event}) => event),
|
|
378
|
+
guard: ({context}) => !context.readOnly,
|
|
379
|
+
},
|
|
380
|
+
'style.*': {
|
|
381
|
+
actions: emit(({event}) => event),
|
|
382
|
+
guard: ({context}) => !context.readOnly,
|
|
383
|
+
},
|
|
350
384
|
'ready': {actions: emit(({event}) => event)},
|
|
351
385
|
'unset': {actions: emit(({event}) => event)},
|
|
352
386
|
'value changed': {actions: emit(({event}) => event)},
|
|
353
387
|
'invalid value': {actions: emit(({event}) => event)},
|
|
354
388
|
'error': {actions: emit(({event}) => event)},
|
|
355
|
-
'selection': {
|
|
356
|
-
|
|
389
|
+
'selection': {
|
|
390
|
+
actions: [
|
|
391
|
+
assign({selection: ({event}) => event.selection ?? undefined}),
|
|
392
|
+
emit(({event}) => event),
|
|
393
|
+
],
|
|
394
|
+
},
|
|
395
|
+
'blurred': {actions: emit(({event}) => event)},
|
|
357
396
|
'focused': {actions: emit(({event}) => event)},
|
|
358
397
|
'loading': {actions: emit({type: 'loading'})},
|
|
359
398
|
'patches': {actions: emit(({event}) => event)},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React, {useMemo} from 'react'
|
|
2
2
|
import {Slate} from 'slate-react'
|
|
3
3
|
import {Synchronizer} from './components/Synchronizer'
|
|
4
|
+
import {useCreateEditor, type Editor, type EditorConfig} from './create-editor'
|
|
4
5
|
import {EditorActorContext} from './editor-actor-context'
|
|
5
6
|
import {PortableTextEditorContext} from './hooks/usePortableTextEditor'
|
|
6
7
|
import {PortableTextEditorSelectionProvider} from './hooks/usePortableTextEditorSelection'
|
|
@@ -9,7 +10,6 @@ import {
|
|
|
9
10
|
RouteEventsToChanges,
|
|
10
11
|
type PortableTextEditorProps,
|
|
11
12
|
} from './PortableTextEditor'
|
|
12
|
-
import {useEditor, type Editor, type EditorConfig} from './use-editor'
|
|
13
13
|
|
|
14
14
|
const EditorContext = React.createContext<Editor | undefined>(undefined)
|
|
15
15
|
|
|
@@ -17,7 +17,7 @@ const EditorContext = React.createContext<Editor | undefined>(undefined)
|
|
|
17
17
|
* @alpha
|
|
18
18
|
*/
|
|
19
19
|
export type EditorProviderProps = {
|
|
20
|
-
|
|
20
|
+
initialConfig: EditorConfig
|
|
21
21
|
children?: React.ReactNode
|
|
22
22
|
}
|
|
23
23
|
|
|
@@ -25,10 +25,10 @@ export type EditorProviderProps = {
|
|
|
25
25
|
* @alpha
|
|
26
26
|
*/
|
|
27
27
|
export function EditorProvider(props: EditorProviderProps) {
|
|
28
|
-
const editor =
|
|
28
|
+
const editor = useCreateEditor(props.initialConfig)
|
|
29
29
|
const editorActor = editor._internal.editorActor
|
|
30
30
|
const slateEditor = editor._internal.slateEditor
|
|
31
|
-
const editable = editor.editable
|
|
31
|
+
const editable = editor._internal.editable
|
|
32
32
|
const portableTextEditor = useMemo(
|
|
33
33
|
() =>
|
|
34
34
|
new PortableTextEditor({
|
|
@@ -70,7 +70,7 @@ export function EditorProvider(props: EditorProviderProps) {
|
|
|
70
70
|
/**
|
|
71
71
|
* @alpha
|
|
72
72
|
*/
|
|
73
|
-
export function
|
|
73
|
+
export function useEditor() {
|
|
74
74
|
const editor = React.useContext(EditorContext)
|
|
75
75
|
|
|
76
76
|
if (!editor) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {useSelector} from '@xstate/react'
|
|
2
|
+
import type {EditorSelection} from '../types/editor'
|
|
3
|
+
import type {Editor} from './create-editor'
|
|
4
|
+
import type {EditorSnapshot} from './editor-snapshot'
|
|
5
|
+
import {getValue} from './get-value'
|
|
6
|
+
|
|
7
|
+
function defaultCompare<T>(a: T, b: T) {
|
|
8
|
+
return a === b
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @alpha
|
|
13
|
+
*/
|
|
14
|
+
export type EditorSelectorSnapshot = {
|
|
15
|
+
context: Omit<EditorSnapshot['context'], 'selection'> & {
|
|
16
|
+
selection?: NonNullable<EditorSelection>
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @alpha
|
|
22
|
+
*/
|
|
23
|
+
export type EditorSelector<TSelected> = (
|
|
24
|
+
snapshot: EditorSelectorSnapshot,
|
|
25
|
+
) => TSelected
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @alpha
|
|
29
|
+
*/
|
|
30
|
+
export function useEditorSelector<TSelected>(
|
|
31
|
+
editor: Editor,
|
|
32
|
+
selector: EditorSelector<TSelected>,
|
|
33
|
+
compare: (a: TSelected, b: TSelected) => boolean = defaultCompare,
|
|
34
|
+
) {
|
|
35
|
+
return useSelector(
|
|
36
|
+
editor._internal.editorActor,
|
|
37
|
+
(snapshot) => {
|
|
38
|
+
const context = {
|
|
39
|
+
keyGenerator: snapshot.context.keyGenerator,
|
|
40
|
+
schema: snapshot.context.schema,
|
|
41
|
+
selection: snapshot.context.selection,
|
|
42
|
+
value: getValue(editor),
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return selector({context})
|
|
46
|
+
},
|
|
47
|
+
compare,
|
|
48
|
+
)
|
|
49
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type {PortableTextBlock} from '@sanity/types'
|
|
2
|
+
import type {
|
|
3
|
+
EditorSelection,
|
|
4
|
+
PortableTextMemberSchemaTypes,
|
|
5
|
+
} from '../types/editor'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @alpha
|
|
9
|
+
*/
|
|
10
|
+
export type EditorContext = {
|
|
11
|
+
keyGenerator: () => string
|
|
12
|
+
schema: PortableTextMemberSchemaTypes
|
|
13
|
+
selection: NonNullable<EditorSelection>
|
|
14
|
+
value: Array<PortableTextBlock>
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @alpha
|
|
19
|
+
*/
|
|
20
|
+
export type EditorSnapshot = {
|
|
21
|
+
context: EditorContext
|
|
22
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import {fromSlateValue} from '../utils/values'
|
|
2
|
+
import {KEY_TO_VALUE_ELEMENT} from '../utils/weakMaps'
|
|
3
|
+
import type {Editor} from './create-editor'
|
|
4
|
+
|
|
5
|
+
export function getValue(editor: Editor) {
|
|
6
|
+
return fromSlateValue(
|
|
7
|
+
editor._internal.slateEditor.instance.children,
|
|
8
|
+
editor._internal.editorActor.getSnapshot().context.schema.block.name,
|
|
9
|
+
KEY_TO_VALUE_ELEMENT.get(editor._internal.slateEditor.instance),
|
|
10
|
+
)
|
|
11
|
+
}
|
|
@@ -46,6 +46,49 @@ export function createWithEventListeners(
|
|
|
46
46
|
})
|
|
47
47
|
break
|
|
48
48
|
}
|
|
49
|
+
case 'blur': {
|
|
50
|
+
editorActor.send({
|
|
51
|
+
type: 'behavior event',
|
|
52
|
+
behaviorEvent: {
|
|
53
|
+
type: 'blur',
|
|
54
|
+
},
|
|
55
|
+
editor,
|
|
56
|
+
})
|
|
57
|
+
break
|
|
58
|
+
}
|
|
59
|
+
case 'decorator.add': {
|
|
60
|
+
editorActor.send({
|
|
61
|
+
type: 'behavior event',
|
|
62
|
+
behaviorEvent: {
|
|
63
|
+
type: 'decorator.add',
|
|
64
|
+
decorator: event.decorator,
|
|
65
|
+
},
|
|
66
|
+
editor,
|
|
67
|
+
})
|
|
68
|
+
break
|
|
69
|
+
}
|
|
70
|
+
case 'decorator.remove': {
|
|
71
|
+
editorActor.send({
|
|
72
|
+
type: 'behavior event',
|
|
73
|
+
behaviorEvent: {
|
|
74
|
+
type: 'decorator.remove',
|
|
75
|
+
decorator: event.decorator,
|
|
76
|
+
},
|
|
77
|
+
editor,
|
|
78
|
+
})
|
|
79
|
+
break
|
|
80
|
+
}
|
|
81
|
+
case 'decorator.toggle': {
|
|
82
|
+
editorActor.send({
|
|
83
|
+
type: 'behavior event',
|
|
84
|
+
behaviorEvent: {
|
|
85
|
+
type: 'decorator.toggle',
|
|
86
|
+
decorator: event.decorator,
|
|
87
|
+
},
|
|
88
|
+
editor,
|
|
89
|
+
})
|
|
90
|
+
break
|
|
91
|
+
}
|
|
49
92
|
case 'focus': {
|
|
50
93
|
editorActor.send({
|
|
51
94
|
type: 'behavior event',
|
|
@@ -56,6 +99,51 @@ export function createWithEventListeners(
|
|
|
56
99
|
})
|
|
57
100
|
break
|
|
58
101
|
}
|
|
102
|
+
case 'insert.block object': {
|
|
103
|
+
editorActor.send({
|
|
104
|
+
type: 'behavior event',
|
|
105
|
+
behaviorEvent: {
|
|
106
|
+
type: 'insert.block object',
|
|
107
|
+
placement: event.placement,
|
|
108
|
+
blockObject: event.blockObject,
|
|
109
|
+
},
|
|
110
|
+
editor,
|
|
111
|
+
})
|
|
112
|
+
break
|
|
113
|
+
}
|
|
114
|
+
case 'insert.inline object': {
|
|
115
|
+
editorActor.send({
|
|
116
|
+
type: 'behavior event',
|
|
117
|
+
behaviorEvent: {
|
|
118
|
+
type: 'insert.inline object',
|
|
119
|
+
inlineObject: event.inlineObject,
|
|
120
|
+
},
|
|
121
|
+
editor,
|
|
122
|
+
})
|
|
123
|
+
break
|
|
124
|
+
}
|
|
125
|
+
case 'list item.toggle': {
|
|
126
|
+
editorActor.send({
|
|
127
|
+
type: 'behavior event',
|
|
128
|
+
behaviorEvent: {
|
|
129
|
+
type: 'list item.toggle',
|
|
130
|
+
listItem: event.listItem,
|
|
131
|
+
},
|
|
132
|
+
editor,
|
|
133
|
+
})
|
|
134
|
+
break
|
|
135
|
+
}
|
|
136
|
+
case 'style.toggle': {
|
|
137
|
+
editorActor.send({
|
|
138
|
+
type: 'behavior event',
|
|
139
|
+
behaviorEvent: {
|
|
140
|
+
type: 'style.toggle',
|
|
141
|
+
style: event.style,
|
|
142
|
+
},
|
|
143
|
+
editor,
|
|
144
|
+
})
|
|
145
|
+
break
|
|
146
|
+
}
|
|
59
147
|
}
|
|
60
148
|
})
|
|
61
149
|
|
|
@@ -92,7 +180,7 @@ export function createWithEventListeners(
|
|
|
92
180
|
editorActor.send({
|
|
93
181
|
type: 'behavior event',
|
|
94
182
|
behaviorEvent: {
|
|
95
|
-
type: 'delete
|
|
183
|
+
type: 'delete.backward',
|
|
96
184
|
unit,
|
|
97
185
|
},
|
|
98
186
|
editor,
|
|
@@ -104,7 +192,7 @@ export function createWithEventListeners(
|
|
|
104
192
|
editorActor.send({
|
|
105
193
|
type: 'behavior event',
|
|
106
194
|
behaviorEvent: {
|
|
107
|
-
type: 'delete
|
|
195
|
+
type: 'delete.forward',
|
|
108
196
|
unit,
|
|
109
197
|
},
|
|
110
198
|
editor,
|
|
@@ -116,7 +204,7 @@ export function createWithEventListeners(
|
|
|
116
204
|
editorActor.send({
|
|
117
205
|
type: 'behavior event',
|
|
118
206
|
behaviorEvent: {
|
|
119
|
-
type: 'insert
|
|
207
|
+
type: 'insert.break',
|
|
120
208
|
},
|
|
121
209
|
editor,
|
|
122
210
|
})
|
|
@@ -127,7 +215,7 @@ export function createWithEventListeners(
|
|
|
127
215
|
editorActor.send({
|
|
128
216
|
type: 'behavior event',
|
|
129
217
|
behaviorEvent: {
|
|
130
|
-
type: 'insert
|
|
218
|
+
type: 'insert.soft break',
|
|
131
219
|
},
|
|
132
220
|
editor,
|
|
133
221
|
})
|
|
@@ -138,7 +226,7 @@ export function createWithEventListeners(
|
|
|
138
226
|
editorActor.send({
|
|
139
227
|
type: 'behavior event',
|
|
140
228
|
behaviorEvent: {
|
|
141
|
-
type: 'insert
|
|
229
|
+
type: 'insert.text',
|
|
142
230
|
text,
|
|
143
231
|
options,
|
|
144
232
|
},
|
|
@@ -31,7 +31,8 @@ import {
|
|
|
31
31
|
KEY_TO_VALUE_ELEMENT,
|
|
32
32
|
SLATE_TO_PORTABLE_TEXT_RANGE,
|
|
33
33
|
} from '../../utils/weakMaps'
|
|
34
|
-
import {
|
|
34
|
+
import {isListItemActive} from '../behavior/behavior.action.list-item'
|
|
35
|
+
import {isStyleActive} from '../behavior/behavior.action.style'
|
|
35
36
|
import type {BehaviorActionImplementation} from '../behavior/behavior.actions'
|
|
36
37
|
import type {EditorActor} from '../editor-machine'
|
|
37
38
|
import {isDecoratorActive} from './createWithPortableTextMarkModel'
|
|
@@ -46,10 +47,22 @@ export function createEditableAPI(
|
|
|
46
47
|
|
|
47
48
|
const editableApi: EditableAPI = {
|
|
48
49
|
focus: (): void => {
|
|
49
|
-
|
|
50
|
+
editorActor.send({
|
|
51
|
+
type: 'behavior event',
|
|
52
|
+
behaviorEvent: {
|
|
53
|
+
type: 'focus',
|
|
54
|
+
},
|
|
55
|
+
editor,
|
|
56
|
+
})
|
|
50
57
|
},
|
|
51
58
|
blur: (): void => {
|
|
52
|
-
|
|
59
|
+
editorActor.send({
|
|
60
|
+
type: 'behavior event',
|
|
61
|
+
behaviorEvent: {
|
|
62
|
+
type: 'blur',
|
|
63
|
+
},
|
|
64
|
+
editor,
|
|
65
|
+
})
|
|
53
66
|
},
|
|
54
67
|
toggleMark: (mark: string): void => {
|
|
55
68
|
editorActor.send({
|
|
@@ -61,11 +74,25 @@ export function createEditableAPI(
|
|
|
61
74
|
editor,
|
|
62
75
|
})
|
|
63
76
|
},
|
|
64
|
-
toggleList: (
|
|
65
|
-
|
|
77
|
+
toggleList: (listItem: string): void => {
|
|
78
|
+
editorActor.send({
|
|
79
|
+
type: 'behavior event',
|
|
80
|
+
behaviorEvent: {
|
|
81
|
+
type: 'list item.toggle',
|
|
82
|
+
listItem,
|
|
83
|
+
},
|
|
84
|
+
editor,
|
|
85
|
+
})
|
|
66
86
|
},
|
|
67
|
-
toggleBlockStyle: (
|
|
68
|
-
|
|
87
|
+
toggleBlockStyle: (style: string): void => {
|
|
88
|
+
editorActor.send({
|
|
89
|
+
type: 'behavior event',
|
|
90
|
+
behaviorEvent: {
|
|
91
|
+
type: 'style.toggle',
|
|
92
|
+
style,
|
|
93
|
+
},
|
|
94
|
+
editor,
|
|
95
|
+
})
|
|
69
96
|
},
|
|
70
97
|
isMarkActive: (mark: string): boolean => {
|
|
71
98
|
// Try/catch this, as Slate may error because the selection is currently wrong
|
|
@@ -132,6 +159,32 @@ export function createEditableAPI(
|
|
|
132
159
|
type: TSchemaType,
|
|
133
160
|
value?: {[prop: string]: any},
|
|
134
161
|
): Path => {
|
|
162
|
+
if (type.name !== types.span.name) {
|
|
163
|
+
editorActor.send({
|
|
164
|
+
type: 'behavior event',
|
|
165
|
+
behaviorEvent: {
|
|
166
|
+
type: 'insert.inline object',
|
|
167
|
+
inlineObject: {
|
|
168
|
+
name: type.name,
|
|
169
|
+
value,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
editor,
|
|
173
|
+
})
|
|
174
|
+
|
|
175
|
+
return (
|
|
176
|
+
toPortableTextRange(
|
|
177
|
+
fromSlateValue(
|
|
178
|
+
editor.children,
|
|
179
|
+
types.block.name,
|
|
180
|
+
KEY_TO_VALUE_ELEMENT.get(editor),
|
|
181
|
+
),
|
|
182
|
+
editor.selection,
|
|
183
|
+
types,
|
|
184
|
+
)?.focus.path ?? []
|
|
185
|
+
)
|
|
186
|
+
}
|
|
187
|
+
|
|
135
188
|
if (!editor.selection) {
|
|
136
189
|
throw new Error('The editor has no selection')
|
|
137
190
|
}
|
|
@@ -187,6 +240,7 @@ export function createEditableAPI(
|
|
|
187
240
|
at: editor.selection,
|
|
188
241
|
})
|
|
189
242
|
editor.onChange()
|
|
243
|
+
|
|
190
244
|
return (
|
|
191
245
|
toPortableTextRange(
|
|
192
246
|
fromSlateValue(
|
|
@@ -203,24 +257,19 @@ export function createEditableAPI(
|
|
|
203
257
|
type: TSchemaType,
|
|
204
258
|
value?: {[prop: string]: any},
|
|
205
259
|
): Path => {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
},
|
|
211
|
-
action: {
|
|
212
|
-
type: 'insert block object',
|
|
260
|
+
editorActor.send({
|
|
261
|
+
type: 'behavior event',
|
|
262
|
+
behaviorEvent: {
|
|
263
|
+
type: 'insert.block object',
|
|
213
264
|
blockObject: {
|
|
214
265
|
name: type.name,
|
|
215
266
|
value,
|
|
216
267
|
},
|
|
217
268
|
placement: 'auto',
|
|
218
|
-
editor,
|
|
219
269
|
},
|
|
270
|
+
editor,
|
|
220
271
|
})
|
|
221
272
|
|
|
222
|
-
editor.onChange()
|
|
223
|
-
|
|
224
273
|
return (
|
|
225
274
|
toPortableTextRange(
|
|
226
275
|
fromSlateValue(
|
|
@@ -235,15 +284,15 @@ export function createEditableAPI(
|
|
|
235
284
|
},
|
|
236
285
|
hasBlockStyle: (style: string): boolean => {
|
|
237
286
|
try {
|
|
238
|
-
return editor
|
|
287
|
+
return isStyleActive({editor, style})
|
|
239
288
|
} catch {
|
|
240
289
|
// This is fine.
|
|
241
290
|
return false
|
|
242
291
|
}
|
|
243
292
|
},
|
|
244
|
-
hasListStyle: (
|
|
293
|
+
hasListStyle: (listItem: string): boolean => {
|
|
245
294
|
try {
|
|
246
|
-
return editor
|
|
295
|
+
return isListItemActive({editor, listItem})
|
|
247
296
|
} catch {
|
|
248
297
|
// This is fine.
|
|
249
298
|
return false
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import {isPortableTextSpan, isPortableTextTextBlock} from '@sanity/types'
|
|
2
1
|
import type {KeyboardEvent} from 'react'
|
|
3
|
-
import {Editor, Node, Range} from 'slate'
|
|
4
2
|
import type {ReactEditor} from 'slate-react'
|
|
5
3
|
import type {PortableTextSlateEditor} from '../../types/editor'
|
|
6
4
|
import type {HotkeyOptions} from '../../types/options'
|
|
7
|
-
import type {SlateTextBlock, VoidElement} from '../../types/slate'
|
|
8
5
|
import {debugWithName} from '../../utils/debug'
|
|
9
6
|
import {isHotkey} from '../../utils/is-hotkey'
|
|
10
7
|
import type {EditorActor} from '../editor-machine'
|
|
@@ -75,57 +72,6 @@ export function createWithHotkeys(
|
|
|
75
72
|
}
|
|
76
73
|
}
|
|
77
74
|
})
|
|
78
|
-
|
|
79
|
-
const isEnter = isHotkey('enter', event.nativeEvent)
|
|
80
|
-
const isTab = isHotkey('tab', event.nativeEvent)
|
|
81
|
-
const isShiftEnter = isHotkey('shift+enter', event.nativeEvent)
|
|
82
|
-
const isShiftTab = isHotkey('shift+tab', event.nativeEvent)
|
|
83
|
-
|
|
84
|
-
// Tab for lists
|
|
85
|
-
// Only steal tab when we are on a plain text span or we are at the start of the line (fallback if the whole block is annotated or contains a single inline object)
|
|
86
|
-
// Otherwise tab is reserved for accessability for buttons etc.
|
|
87
|
-
if ((isTab || isShiftTab) && editor.selection) {
|
|
88
|
-
const [focusChild] = Editor.node(editor, editor.selection.focus, {
|
|
89
|
-
depth: 2,
|
|
90
|
-
})
|
|
91
|
-
const [focusBlock] = isPortableTextSpan(focusChild)
|
|
92
|
-
? Editor.node(editor, editor.selection.focus, {depth: 1})
|
|
93
|
-
: []
|
|
94
|
-
const hasAnnotationFocus =
|
|
95
|
-
focusChild &&
|
|
96
|
-
isPortableTextTextBlock(focusBlock) &&
|
|
97
|
-
isPortableTextSpan(focusChild) &&
|
|
98
|
-
(focusChild.marks || ([] as string[])).filter((m) =>
|
|
99
|
-
(focusBlock.markDefs || []).map((def) => def._key).includes(m),
|
|
100
|
-
).length > 0
|
|
101
|
-
const [start] = Range.edges(editor.selection)
|
|
102
|
-
const atStartOfNode = Editor.isStart(editor, start, start.path)
|
|
103
|
-
|
|
104
|
-
if (
|
|
105
|
-
focusChild &&
|
|
106
|
-
isPortableTextSpan(focusChild) &&
|
|
107
|
-
(!hasAnnotationFocus || atStartOfNode) &&
|
|
108
|
-
editor.pteIncrementBlockLevels(isShiftTab)
|
|
109
|
-
) {
|
|
110
|
-
event.preventDefault()
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// Deal with enter key combos
|
|
115
|
-
if (isEnter && !isShiftEnter && editor.selection) {
|
|
116
|
-
const focusBlockPath = editor.selection.focus.path.slice(0, 1)
|
|
117
|
-
const focusBlock = Node.descendant(editor, focusBlockPath) as
|
|
118
|
-
| SlateTextBlock
|
|
119
|
-
| VoidElement
|
|
120
|
-
|
|
121
|
-
// List item enter key
|
|
122
|
-
if (editor.isListBlock(focusBlock)) {
|
|
123
|
-
if (editor.pteEndList()) {
|
|
124
|
-
event.preventDefault()
|
|
125
|
-
}
|
|
126
|
-
return
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
75
|
}
|
|
130
76
|
return editor
|
|
131
77
|
}
|