@portabletext/editor 1.31.2 → 1.33.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/_chunks-cjs/behavior.core.cjs +4 -4
- package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
- package/lib/_chunks-cjs/behavior.markdown.cjs +19 -11
- package/lib/_chunks-cjs/behavior.markdown.cjs.map +1 -1
- package/lib/_chunks-cjs/plugin.event-listener.cjs +1839 -1724
- package/lib/_chunks-cjs/plugin.event-listener.cjs.map +1 -1
- package/lib/_chunks-cjs/selector.get-trimmed-selection.cjs +97 -0
- package/lib/_chunks-cjs/selector.get-trimmed-selection.cjs.map +1 -0
- package/lib/_chunks-cjs/{parse-blocks.cjs → util.block-offsets-to-selection.cjs} +21 -2
- package/lib/_chunks-cjs/util.block-offsets-to-selection.cjs.map +1 -0
- package/lib/_chunks-cjs/util.reverse-selection.cjs +11 -0
- package/lib/_chunks-cjs/util.reverse-selection.cjs.map +1 -1
- package/lib/_chunks-es/behavior.core.js +1 -1
- package/lib/_chunks-es/behavior.core.js.map +1 -1
- package/lib/_chunks-es/behavior.markdown.js +18 -11
- package/lib/_chunks-es/behavior.markdown.js.map +1 -1
- package/lib/_chunks-es/plugin.event-listener.js +1842 -1726
- package/lib/_chunks-es/plugin.event-listener.js.map +1 -1
- package/lib/_chunks-es/selector.get-trimmed-selection.js +100 -0
- package/lib/_chunks-es/selector.get-trimmed-selection.js.map +1 -0
- package/lib/_chunks-es/{parse-blocks.js → util.block-offsets-to-selection.js} +21 -1
- package/lib/_chunks-es/util.block-offsets-to-selection.js.map +1 -0
- package/lib/_chunks-es/util.reverse-selection.js +11 -0
- package/lib/_chunks-es/util.reverse-selection.js.map +1 -1
- package/lib/behaviors/index.d.cts +27 -0
- package/lib/behaviors/index.d.ts +27 -0
- package/lib/index.d.cts +1128 -66
- package/lib/index.d.ts +1128 -66
- package/lib/plugins/index.cjs +295 -3
- package/lib/plugins/index.cjs.map +1 -1
- package/lib/plugins/index.d.cts +1142 -67
- package/lib/plugins/index.d.ts +1142 -67
- package/lib/plugins/index.js +300 -4
- package/lib/plugins/index.js.map +1 -1
- package/lib/selectors/index.cjs +51 -1
- package/lib/selectors/index.cjs.map +1 -1
- package/lib/selectors/index.d.cts +67 -0
- package/lib/selectors/index.d.ts +67 -0
- package/lib/selectors/index.js +53 -2
- package/lib/selectors/index.js.map +1 -1
- package/lib/utils/index.cjs +5 -4
- package/lib/utils/index.cjs.map +1 -1
- package/lib/utils/index.d.cts +16 -0
- package/lib/utils/index.d.ts +16 -0
- package/lib/utils/index.js +4 -3
- package/package.json +2 -2
- package/src/behavior-actions/behavior.action.decorator.add.ts +161 -0
- package/src/behavior-actions/behavior.action.delete.text.ts +54 -0
- package/src/behavior-actions/behavior.actions.ts +25 -43
- package/src/behaviors/behavior.markdown-emphasis.ts +395 -0
- package/src/behaviors/behavior.markdown.ts +11 -4
- package/src/behaviors/behavior.types.ts +7 -0
- package/src/editor/editor-machine.ts +80 -85
- package/src/editor/plugins/create-with-event-listeners.ts +51 -0
- package/src/editor/plugins/createWithEditableAPI.ts +18 -2
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +2 -97
- package/src/editor/plugins/createWithUndoRedo.ts +132 -107
- package/src/editor/with-applying-behavior-actions.ts +27 -3
- package/src/plugins/plugin.markdown.tsx +11 -1
- package/src/selectors/index.ts +5 -0
- package/src/selectors/selector.get-anchor-block.ts +22 -0
- package/src/selectors/selector.get-anchor-child.ts +36 -0
- package/src/selectors/selector.get-anchor-span.ts +18 -0
- package/src/selectors/selector.get-anchor-text-block.ts +20 -0
- package/src/selectors/selector.get-trimmed-selection.test.ts +658 -0
- package/src/selectors/selector.get-trimmed-selection.ts +175 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/util.block-offsets-to-selection.ts +36 -0
- package/lib/_chunks-cjs/parse-blocks.cjs.map +0 -1
- package/lib/_chunks-cjs/util.is-empty-text-block.cjs +0 -14
- package/lib/_chunks-cjs/util.is-empty-text-block.cjs.map +0 -1
- package/lib/_chunks-es/parse-blocks.js.map +0 -1
- package/lib/_chunks-es/util.is-empty-text-block.js +0 -15
- package/lib/_chunks-es/util.is-empty-text-block.js.map +0 -1
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import {Transforms} from 'slate'
|
|
2
|
+
import {toSlateRange} from '../internal-utils/ranges'
|
|
3
|
+
import {fromSlateValue} from '../internal-utils/values'
|
|
4
|
+
import {KEY_TO_VALUE_ELEMENT} from '../internal-utils/weakMaps'
|
|
5
|
+
import * as selectors from '../selectors'
|
|
6
|
+
import * as utils from '../utils'
|
|
7
|
+
import type {BehaviorActionImplementation} from './behavior.actions'
|
|
8
|
+
|
|
9
|
+
export const deleteTextActionImplementation: BehaviorActionImplementation<
|
|
10
|
+
'delete.text'
|
|
11
|
+
> = ({context, action}) => {
|
|
12
|
+
const value = fromSlateValue(
|
|
13
|
+
action.editor.children,
|
|
14
|
+
context.schema.block.name,
|
|
15
|
+
KEY_TO_VALUE_ELEMENT.get(action.editor),
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
const selection = utils.blockOffsetsToSelection({
|
|
19
|
+
value,
|
|
20
|
+
offsets: {
|
|
21
|
+
anchor: action.anchor,
|
|
22
|
+
focus: action.focus,
|
|
23
|
+
},
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
if (!selection) {
|
|
27
|
+
throw new Error('Unable to find selection from block offsets')
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const trimmedSelection = selectors.getTrimmedSelection({
|
|
31
|
+
context: {
|
|
32
|
+
converters: [],
|
|
33
|
+
schema: context.schema,
|
|
34
|
+
keyGenerator: context.keyGenerator,
|
|
35
|
+
activeDecorators: [],
|
|
36
|
+
value,
|
|
37
|
+
selection,
|
|
38
|
+
},
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
if (!trimmedSelection) {
|
|
42
|
+
throw new Error('Unable to find trimmed selection')
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const range = toSlateRange(trimmedSelection, action.editor)
|
|
46
|
+
|
|
47
|
+
if (!range) {
|
|
48
|
+
throw new Error('Unable to find Slate range from trimmed selection')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
Transforms.delete(action.editor, {
|
|
52
|
+
at: range,
|
|
53
|
+
})
|
|
54
|
+
}
|
|
@@ -17,21 +17,24 @@ import {
|
|
|
17
17
|
toggleAnnotationActionImplementation,
|
|
18
18
|
} from '../editor/plugins/createWithEditableAPI'
|
|
19
19
|
import {
|
|
20
|
-
addDecoratorActionImplementation,
|
|
21
20
|
removeDecoratorActionImplementation,
|
|
22
21
|
toggleDecoratorActionImplementation,
|
|
23
22
|
} from '../editor/plugins/createWithPortableTextMarkModel'
|
|
23
|
+
import {
|
|
24
|
+
historyRedoActionImplementation,
|
|
25
|
+
historyUndoActionImplementation,
|
|
26
|
+
} from '../editor/plugins/createWithUndoRedo'
|
|
24
27
|
import {toSlatePath} from '../internal-utils/paths'
|
|
25
28
|
import {toSlateRange} from '../internal-utils/ranges'
|
|
26
|
-
import {
|
|
27
|
-
import {KEY_TO_VALUE_ELEMENT} from '../internal-utils/weakMaps'
|
|
29
|
+
import {toSlateValue} from '../internal-utils/values'
|
|
28
30
|
import type {PickFromUnion} from '../type-utils'
|
|
29
|
-
import {blockOffsetToSpanSelectionPoint} from '../utils/util.block-offset'
|
|
30
31
|
import {insertBlock} from './behavior.action-utils.insert-block'
|
|
31
32
|
import {blockSetBehaviorActionImplementation} from './behavior.action.block.set'
|
|
32
33
|
import {blockUnsetBehaviorActionImplementation} from './behavior.action.block.unset'
|
|
33
34
|
import {dataTransferSetActionImplementation} from './behavior.action.data-transfer-set'
|
|
35
|
+
import {decoratorAddActionImplementation} from './behavior.action.decorator.add'
|
|
34
36
|
import {deleteActionImplementation} from './behavior.action.delete'
|
|
37
|
+
import {deleteTextActionImplementation} from './behavior.action.delete.text'
|
|
35
38
|
import {insertBlockObjectActionImplementation} from './behavior.action.insert-block-object'
|
|
36
39
|
import {insertBlocksActionImplementation} from './behavior.action.insert-blocks'
|
|
37
40
|
import {
|
|
@@ -84,7 +87,7 @@ const behaviorActionImplementations: BehaviorActionImplementations = {
|
|
|
84
87
|
ReactEditor.blur(action.editor)
|
|
85
88
|
},
|
|
86
89
|
'data transfer.set': dataTransferSetActionImplementation,
|
|
87
|
-
'decorator.add':
|
|
90
|
+
'decorator.add': decoratorAddActionImplementation,
|
|
88
91
|
'decorator.remove': removeDecoratorActionImplementation,
|
|
89
92
|
'decorator.toggle': toggleDecoratorActionImplementation,
|
|
90
93
|
'focus': ({action}) => {
|
|
@@ -115,44 +118,7 @@ const behaviorActionImplementations: BehaviorActionImplementations = {
|
|
|
115
118
|
at: range,
|
|
116
119
|
})
|
|
117
120
|
},
|
|
118
|
-
'delete.text':
|
|
119
|
-
const value = fromSlateValue(
|
|
120
|
-
action.editor.children,
|
|
121
|
-
context.schema.block.name,
|
|
122
|
-
KEY_TO_VALUE_ELEMENT.get(action.editor),
|
|
123
|
-
)
|
|
124
|
-
|
|
125
|
-
const anchor = blockOffsetToSpanSelectionPoint({
|
|
126
|
-
value,
|
|
127
|
-
blockOffset: action.anchor,
|
|
128
|
-
})
|
|
129
|
-
const focus = blockOffsetToSpanSelectionPoint({
|
|
130
|
-
value,
|
|
131
|
-
blockOffset: action.focus,
|
|
132
|
-
})
|
|
133
|
-
|
|
134
|
-
if (!anchor || !focus) {
|
|
135
|
-
console.error('Unable to find anchor or focus selection point')
|
|
136
|
-
return
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
const range = toSlateRange(
|
|
140
|
-
{
|
|
141
|
-
anchor,
|
|
142
|
-
focus,
|
|
143
|
-
},
|
|
144
|
-
action.editor,
|
|
145
|
-
)
|
|
146
|
-
|
|
147
|
-
if (!range) {
|
|
148
|
-
console.error('Unable to find Slate range from selection points')
|
|
149
|
-
return
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
Transforms.delete(action.editor, {
|
|
153
|
-
at: range,
|
|
154
|
-
})
|
|
155
|
-
},
|
|
121
|
+
'delete.text': deleteTextActionImplementation,
|
|
156
122
|
'deserialization.failure': ({action}) => {
|
|
157
123
|
console.error(
|
|
158
124
|
`Deserialization of ${action.mimeType} failed with reason ${action.reason}`,
|
|
@@ -168,6 +134,8 @@ const behaviorActionImplementations: BehaviorActionImplementations = {
|
|
|
168
134
|
},
|
|
169
135
|
})
|
|
170
136
|
},
|
|
137
|
+
'history.redo': historyRedoActionImplementation,
|
|
138
|
+
'history.undo': historyUndoActionImplementation,
|
|
171
139
|
'insert.block': insertBlockActionImplementation,
|
|
172
140
|
'insert.blocks': insertBlocksActionImplementation,
|
|
173
141
|
'insert.block object': insertBlockObjectActionImplementation,
|
|
@@ -470,6 +438,20 @@ function performDefaultAction({
|
|
|
470
438
|
})
|
|
471
439
|
break
|
|
472
440
|
}
|
|
441
|
+
case 'history.redo': {
|
|
442
|
+
behaviorActionImplementations['history.redo']({
|
|
443
|
+
context,
|
|
444
|
+
action,
|
|
445
|
+
})
|
|
446
|
+
break
|
|
447
|
+
}
|
|
448
|
+
case 'history.undo': {
|
|
449
|
+
behaviorActionImplementations['history.undo']({
|
|
450
|
+
context,
|
|
451
|
+
action,
|
|
452
|
+
})
|
|
453
|
+
break
|
|
454
|
+
}
|
|
473
455
|
case 'insert.block': {
|
|
474
456
|
behaviorActionImplementations['insert.block']({
|
|
475
457
|
context,
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import {useActorRef} from '@xstate/react'
|
|
2
|
+
import {isEqual} from 'lodash'
|
|
3
|
+
import {
|
|
4
|
+
assign,
|
|
5
|
+
fromCallback,
|
|
6
|
+
setup,
|
|
7
|
+
type AnyEventObject,
|
|
8
|
+
type CallbackLogicFunction,
|
|
9
|
+
} from 'xstate'
|
|
10
|
+
import type {Editor} from '../editor/create-editor'
|
|
11
|
+
import {useEditor} from '../editor/editor-provider'
|
|
12
|
+
import type {EditorSchema} from '../selectors'
|
|
13
|
+
import * as selectors from '../selectors'
|
|
14
|
+
import * as utils from '../utils'
|
|
15
|
+
import {defineBehavior} from './behavior.types'
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* @beta
|
|
19
|
+
*/
|
|
20
|
+
export type MarkdownEmphasisBehaviorsConfig = {
|
|
21
|
+
boldDecorator?: ({schema}: {schema: EditorSchema}) => string | undefined
|
|
22
|
+
italicDecorator?: ({schema}: {schema: EditorSchema}) => string | undefined
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* @beta
|
|
27
|
+
*/
|
|
28
|
+
export function useMarkdownEmphasisBehaviors(props: {
|
|
29
|
+
config: MarkdownEmphasisBehaviorsConfig
|
|
30
|
+
}) {
|
|
31
|
+
const editor = useEditor()
|
|
32
|
+
|
|
33
|
+
useActorRef(emphasisMachine, {
|
|
34
|
+
input: {
|
|
35
|
+
editor,
|
|
36
|
+
boldDecorator: props.config.boldDecorator?.({
|
|
37
|
+
schema: editor.getSnapshot().context.schema,
|
|
38
|
+
}),
|
|
39
|
+
italicDecorator: props.config.italicDecorator?.({
|
|
40
|
+
schema: editor.getSnapshot().context.schema,
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
})
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const italicRegex =
|
|
47
|
+
/(?<!\*)\*(?!\s)([^*\n]+?)(?<!\s)\*(?!\*)|(?<!_)_(?!\s)([^_\n]+?)(?<!\s)_(?!_)$/
|
|
48
|
+
const boldRegex =
|
|
49
|
+
/(?<!\*)\*\*(?!\s)([^*\n]+?)(?<!\s)\*\*(?!\*)|(?<!_)__(?!\s)([^_\n]+?)(?<!\s)__(?!_)$/
|
|
50
|
+
|
|
51
|
+
type MarkdownEmphasisEvent =
|
|
52
|
+
| {
|
|
53
|
+
type: 'emphasis.add'
|
|
54
|
+
blockOffset: utils.BlockOffset
|
|
55
|
+
}
|
|
56
|
+
| {
|
|
57
|
+
type: 'selection'
|
|
58
|
+
blockOffsets?: {
|
|
59
|
+
anchor: utils.BlockOffset
|
|
60
|
+
focus: utils.BlockOffset
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
| {
|
|
64
|
+
type: 'delete.backward'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const emphasisListener: CallbackLogicFunction<
|
|
68
|
+
AnyEventObject,
|
|
69
|
+
MarkdownEmphasisEvent,
|
|
70
|
+
{editor: Editor; boldDecorator?: string; italicDecorator?: string}
|
|
71
|
+
> = ({sendBack, input}) => {
|
|
72
|
+
const unregister = input.editor.registerBehavior({
|
|
73
|
+
behavior: defineBehavior({
|
|
74
|
+
on: 'insert.text',
|
|
75
|
+
guard: ({context, event}) => {
|
|
76
|
+
const boldDecorator = input.boldDecorator
|
|
77
|
+
const italicDecorator = input.italicDecorator
|
|
78
|
+
|
|
79
|
+
if (boldDecorator === undefined && italicDecorator === undefined) {
|
|
80
|
+
return false
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (event.text !== '*' && event.text !== '_') {
|
|
84
|
+
return false
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const focusTextBlock = selectors.getFocusTextBlock({context})
|
|
88
|
+
const selectionStartPoint = selectors.getSelectionStartPoint({context})
|
|
89
|
+
const selectionStartOffset = selectionStartPoint
|
|
90
|
+
? utils.spanSelectionPointToBlockOffset({
|
|
91
|
+
value: context.value,
|
|
92
|
+
selectionPoint: selectionStartPoint,
|
|
93
|
+
})
|
|
94
|
+
: undefined
|
|
95
|
+
|
|
96
|
+
if (!focusTextBlock || !selectionStartOffset) {
|
|
97
|
+
return false
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const textBefore = selectors.getBlockTextBefore({context})
|
|
101
|
+
|
|
102
|
+
const textToItalic = `${textBefore}${event.text}`
|
|
103
|
+
.match(italicRegex)
|
|
104
|
+
?.at(0)
|
|
105
|
+
|
|
106
|
+
if (textToItalic !== undefined && italicDecorator !== undefined) {
|
|
107
|
+
const prefixOffsets = {
|
|
108
|
+
anchor: {
|
|
109
|
+
path: focusTextBlock.path,
|
|
110
|
+
offset: textBefore.length - textToItalic.length + 1,
|
|
111
|
+
},
|
|
112
|
+
focus: {
|
|
113
|
+
path: focusTextBlock.path,
|
|
114
|
+
offset: textBefore.length - textToItalic.length + 1 + 1,
|
|
115
|
+
},
|
|
116
|
+
}
|
|
117
|
+
const suffixOffsets = {
|
|
118
|
+
anchor: {
|
|
119
|
+
path: focusTextBlock.path,
|
|
120
|
+
offset: selectionStartOffset.offset,
|
|
121
|
+
},
|
|
122
|
+
focus: {
|
|
123
|
+
path: focusTextBlock.path,
|
|
124
|
+
offset: selectionStartOffset.offset + 1,
|
|
125
|
+
},
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const anchor = utils.blockOffsetToSpanSelectionPoint({
|
|
129
|
+
value: context.value,
|
|
130
|
+
blockOffset: prefixOffsets.focus,
|
|
131
|
+
})
|
|
132
|
+
const focus = utils.blockOffsetToSpanSelectionPoint({
|
|
133
|
+
value: context.value,
|
|
134
|
+
blockOffset: suffixOffsets.anchor,
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
if (!anchor || !focus) {
|
|
138
|
+
return false
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
prefixOffsets,
|
|
143
|
+
suffixOffsets,
|
|
144
|
+
decorator: italicDecorator,
|
|
145
|
+
selection: {anchor, focus},
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const textToBold = `${textBefore}${event.text}`.match(boldRegex)?.at(0)
|
|
150
|
+
|
|
151
|
+
if (textToBold !== undefined && boldDecorator !== undefined) {
|
|
152
|
+
const prefixOffsets = {
|
|
153
|
+
anchor: {
|
|
154
|
+
path: focusTextBlock.path,
|
|
155
|
+
offset: textBefore.length - textToBold.length + 1,
|
|
156
|
+
},
|
|
157
|
+
focus: {
|
|
158
|
+
path: focusTextBlock.path,
|
|
159
|
+
offset: textBefore.length - textToBold.length + 1 + 2,
|
|
160
|
+
},
|
|
161
|
+
}
|
|
162
|
+
const suffixOffsets = {
|
|
163
|
+
anchor: {
|
|
164
|
+
path: focusTextBlock.path,
|
|
165
|
+
offset: selectionStartOffset.offset - 1,
|
|
166
|
+
},
|
|
167
|
+
focus: {
|
|
168
|
+
path: focusTextBlock.path,
|
|
169
|
+
offset: selectionStartOffset.offset + 1,
|
|
170
|
+
},
|
|
171
|
+
}
|
|
172
|
+
const anchor = utils.blockOffsetToSpanSelectionPoint({
|
|
173
|
+
value: context.value,
|
|
174
|
+
blockOffset: prefixOffsets.focus,
|
|
175
|
+
})
|
|
176
|
+
const focus = utils.blockOffsetToSpanSelectionPoint({
|
|
177
|
+
value: context.value,
|
|
178
|
+
blockOffset: suffixOffsets.anchor,
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
if (!anchor || !focus) {
|
|
182
|
+
return false
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
prefixOffsets,
|
|
187
|
+
suffixOffsets,
|
|
188
|
+
decorator: boldDecorator,
|
|
189
|
+
selection: {anchor, focus},
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return false
|
|
194
|
+
},
|
|
195
|
+
actions: [
|
|
196
|
+
({event}) => [event],
|
|
197
|
+
(_, {prefixOffsets, suffixOffsets, decorator, selection}) => [
|
|
198
|
+
{
|
|
199
|
+
type: 'decorator.add',
|
|
200
|
+
decorator,
|
|
201
|
+
selection,
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
type: 'delete.text',
|
|
205
|
+
...suffixOffsets,
|
|
206
|
+
},
|
|
207
|
+
{
|
|
208
|
+
type: 'delete.text',
|
|
209
|
+
...prefixOffsets,
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
type: 'effect',
|
|
213
|
+
effect: () => {
|
|
214
|
+
sendBack({
|
|
215
|
+
type: 'emphasis.add',
|
|
216
|
+
blockOffset: {
|
|
217
|
+
...suffixOffsets.anchor,
|
|
218
|
+
offset:
|
|
219
|
+
suffixOffsets.anchor.offset -
|
|
220
|
+
(prefixOffsets.focus.offset - prefixOffsets.anchor.offset),
|
|
221
|
+
},
|
|
222
|
+
})
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
],
|
|
226
|
+
],
|
|
227
|
+
}),
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
return unregister
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const selectionListenerCallback: CallbackLogicFunction<
|
|
234
|
+
AnyEventObject,
|
|
235
|
+
MarkdownEmphasisEvent,
|
|
236
|
+
{editor: Editor}
|
|
237
|
+
> = ({sendBack, input}) => {
|
|
238
|
+
const unregister = input.editor.registerBehavior({
|
|
239
|
+
behavior: defineBehavior({
|
|
240
|
+
on: 'select',
|
|
241
|
+
guard: ({context, event}) => {
|
|
242
|
+
if (!event.selection) {
|
|
243
|
+
return {blockOffsets: undefined}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const anchor = utils.spanSelectionPointToBlockOffset({
|
|
247
|
+
value: context.value,
|
|
248
|
+
selectionPoint: event.selection.anchor,
|
|
249
|
+
})
|
|
250
|
+
const focus = utils.spanSelectionPointToBlockOffset({
|
|
251
|
+
value: context.value,
|
|
252
|
+
selectionPoint: event.selection.focus,
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
if (!anchor || !focus) {
|
|
256
|
+
return {blockOffsets: undefined}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return {
|
|
260
|
+
blockOffsets: {
|
|
261
|
+
anchor,
|
|
262
|
+
focus,
|
|
263
|
+
},
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
actions: [
|
|
267
|
+
(_, {blockOffsets}) => [
|
|
268
|
+
{
|
|
269
|
+
type: 'effect',
|
|
270
|
+
effect: () => {
|
|
271
|
+
sendBack({type: 'selection', blockOffsets})
|
|
272
|
+
},
|
|
273
|
+
},
|
|
274
|
+
],
|
|
275
|
+
],
|
|
276
|
+
}),
|
|
277
|
+
})
|
|
278
|
+
|
|
279
|
+
return unregister
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
const deleteBackwardListenerCallback: CallbackLogicFunction<
|
|
283
|
+
AnyEventObject,
|
|
284
|
+
MarkdownEmphasisEvent,
|
|
285
|
+
{editor: Editor}
|
|
286
|
+
> = ({sendBack, input}) => {
|
|
287
|
+
const unregister = input.editor.registerBehavior({
|
|
288
|
+
behavior: defineBehavior({
|
|
289
|
+
on: 'delete.backward',
|
|
290
|
+
actions: [
|
|
291
|
+
() => [
|
|
292
|
+
{
|
|
293
|
+
type: 'history.undo',
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
type: 'effect',
|
|
297
|
+
effect: () => {
|
|
298
|
+
sendBack({type: 'delete.backward'})
|
|
299
|
+
},
|
|
300
|
+
},
|
|
301
|
+
],
|
|
302
|
+
],
|
|
303
|
+
}),
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
return unregister
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
const emphasisMachine = setup({
|
|
310
|
+
types: {
|
|
311
|
+
context: {} as {
|
|
312
|
+
boldDecorator?: string
|
|
313
|
+
italicDecorator?: string
|
|
314
|
+
offsetAfterEmphasis?: utils.BlockOffset
|
|
315
|
+
editor: Editor
|
|
316
|
+
},
|
|
317
|
+
input: {} as {
|
|
318
|
+
boldDecorator?: string
|
|
319
|
+
italicDecorator?: string
|
|
320
|
+
editor: Editor
|
|
321
|
+
},
|
|
322
|
+
events: {} as MarkdownEmphasisEvent,
|
|
323
|
+
},
|
|
324
|
+
actors: {
|
|
325
|
+
'emphasis listener': fromCallback(emphasisListener),
|
|
326
|
+
'delete.backward listener': fromCallback(deleteBackwardListenerCallback),
|
|
327
|
+
'selection listener': fromCallback(selectionListenerCallback),
|
|
328
|
+
},
|
|
329
|
+
}).createMachine({
|
|
330
|
+
id: 'emphasis',
|
|
331
|
+
context: ({input}) => ({
|
|
332
|
+
boldDecorator: input.boldDecorator,
|
|
333
|
+
italicDecorator: input.italicDecorator,
|
|
334
|
+
editor: input.editor,
|
|
335
|
+
}),
|
|
336
|
+
initial: 'idle',
|
|
337
|
+
states: {
|
|
338
|
+
'idle': {
|
|
339
|
+
invoke: [
|
|
340
|
+
{
|
|
341
|
+
src: 'emphasis listener',
|
|
342
|
+
input: ({context}) => ({
|
|
343
|
+
editor: context.editor,
|
|
344
|
+
boldDecorator: context.boldDecorator,
|
|
345
|
+
italicDecorator: context.italicDecorator,
|
|
346
|
+
}),
|
|
347
|
+
},
|
|
348
|
+
],
|
|
349
|
+
on: {
|
|
350
|
+
'emphasis.add': {
|
|
351
|
+
target: 'emphasis added',
|
|
352
|
+
actions: assign({
|
|
353
|
+
offsetAfterEmphasis: ({event}) => event.blockOffset,
|
|
354
|
+
}),
|
|
355
|
+
},
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
'emphasis added': {
|
|
359
|
+
exit: [
|
|
360
|
+
assign({
|
|
361
|
+
offsetAfterEmphasis: undefined,
|
|
362
|
+
}),
|
|
363
|
+
],
|
|
364
|
+
invoke: [
|
|
365
|
+
{
|
|
366
|
+
src: 'selection listener',
|
|
367
|
+
input: ({context}) => ({editor: context.editor}),
|
|
368
|
+
},
|
|
369
|
+
{
|
|
370
|
+
src: 'delete.backward listener',
|
|
371
|
+
input: ({context}) => ({editor: context.editor}),
|
|
372
|
+
},
|
|
373
|
+
],
|
|
374
|
+
on: {
|
|
375
|
+
'selection': {
|
|
376
|
+
target: 'idle',
|
|
377
|
+
guard: ({context, event}) => {
|
|
378
|
+
const selectionChanged = !isEqual(
|
|
379
|
+
{
|
|
380
|
+
anchor: context.offsetAfterEmphasis,
|
|
381
|
+
focus: context.offsetAfterEmphasis,
|
|
382
|
+
},
|
|
383
|
+
event.blockOffsets,
|
|
384
|
+
)
|
|
385
|
+
|
|
386
|
+
return selectionChanged
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
'delete.backward': {
|
|
390
|
+
target: 'idle',
|
|
391
|
+
},
|
|
392
|
+
},
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
})
|
|
@@ -86,6 +86,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
|
|
|
86
86
|
return false
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
const previousInlineObject = selectors.getPreviousInlineObject({context})
|
|
89
90
|
const blockOffset = spanSelectionPointToBlockOffset({
|
|
90
91
|
value: context.value,
|
|
91
92
|
selectionPoint: {
|
|
@@ -98,7 +99,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
|
|
|
98
99
|
},
|
|
99
100
|
})
|
|
100
101
|
|
|
101
|
-
if (!blockOffset) {
|
|
102
|
+
if (previousInlineObject || !blockOffset) {
|
|
102
103
|
return false
|
|
103
104
|
}
|
|
104
105
|
|
|
@@ -173,6 +174,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
|
|
|
173
174
|
return false
|
|
174
175
|
}
|
|
175
176
|
|
|
177
|
+
const previousInlineObject = selectors.getPreviousInlineObject({context})
|
|
176
178
|
const textBefore = getBlockTextBefore({context})
|
|
177
179
|
const hrBlockOffsets = {
|
|
178
180
|
anchor: {
|
|
@@ -185,7 +187,10 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
|
|
|
185
187
|
},
|
|
186
188
|
}
|
|
187
189
|
|
|
188
|
-
if (
|
|
190
|
+
if (
|
|
191
|
+
!previousInlineObject &&
|
|
192
|
+
textBefore === `${hrCharacter}${hrCharacter}`
|
|
193
|
+
) {
|
|
189
194
|
return {hrObject, focusBlock, hrCharacter, hrBlockOffsets}
|
|
190
195
|
}
|
|
191
196
|
|
|
@@ -290,6 +295,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
|
|
|
290
295
|
return false
|
|
291
296
|
}
|
|
292
297
|
|
|
298
|
+
const previousInlineObject = selectors.getPreviousInlineObject({context})
|
|
293
299
|
const blockText = getTextBlockText(focusTextBlock.node)
|
|
294
300
|
const markdownHeadingSearch = /^#+/.exec(blockText)
|
|
295
301
|
const level = markdownHeadingSearch
|
|
@@ -297,7 +303,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
|
|
|
297
303
|
: undefined
|
|
298
304
|
const caretAtTheEndOfHeading = blockOffset.offset === level
|
|
299
305
|
|
|
300
|
-
if (!caretAtTheEndOfHeading) {
|
|
306
|
+
if (previousInlineObject || !caretAtTheEndOfHeading) {
|
|
301
307
|
return false
|
|
302
308
|
}
|
|
303
309
|
|
|
@@ -397,6 +403,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
|
|
|
397
403
|
return false
|
|
398
404
|
}
|
|
399
405
|
|
|
406
|
+
const previousInlineObject = selectors.getPreviousInlineObject({context})
|
|
400
407
|
const blockOffset = spanSelectionPointToBlockOffset({
|
|
401
408
|
value: context.value,
|
|
402
409
|
selectionPoint: {
|
|
@@ -409,7 +416,7 @@ export function createMarkdownBehaviors(config: MarkdownBehaviorsConfig) {
|
|
|
409
416
|
},
|
|
410
417
|
})
|
|
411
418
|
|
|
412
|
-
if (!blockOffset) {
|
|
419
|
+
if (previousInlineObject || !blockOffset) {
|
|
413
420
|
return false
|
|
414
421
|
}
|
|
415
422
|
|
|
@@ -57,6 +57,7 @@ export type SyntheticBehaviorEvent =
|
|
|
57
57
|
| {
|
|
58
58
|
type: 'decorator.add'
|
|
59
59
|
decorator: string
|
|
60
|
+
selection?: NonNullable<EditorSelection>
|
|
60
61
|
}
|
|
61
62
|
| {
|
|
62
63
|
type: 'decorator.remove'
|
|
@@ -90,6 +91,12 @@ export type SyntheticBehaviorEvent =
|
|
|
90
91
|
| {
|
|
91
92
|
type: 'focus'
|
|
92
93
|
}
|
|
94
|
+
| {
|
|
95
|
+
type: 'history.redo'
|
|
96
|
+
}
|
|
97
|
+
| {
|
|
98
|
+
type: 'history.undo'
|
|
99
|
+
}
|
|
93
100
|
| {
|
|
94
101
|
type: 'insert.blocks'
|
|
95
102
|
blocks: Array<PortableTextBlock>
|