@portabletext/editor 1.34.0 → 1.35.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 +57 -118
- package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
- package/lib/_chunks-cjs/behavior.markdown.cjs +27 -67
- package/lib/_chunks-cjs/behavior.markdown.cjs.map +1 -1
- package/lib/_chunks-cjs/plugin.event-listener.cjs +53 -71
- package/lib/_chunks-cjs/plugin.event-listener.cjs.map +1 -1
- package/lib/_chunks-cjs/selector.get-text-before.cjs +5 -7
- package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
- package/lib/_chunks-cjs/selector.is-active-style.cjs +22 -36
- package/lib/_chunks-cjs/selector.is-active-style.cjs.map +1 -1
- package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs +68 -153
- package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs.map +1 -1
- package/lib/_chunks-cjs/util.block-offsets-to-selection.cjs.map +1 -1
- package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
- package/lib/_chunks-es/behavior.core.js +57 -118
- package/lib/_chunks-es/behavior.core.js.map +1 -1
- package/lib/_chunks-es/behavior.markdown.js +27 -67
- package/lib/_chunks-es/behavior.markdown.js.map +1 -1
- package/lib/_chunks-es/plugin.event-listener.js +53 -71
- package/lib/_chunks-es/plugin.event-listener.js.map +1 -1
- package/lib/_chunks-es/selector.get-text-before.js +5 -7
- package/lib/_chunks-es/selector.get-text-before.js.map +1 -1
- package/lib/_chunks-es/selector.is-active-style.js +22 -36
- package/lib/_chunks-es/selector.is-active-style.js.map +1 -1
- package/lib/_chunks-es/selector.is-at-the-start-of-block.js +68 -153
- package/lib/_chunks-es/selector.is-at-the-start-of-block.js.map +1 -1
- package/lib/_chunks-es/util.block-offsets-to-selection.js.map +1 -1
- package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
- package/lib/behaviors/index.cjs +18 -48
- package/lib/behaviors/index.cjs.map +1 -1
- package/lib/behaviors/index.d.cts +28 -16
- package/lib/behaviors/index.d.ts +28 -16
- package/lib/behaviors/index.js +18 -48
- package/lib/behaviors/index.js.map +1 -1
- package/lib/index.d.cts +132 -71
- package/lib/index.d.ts +132 -71
- package/lib/plugins/index.cjs +182 -186
- package/lib/plugins/index.cjs.map +1 -1
- package/lib/plugins/index.d.cts +147 -82
- package/lib/plugins/index.d.ts +147 -82
- package/lib/plugins/index.js +182 -186
- package/lib/plugins/index.js.map +1 -1
- package/lib/selectors/index.cjs +22 -50
- package/lib/selectors/index.cjs.map +1 -1
- package/lib/selectors/index.d.cts +9 -200
- package/lib/selectors/index.d.ts +9 -200
- package/lib/selectors/index.js +22 -50
- package/lib/selectors/index.js.map +1 -1
- package/lib/utils/index.cjs.map +1 -1
- package/lib/utils/index.d.cts +15 -7
- package/lib/utils/index.d.ts +15 -7
- package/lib/utils/index.js.map +1 -1
- package/package.json +6 -6
- package/src/behaviors/behavior.code-editor.ts +6 -6
- package/src/behaviors/behavior.core.annotations.ts +5 -4
- package/src/behaviors/behavior.core.block-objects.ts +17 -17
- package/src/behaviors/behavior.core.decorators.ts +12 -8
- package/src/behaviors/behavior.core.insert-break.ts +27 -29
- package/src/behaviors/behavior.core.lists.ts +19 -19
- package/src/behaviors/behavior.decorator-pair.ts +200 -0
- package/src/behaviors/behavior.default.ts +35 -30
- package/src/behaviors/behavior.emoji-picker.ts +12 -12
- package/src/behaviors/behavior.links.ts +7 -7
- package/src/behaviors/behavior.markdown.ts +41 -42
- package/src/behaviors/behavior.types.ts +15 -18
- package/src/behaviors/index.ts +0 -1
- package/src/converters/converter.json.ts +6 -6
- package/src/converters/converter.portable-text.deserialize.test.ts +28 -26
- package/src/converters/converter.portable-text.ts +6 -6
- package/src/converters/converter.text-html.deserialize.test.ts +17 -15
- package/src/converters/converter.text-html.serialize.test.ts +57 -53
- package/src/converters/converter.text-html.ts +14 -10
- package/src/converters/converter.text-plain.test.ts +17 -15
- package/src/converters/converter.text-plain.ts +15 -11
- package/src/converters/converter.types.ts +8 -7
- package/src/editor/editor-machine.ts +6 -1
- package/src/editor/plugins/create-with-event-listeners.ts +0 -5
- package/src/index.ts +3 -3
- package/src/internal-utils/get-text-to-emphasize.ts +29 -7
- package/src/plugins/plugin.decorator-shortcut.ts +235 -0
- package/src/plugins/plugin.markdown.tsx +56 -8
- package/src/plugins/plugin.one-line.tsx +17 -17
- package/src/selectors/selector.get-active-list-item.ts +4 -4
- package/src/selectors/selector.get-active-style.ts +6 -6
- package/src/selectors/selector.get-anchor-block.ts +5 -5
- package/src/selectors/selector.get-anchor-child.ts +5 -5
- package/src/selectors/selector.get-anchor-span.ts +2 -2
- package/src/selectors/selector.get-anchor-text-block.ts +2 -2
- package/src/selectors/selector.get-block-offsets.ts +8 -7
- package/src/selectors/selector.get-caret-word-selection.ts +19 -16
- package/src/selectors/selector.get-next-inline-object.ts +4 -4
- package/src/selectors/selector.get-previous-inline-object.ts +4 -4
- package/src/selectors/selector.get-selected-slice.ts +7 -4
- package/src/selectors/selector.get-selected-spans.ts +9 -9
- package/src/selectors/selector.get-selection-end-point.ts +5 -5
- package/src/selectors/selector.get-selection-start-point.ts +5 -5
- package/src/selectors/selector.get-selection-text.ts +2 -2
- package/src/selectors/selector.get-selection.ts +2 -2
- package/src/selectors/selector.get-text-before.ts +8 -8
- package/src/selectors/selector.get-trimmed-selection.ts +15 -13
- package/src/selectors/selector.get-value.ts +4 -4
- package/src/selectors/selector.is-at-the-end-of-block.ts +6 -3
- package/src/selectors/selector.is-at-the-start-of-block.ts +3 -3
- package/src/selectors/selector.is-overlapping-selection.ts +8 -6
- package/src/selectors/selector.is-selection-collapsed.ts +6 -5
- package/src/selectors/selector.is-selection-expanded.ts +2 -2
- package/src/selectors/selectors.ts +59 -59
- package/src/types/block-offset.ts +9 -0
- package/src/utils/index.ts +0 -1
- package/src/utils/util.block-offset.ts +1 -1
- package/src/utils/util.block-offsets-to-selection.ts +1 -1
- package/src/utils/util.child-selection-point-to-block-offset.ts +1 -1
- package/src/behaviors/behavior.markdown-emphasis.ts +0 -437
|
@@ -0,0 +1,235 @@
|
|
|
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 {createDecoratorPairBehavior} from '../behaviors/behavior.decorator-pair'
|
|
11
|
+
import {defineBehavior} from '../behaviors/behavior.types'
|
|
12
|
+
import type {Editor} from '../editor/create-editor'
|
|
13
|
+
import {useEditor} from '../editor/editor-provider'
|
|
14
|
+
import type {EditorSchema} from '../selectors'
|
|
15
|
+
import type {BlockOffset} from '../types/block-offset'
|
|
16
|
+
import * as utils from '../utils'
|
|
17
|
+
|
|
18
|
+
export function DecoratorShortcutPlugin(config: {
|
|
19
|
+
decorator: ({schema}: {schema: EditorSchema}) => string | undefined
|
|
20
|
+
pair: {char: string; amount: number}
|
|
21
|
+
}) {
|
|
22
|
+
const editor = useEditor()
|
|
23
|
+
|
|
24
|
+
useActorRef(decoratorPairMachine, {
|
|
25
|
+
input: {
|
|
26
|
+
editor,
|
|
27
|
+
decorator: config.decorator,
|
|
28
|
+
pair: config.pair,
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
type MarkdownEmphasisEvent =
|
|
36
|
+
| {
|
|
37
|
+
type: 'emphasis.add'
|
|
38
|
+
blockOffset: BlockOffset
|
|
39
|
+
}
|
|
40
|
+
| {
|
|
41
|
+
type: 'selection'
|
|
42
|
+
blockOffsets?: {
|
|
43
|
+
anchor: BlockOffset
|
|
44
|
+
focus: BlockOffset
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
| {
|
|
48
|
+
type: 'delete.backward'
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const emphasisListener: CallbackLogicFunction<
|
|
52
|
+
AnyEventObject,
|
|
53
|
+
MarkdownEmphasisEvent,
|
|
54
|
+
{
|
|
55
|
+
decorator: ({schema}: {schema: EditorSchema}) => string | undefined
|
|
56
|
+
editor: Editor
|
|
57
|
+
pair: {char: string; amount: number}
|
|
58
|
+
}
|
|
59
|
+
> = ({sendBack, input}) => {
|
|
60
|
+
const unregister = input.editor.registerBehavior({
|
|
61
|
+
behavior: createDecoratorPairBehavior({
|
|
62
|
+
decorator: input.decorator,
|
|
63
|
+
pair: input.pair,
|
|
64
|
+
onDecorate: (offset) => {
|
|
65
|
+
sendBack({type: 'emphasis.add', blockOffset: offset})
|
|
66
|
+
},
|
|
67
|
+
}),
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
return unregister
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const selectionListenerCallback: CallbackLogicFunction<
|
|
74
|
+
AnyEventObject,
|
|
75
|
+
MarkdownEmphasisEvent,
|
|
76
|
+
{editor: Editor}
|
|
77
|
+
> = ({sendBack, input}) => {
|
|
78
|
+
const unregister = input.editor.registerBehavior({
|
|
79
|
+
behavior: defineBehavior({
|
|
80
|
+
on: 'select',
|
|
81
|
+
guard: ({snapshot, event}) => {
|
|
82
|
+
if (!event.selection) {
|
|
83
|
+
return {blockOffsets: undefined}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const anchor = utils.spanSelectionPointToBlockOffset({
|
|
87
|
+
value: snapshot.context.value,
|
|
88
|
+
selectionPoint: event.selection.anchor,
|
|
89
|
+
})
|
|
90
|
+
const focus = utils.spanSelectionPointToBlockOffset({
|
|
91
|
+
value: snapshot.context.value,
|
|
92
|
+
selectionPoint: event.selection.focus,
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
if (!anchor || !focus) {
|
|
96
|
+
return {blockOffsets: undefined}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
blockOffsets: {
|
|
101
|
+
anchor,
|
|
102
|
+
focus,
|
|
103
|
+
},
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
actions: [
|
|
107
|
+
(_, {blockOffsets}) => [
|
|
108
|
+
{
|
|
109
|
+
type: 'effect',
|
|
110
|
+
effect: () => {
|
|
111
|
+
sendBack({type: 'selection', blockOffsets})
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
],
|
|
116
|
+
}),
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
return unregister
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const deleteBackwardListenerCallback: CallbackLogicFunction<
|
|
123
|
+
AnyEventObject,
|
|
124
|
+
MarkdownEmphasisEvent,
|
|
125
|
+
{editor: Editor}
|
|
126
|
+
> = ({sendBack, input}) => {
|
|
127
|
+
const unregister = input.editor.registerBehavior({
|
|
128
|
+
behavior: defineBehavior({
|
|
129
|
+
on: 'delete.backward',
|
|
130
|
+
actions: [
|
|
131
|
+
() => [
|
|
132
|
+
{
|
|
133
|
+
type: 'history.undo',
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
type: 'effect',
|
|
137
|
+
effect: () => {
|
|
138
|
+
sendBack({type: 'delete.backward'})
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
],
|
|
143
|
+
}),
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
return unregister
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const decoratorPairMachine = setup({
|
|
150
|
+
types: {
|
|
151
|
+
context: {} as {
|
|
152
|
+
decorator: ({schema}: {schema: EditorSchema}) => string | undefined
|
|
153
|
+
editor: Editor
|
|
154
|
+
offsetAfterEmphasis?: BlockOffset
|
|
155
|
+
pair: {char: string; amount: number}
|
|
156
|
+
},
|
|
157
|
+
input: {} as {
|
|
158
|
+
decorator: ({schema}: {schema: EditorSchema}) => string | undefined
|
|
159
|
+
editor: Editor
|
|
160
|
+
pair: {char: string; amount: number}
|
|
161
|
+
},
|
|
162
|
+
events: {} as MarkdownEmphasisEvent,
|
|
163
|
+
},
|
|
164
|
+
actors: {
|
|
165
|
+
'emphasis listener': fromCallback(emphasisListener),
|
|
166
|
+
'delete.backward listener': fromCallback(deleteBackwardListenerCallback),
|
|
167
|
+
'selection listener': fromCallback(selectionListenerCallback),
|
|
168
|
+
},
|
|
169
|
+
}).createMachine({
|
|
170
|
+
id: 'decorator pair',
|
|
171
|
+
context: ({input}) => ({
|
|
172
|
+
decorator: input.decorator,
|
|
173
|
+
editor: input.editor,
|
|
174
|
+
pair: input.pair,
|
|
175
|
+
}),
|
|
176
|
+
initial: 'idle',
|
|
177
|
+
states: {
|
|
178
|
+
'idle': {
|
|
179
|
+
invoke: [
|
|
180
|
+
{
|
|
181
|
+
src: 'emphasis listener',
|
|
182
|
+
input: ({context}) => ({
|
|
183
|
+
decorator: context.decorator,
|
|
184
|
+
editor: context.editor,
|
|
185
|
+
pair: context.pair,
|
|
186
|
+
}),
|
|
187
|
+
},
|
|
188
|
+
],
|
|
189
|
+
on: {
|
|
190
|
+
'emphasis.add': {
|
|
191
|
+
target: 'emphasis added',
|
|
192
|
+
actions: assign({
|
|
193
|
+
offsetAfterEmphasis: ({event}) => event.blockOffset,
|
|
194
|
+
}),
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
'emphasis added': {
|
|
199
|
+
exit: [
|
|
200
|
+
assign({
|
|
201
|
+
offsetAfterEmphasis: undefined,
|
|
202
|
+
}),
|
|
203
|
+
],
|
|
204
|
+
invoke: [
|
|
205
|
+
{
|
|
206
|
+
src: 'selection listener',
|
|
207
|
+
input: ({context}) => ({editor: context.editor}),
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
src: 'delete.backward listener',
|
|
211
|
+
input: ({context}) => ({editor: context.editor}),
|
|
212
|
+
},
|
|
213
|
+
],
|
|
214
|
+
on: {
|
|
215
|
+
'selection': {
|
|
216
|
+
target: 'idle',
|
|
217
|
+
guard: ({context, event}) => {
|
|
218
|
+
const selectionChanged = !isEqual(
|
|
219
|
+
{
|
|
220
|
+
anchor: context.offsetAfterEmphasis,
|
|
221
|
+
focus: context.offsetAfterEmphasis,
|
|
222
|
+
},
|
|
223
|
+
event.blockOffsets,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
return selectionChanged
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
'delete.backward': {
|
|
230
|
+
target: 'idle',
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
},
|
|
235
|
+
})
|
|
@@ -3,17 +3,23 @@ import {
|
|
|
3
3
|
createMarkdownBehaviors,
|
|
4
4
|
type MarkdownBehaviorsConfig,
|
|
5
5
|
} from '../behaviors/behavior.markdown'
|
|
6
|
-
import {
|
|
7
|
-
useMarkdownEmphasisBehaviors,
|
|
8
|
-
type MarkdownEmphasisBehaviorsConfig,
|
|
9
|
-
} from '../behaviors/behavior.markdown-emphasis'
|
|
6
|
+
import type {EditorSchema} from '../editor/define-schema'
|
|
10
7
|
import {useEditor} from '../editor/editor-provider'
|
|
8
|
+
import {DecoratorShortcutPlugin} from './plugin.decorator-shortcut'
|
|
11
9
|
|
|
12
10
|
/**
|
|
13
11
|
* @beta
|
|
14
12
|
*/
|
|
15
|
-
export type MarkdownPluginConfig = MarkdownBehaviorsConfig &
|
|
16
|
-
|
|
13
|
+
export type MarkdownPluginConfig = MarkdownBehaviorsConfig & {
|
|
14
|
+
boldDecorator?: ({schema}: {schema: EditorSchema}) => string | undefined
|
|
15
|
+
codeDecorator?: ({schema}: {schema: EditorSchema}) => string | undefined
|
|
16
|
+
italicDecorator?: ({schema}: {schema: EditorSchema}) => string | undefined
|
|
17
|
+
strikeThroughDecorator?: ({
|
|
18
|
+
schema,
|
|
19
|
+
}: {
|
|
20
|
+
schema: EditorSchema
|
|
21
|
+
}) => string | undefined
|
|
22
|
+
}
|
|
17
23
|
|
|
18
24
|
/**
|
|
19
25
|
* @beta
|
|
@@ -32,8 +38,12 @@ export type MarkdownPluginConfig = MarkdownBehaviorsConfig &
|
|
|
32
38
|
* config={{
|
|
33
39
|
* boldDecorator: ({schema}) =>
|
|
34
40
|
* schema.decorators.find((decorator) => decorator.value === 'strong')?.value,
|
|
41
|
+
* codeDecorator: ({schema}) =>
|
|
42
|
+
* schema.decorators.find((decorator) => decorator.value === 'code')?.value,
|
|
35
43
|
* italicDecorator: ({schema}) =>
|
|
36
44
|
* schema.decorators.find((decorator) => decorator.value === 'em')?.value,
|
|
45
|
+
* strikeThroughDecorator: ({schema}) =>
|
|
46
|
+
* schema.decorators.find((decorator) => decorator.value === 'strike-through')?.value,
|
|
37
47
|
* horizontalRuleObject: ({schema}) => {
|
|
38
48
|
* const name = schema.blockObjects.find(
|
|
39
49
|
* (object) => object.name === 'break',
|
|
@@ -60,7 +70,6 @@ export type MarkdownPluginConfig = MarkdownBehaviorsConfig &
|
|
|
60
70
|
*/
|
|
61
71
|
export function MarkdownPlugin(props: {config: MarkdownPluginConfig}) {
|
|
62
72
|
const editor = useEditor()
|
|
63
|
-
useMarkdownEmphasisBehaviors({config: props.config})
|
|
64
73
|
|
|
65
74
|
useEffect(() => {
|
|
66
75
|
const behaviors = createMarkdownBehaviors(props.config)
|
|
@@ -76,5 +85,44 @@ export function MarkdownPlugin(props: {config: MarkdownPluginConfig}) {
|
|
|
76
85
|
}
|
|
77
86
|
}, [editor, props.config])
|
|
78
87
|
|
|
79
|
-
return
|
|
88
|
+
return (
|
|
89
|
+
<>
|
|
90
|
+
{props.config.boldDecorator ? (
|
|
91
|
+
<>
|
|
92
|
+
<DecoratorShortcutPlugin
|
|
93
|
+
decorator={props.config.boldDecorator}
|
|
94
|
+
pair={{char: '*', amount: 2}}
|
|
95
|
+
/>
|
|
96
|
+
<DecoratorShortcutPlugin
|
|
97
|
+
decorator={props.config.boldDecorator}
|
|
98
|
+
pair={{char: '_', amount: 2}}
|
|
99
|
+
/>
|
|
100
|
+
</>
|
|
101
|
+
) : null}
|
|
102
|
+
{props.config.codeDecorator ? (
|
|
103
|
+
<DecoratorShortcutPlugin
|
|
104
|
+
decorator={props.config.codeDecorator}
|
|
105
|
+
pair={{char: '`', amount: 1}}
|
|
106
|
+
/>
|
|
107
|
+
) : null}
|
|
108
|
+
{props.config.italicDecorator ? (
|
|
109
|
+
<>
|
|
110
|
+
<DecoratorShortcutPlugin
|
|
111
|
+
decorator={props.config.italicDecorator}
|
|
112
|
+
pair={{char: '*', amount: 1}}
|
|
113
|
+
/>
|
|
114
|
+
<DecoratorShortcutPlugin
|
|
115
|
+
decorator={props.config.italicDecorator}
|
|
116
|
+
pair={{char: '_', amount: 1}}
|
|
117
|
+
/>
|
|
118
|
+
</>
|
|
119
|
+
) : null}
|
|
120
|
+
{props.config.strikeThroughDecorator ? (
|
|
121
|
+
<DecoratorShortcutPlugin
|
|
122
|
+
decorator={props.config.strikeThroughDecorator}
|
|
123
|
+
pair={{char: '~', amount: 2}}
|
|
124
|
+
/>
|
|
125
|
+
) : null}
|
|
126
|
+
</>
|
|
127
|
+
)
|
|
80
128
|
}
|
|
@@ -10,9 +10,9 @@ const oneLineBehaviors = [
|
|
|
10
10
|
*/
|
|
11
11
|
defineBehavior({
|
|
12
12
|
on: 'insert.break',
|
|
13
|
-
guard: (
|
|
14
|
-
context.selection && selectors.isSelectionExpanded(
|
|
15
|
-
? {selection: context.selection}
|
|
13
|
+
guard: (snapshot) =>
|
|
14
|
+
snapshot.context.selection && selectors.isSelectionExpanded(snapshot)
|
|
15
|
+
? {selection: snapshot.context.selection}
|
|
16
16
|
: false,
|
|
17
17
|
actions: [(_, {selection}) => [{type: 'delete', selection}]],
|
|
18
18
|
}),
|
|
@@ -40,14 +40,14 @@ const oneLineBehaviors = [
|
|
|
40
40
|
*/
|
|
41
41
|
defineBehavior({
|
|
42
42
|
on: 'insert.block',
|
|
43
|
-
guard: ({
|
|
44
|
-
const focusTextBlock = selectors.getFocusTextBlock(
|
|
45
|
-
const selectionStartPoint = selectors.getSelectionStartPoint(
|
|
46
|
-
const selectionEndPoint = selectors.getSelectionEndPoint(
|
|
43
|
+
guard: ({snapshot, event}) => {
|
|
44
|
+
const focusTextBlock = selectors.getFocusTextBlock(snapshot)
|
|
45
|
+
const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)
|
|
46
|
+
const selectionEndPoint = selectors.getSelectionEndPoint(snapshot)
|
|
47
47
|
|
|
48
48
|
if (
|
|
49
49
|
!focusTextBlock ||
|
|
50
|
-
!utils.isTextBlock(context, event.block) ||
|
|
50
|
+
!utils.isTextBlock(snapshot.context, event.block) ||
|
|
51
51
|
!selectionStartPoint ||
|
|
52
52
|
!selectionEndPoint
|
|
53
53
|
) {
|
|
@@ -90,14 +90,14 @@ const oneLineBehaviors = [
|
|
|
90
90
|
*/
|
|
91
91
|
defineBehavior({
|
|
92
92
|
on: 'insert.block',
|
|
93
|
-
guard: ({
|
|
94
|
-
const focusTextBlock = selectors.getFocusTextBlock(
|
|
95
|
-
const selectionStartPoint = selectors.getSelectionStartPoint(
|
|
96
|
-
const selectionEndPoint = selectors.getSelectionEndPoint(
|
|
93
|
+
guard: ({snapshot, event}) => {
|
|
94
|
+
const focusTextBlock = selectors.getFocusTextBlock(snapshot)
|
|
95
|
+
const selectionStartPoint = selectors.getSelectionStartPoint(snapshot)
|
|
96
|
+
const selectionEndPoint = selectors.getSelectionEndPoint(snapshot)
|
|
97
97
|
|
|
98
98
|
if (
|
|
99
99
|
!focusTextBlock ||
|
|
100
|
-
!utils.isTextBlock(context, event.block) ||
|
|
100
|
+
!utils.isTextBlock(snapshot.context, event.block) ||
|
|
101
101
|
!selectionStartPoint ||
|
|
102
102
|
!selectionEndPoint
|
|
103
103
|
) {
|
|
@@ -105,12 +105,12 @@ const oneLineBehaviors = [
|
|
|
105
105
|
}
|
|
106
106
|
|
|
107
107
|
const blockBeforeStartPoint = utils.splitTextBlock({
|
|
108
|
-
context,
|
|
108
|
+
context: snapshot.context,
|
|
109
109
|
block: focusTextBlock.node,
|
|
110
110
|
point: selectionStartPoint,
|
|
111
111
|
})?.before
|
|
112
112
|
const blockAfterEndPoint = utils.splitTextBlock({
|
|
113
|
-
context,
|
|
113
|
+
context: snapshot.context,
|
|
114
114
|
block: focusTextBlock.node,
|
|
115
115
|
point: selectionEndPoint,
|
|
116
116
|
})?.after
|
|
@@ -120,7 +120,7 @@ const oneLineBehaviors = [
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
const targetBlock = utils.mergeTextBlocks({
|
|
123
|
-
context,
|
|
123
|
+
context: snapshot.context,
|
|
124
124
|
targetBlock: blockBeforeStartPoint,
|
|
125
125
|
incomingBlock: event.block,
|
|
126
126
|
})
|
|
@@ -131,7 +131,7 @@ const oneLineBehaviors = [
|
|
|
131
131
|
})
|
|
132
132
|
|
|
133
133
|
const mergedBlock = utils.mergeTextBlocks({
|
|
134
|
-
context,
|
|
134
|
+
context: snapshot.context,
|
|
135
135
|
targetBlock,
|
|
136
136
|
incomingBlock: blockAfterEndPoint,
|
|
137
137
|
})
|
|
@@ -8,13 +8,13 @@ import {getSelectedBlocks} from './selectors'
|
|
|
8
8
|
*/
|
|
9
9
|
export const getActiveListItem: EditorSelector<
|
|
10
10
|
PortableTextListBlock['listItem'] | undefined
|
|
11
|
-
> = (
|
|
12
|
-
if (!context.selection) {
|
|
11
|
+
> = (snapshot) => {
|
|
12
|
+
if (!snapshot.context.selection) {
|
|
13
13
|
return undefined
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const guards = createGuards(context)
|
|
17
|
-
const selectedBlocks = getSelectedBlocks(
|
|
16
|
+
const guards = createGuards(snapshot.context)
|
|
17
|
+
const selectedBlocks = getSelectedBlocks(snapshot).map((block) => block.node)
|
|
18
18
|
const selectedTextBlocks = selectedBlocks.filter(guards.isTextBlock)
|
|
19
19
|
|
|
20
20
|
const firstTextBlock = selectedTextBlocks.at(0)
|
|
@@ -6,15 +6,15 @@ import {getSelectedBlocks} from './selectors'
|
|
|
6
6
|
/**
|
|
7
7
|
* @public
|
|
8
8
|
*/
|
|
9
|
-
export const getActiveStyle: EditorSelector<PortableTextTextBlock['style']> = (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (!context.selection) {
|
|
9
|
+
export const getActiveStyle: EditorSelector<PortableTextTextBlock['style']> = (
|
|
10
|
+
snapshot,
|
|
11
|
+
) => {
|
|
12
|
+
if (!snapshot.context.selection) {
|
|
13
13
|
return undefined
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
const guards = createGuards(context)
|
|
17
|
-
const selectedBlocks = getSelectedBlocks(
|
|
16
|
+
const guards = createGuards(snapshot.context)
|
|
17
|
+
const selectedBlocks = getSelectedBlocks(snapshot).map((block) => block.node)
|
|
18
18
|
const selectedTextBlocks = selectedBlocks.filter(guards.isTextBlock)
|
|
19
19
|
|
|
20
20
|
const firstTextBlock = selectedTextBlocks.at(0)
|
|
@@ -7,15 +7,15 @@ import {isKeyedSegment} from '../utils'
|
|
|
7
7
|
*/
|
|
8
8
|
export const getAnchorBlock: EditorSelector<
|
|
9
9
|
{node: PortableTextBlock; path: [KeyedSegment]} | undefined
|
|
10
|
-
> = (
|
|
11
|
-
const key = context.selection
|
|
12
|
-
? isKeyedSegment(context.selection.anchor.path[0])
|
|
13
|
-
? context.selection.anchor.path[0]._key
|
|
10
|
+
> = (snapshot) => {
|
|
11
|
+
const key = snapshot.context.selection
|
|
12
|
+
? isKeyedSegment(snapshot.context.selection.anchor.path[0])
|
|
13
|
+
? snapshot.context.selection.anchor.path[0]._key
|
|
14
14
|
: undefined
|
|
15
15
|
: undefined
|
|
16
16
|
|
|
17
17
|
const node = key
|
|
18
|
-
? context.value.find((block) => block._key === key)
|
|
18
|
+
? snapshot.context.value.find((block) => block._key === key)
|
|
19
19
|
: undefined
|
|
20
20
|
|
|
21
21
|
return node && key ? {node, path: [{_key: key}]} : undefined
|
|
@@ -13,16 +13,16 @@ export const getAnchorChild: EditorSelector<
|
|
|
13
13
|
path: [KeyedSegment, 'children', KeyedSegment]
|
|
14
14
|
}
|
|
15
15
|
| undefined
|
|
16
|
-
> = (
|
|
17
|
-
const anchorBlock = getAnchorTextBlock(
|
|
16
|
+
> = (snapshot) => {
|
|
17
|
+
const anchorBlock = getAnchorTextBlock(snapshot)
|
|
18
18
|
|
|
19
19
|
if (!anchorBlock) {
|
|
20
20
|
return undefined
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
const key = context.selection
|
|
24
|
-
? isKeyedSegment(context.selection.anchor.path[2])
|
|
25
|
-
? context.selection.anchor.path[2]._key
|
|
23
|
+
const key = snapshot.context.selection
|
|
24
|
+
? isKeyedSegment(snapshot.context.selection.anchor.path[2])
|
|
25
|
+
? snapshot.context.selection.anchor.path[2]._key
|
|
26
26
|
: undefined
|
|
27
27
|
: undefined
|
|
28
28
|
|
|
@@ -9,8 +9,8 @@ import {getAnchorChild} from './selector.get-anchor-child'
|
|
|
9
9
|
export const getAnchorSpan: EditorSelector<
|
|
10
10
|
| {node: PortableTextSpan; path: [KeyedSegment, 'children', KeyedSegment]}
|
|
11
11
|
| undefined
|
|
12
|
-
> = (
|
|
13
|
-
const anchorChild = getAnchorChild(
|
|
12
|
+
> = (snapshot) => {
|
|
13
|
+
const anchorChild = getAnchorChild(snapshot)
|
|
14
14
|
|
|
15
15
|
return anchorChild && isPortableTextSpan(anchorChild.node)
|
|
16
16
|
? {node: anchorChild.node, path: anchorChild.path}
|
|
@@ -11,8 +11,8 @@ import {getAnchorBlock} from './selector.get-anchor-block'
|
|
|
11
11
|
*/
|
|
12
12
|
export const getAnchorTextBlock: EditorSelector<
|
|
13
13
|
{node: PortableTextTextBlock; path: [KeyedSegment]} | undefined
|
|
14
|
-
> = (
|
|
15
|
-
const anchorBlock = getAnchorBlock(
|
|
14
|
+
> = (snapshot) => {
|
|
15
|
+
const anchorBlock = getAnchorBlock(snapshot)
|
|
16
16
|
|
|
17
17
|
return anchorBlock && isPortableTextTextBlock(anchorBlock.node)
|
|
18
18
|
? {node: anchorBlock.node, path: anchorBlock.path}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type {EditorSelector} from '../editor/editor-selector'
|
|
2
|
+
import type {BlockOffset} from '../types/block-offset'
|
|
2
3
|
import * as utils from '../utils'
|
|
3
4
|
import {getSelectionEndPoint} from './selector.get-selection-end-point'
|
|
4
5
|
import {getSelectionStartPoint} from './selector.get-selection-start-point'
|
|
@@ -7,25 +8,25 @@ import {getSelectionStartPoint} from './selector.get-selection-start-point'
|
|
|
7
8
|
* @public
|
|
8
9
|
*/
|
|
9
10
|
export const getBlockOffsets: EditorSelector<
|
|
10
|
-
{start:
|
|
11
|
-
> = (
|
|
12
|
-
if (!context.selection) {
|
|
11
|
+
{start: BlockOffset; end: BlockOffset} | undefined
|
|
12
|
+
> = (snapshot) => {
|
|
13
|
+
if (!snapshot.context.selection) {
|
|
13
14
|
return undefined
|
|
14
15
|
}
|
|
15
16
|
|
|
16
|
-
const selectionStartPoint = getSelectionStartPoint(
|
|
17
|
-
const selectionEndPoint = getSelectionEndPoint(
|
|
17
|
+
const selectionStartPoint = getSelectionStartPoint(snapshot)
|
|
18
|
+
const selectionEndPoint = getSelectionEndPoint(snapshot)
|
|
18
19
|
|
|
19
20
|
if (!selectionStartPoint || !selectionEndPoint) {
|
|
20
21
|
return undefined
|
|
21
22
|
}
|
|
22
23
|
|
|
23
24
|
const start = utils.spanSelectionPointToBlockOffset({
|
|
24
|
-
value: context.value,
|
|
25
|
+
value: snapshot.context.value,
|
|
25
26
|
selectionPoint: selectionStartPoint,
|
|
26
27
|
})
|
|
27
28
|
const end = utils.spanSelectionPointToBlockOffset({
|
|
28
|
-
value: context.value,
|
|
29
|
+
value: snapshot.context.value,
|
|
29
30
|
selectionPoint: selectionEndPoint,
|
|
30
31
|
})
|
|
31
32
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type {EditorSelector} from '../editor/editor-selector'
|
|
2
|
+
import type {BlockOffset} from '../types/block-offset'
|
|
2
3
|
import type {EditorSelection} from '../types/editor'
|
|
3
4
|
import {
|
|
4
5
|
blockOffsetToSpanSelectionPoint,
|
|
5
6
|
getBlockEndPoint,
|
|
6
7
|
getBlockStartPoint,
|
|
7
8
|
spanSelectionPointToBlockOffset,
|
|
8
|
-
type BlockOffset,
|
|
9
9
|
} from '../utils'
|
|
10
10
|
import {getNextInlineObject} from './selector.get-next-inline-object'
|
|
11
11
|
import {getPreviousInlineObject} from './selector.get-previous-inline-object'
|
|
@@ -20,22 +20,22 @@ import {getFocusTextBlock} from './selectors'
|
|
|
20
20
|
* Returns the selection of the of the word the caret is placed in.
|
|
21
21
|
* Note: Only returns a word selection if the current selection is collapsed
|
|
22
22
|
*/
|
|
23
|
-
export const getCaretWordSelection: EditorSelector<EditorSelection> = (
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (!context.selection) {
|
|
23
|
+
export const getCaretWordSelection: EditorSelector<EditorSelection> = (
|
|
24
|
+
snapshot,
|
|
25
|
+
) => {
|
|
26
|
+
if (!snapshot.context.selection) {
|
|
27
27
|
return null
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
if (!isSelectionCollapsed(
|
|
30
|
+
if (!isSelectionCollapsed(snapshot)) {
|
|
31
31
|
return null
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
const focusTextBlock = getFocusTextBlock(
|
|
35
|
-
const selectionStartPoint = getSelectionStartPoint(
|
|
34
|
+
const focusTextBlock = getFocusTextBlock(snapshot)
|
|
35
|
+
const selectionStartPoint = getSelectionStartPoint(snapshot)
|
|
36
36
|
const selectionStartOffset = selectionStartPoint
|
|
37
37
|
? spanSelectionPointToBlockOffset({
|
|
38
|
-
value: context.value,
|
|
38
|
+
value: snapshot.context.value,
|
|
39
39
|
selectionPoint: selectionStartPoint,
|
|
40
40
|
})
|
|
41
41
|
: undefined
|
|
@@ -44,11 +44,12 @@ export const getCaretWordSelection: EditorSelector<EditorSelection> = ({
|
|
|
44
44
|
return null
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
const previousInlineObject = getPreviousInlineObject(
|
|
47
|
+
const previousInlineObject = getPreviousInlineObject(snapshot)
|
|
48
48
|
const blockStartPoint = getBlockStartPoint(focusTextBlock)
|
|
49
49
|
const textBefore = getSelectionText({
|
|
50
|
+
...snapshot,
|
|
50
51
|
context: {
|
|
51
|
-
...context,
|
|
52
|
+
...snapshot.context,
|
|
52
53
|
selection: {
|
|
53
54
|
anchor: previousInlineObject
|
|
54
55
|
? {path: previousInlineObject.path, offset: 0}
|
|
@@ -59,11 +60,12 @@ export const getCaretWordSelection: EditorSelector<EditorSelection> = ({
|
|
|
59
60
|
})
|
|
60
61
|
const textDirectlyBefore = textBefore.split(/\s+/).at(-1)
|
|
61
62
|
|
|
62
|
-
const nextInlineObject = getNextInlineObject(
|
|
63
|
+
const nextInlineObject = getNextInlineObject(snapshot)
|
|
63
64
|
const blockEndPoint = getBlockEndPoint(focusTextBlock)
|
|
64
65
|
const textAfter = getSelectionText({
|
|
66
|
+
...snapshot,
|
|
65
67
|
context: {
|
|
66
|
-
...context,
|
|
68
|
+
...snapshot.context,
|
|
67
69
|
selection: {
|
|
68
70
|
anchor: selectionStartPoint,
|
|
69
71
|
focus: nextInlineObject
|
|
@@ -95,12 +97,12 @@ export const getCaretWordSelection: EditorSelector<EditorSelection> = ({
|
|
|
95
97
|
: selectionStartOffset
|
|
96
98
|
|
|
97
99
|
const caretWordStartSelectionPoint = blockOffsetToSpanSelectionPoint({
|
|
98
|
-
value: context.value,
|
|
100
|
+
value: snapshot.context.value,
|
|
99
101
|
blockOffset: caretWordStartOffset,
|
|
100
102
|
direction: 'backward',
|
|
101
103
|
})
|
|
102
104
|
const caretWordEndSelectionPoint = blockOffsetToSpanSelectionPoint({
|
|
103
|
-
value: context.value,
|
|
105
|
+
value: snapshot.context.value,
|
|
104
106
|
blockOffset: caretWordEndOffset,
|
|
105
107
|
direction: 'forward',
|
|
106
108
|
})
|
|
@@ -115,8 +117,9 @@ export const getCaretWordSelection: EditorSelector<EditorSelection> = ({
|
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
return isSelectionExpanded({
|
|
120
|
+
...snapshot,
|
|
118
121
|
context: {
|
|
119
|
-
...context,
|
|
122
|
+
...snapshot.context,
|
|
120
123
|
selection: caretWordSelection,
|
|
121
124
|
},
|
|
122
125
|
})
|
|
@@ -17,9 +17,9 @@ export const getNextInlineObject: EditorSelector<
|
|
|
17
17
|
path: [KeyedSegment, 'children', KeyedSegment]
|
|
18
18
|
}
|
|
19
19
|
| undefined
|
|
20
|
-
> = (
|
|
21
|
-
const focusTextBlock = getFocusTextBlock(
|
|
22
|
-
const selectionEndPoint = getSelectionEndPoint(
|
|
20
|
+
> = (snapshot) => {
|
|
21
|
+
const focusTextBlock = getFocusTextBlock(snapshot)
|
|
22
|
+
const selectionEndPoint = getSelectionEndPoint(snapshot)
|
|
23
23
|
const selectionEndPointChildKey =
|
|
24
24
|
selectionEndPoint && isKeySegment(selectionEndPoint.path[2])
|
|
25
25
|
? selectionEndPoint.path[2]._key
|
|
@@ -43,7 +43,7 @@ export const getNextInlineObject: EditorSelector<
|
|
|
43
43
|
continue
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
if (!isSpan(context, child) && endPointChildFound) {
|
|
46
|
+
if (!isSpan(snapshot.context, child) && endPointChildFound) {
|
|
47
47
|
inlineObject = {
|
|
48
48
|
node: child,
|
|
49
49
|
path: [...focusTextBlock.path, 'children', {_key: child._key}],
|