@portabletext/editor 2.3.8 → 2.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/_chunks-dts/behavior.types.action.d.cts +93 -51
- package/lib/_chunks-dts/behavior.types.action.d.ts +102 -60
- package/lib/behaviors/index.cjs.map +1 -1
- package/lib/behaviors/index.js.map +1 -1
- package/lib/index.cjs +344 -259
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +345 -260
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.d.ts +3 -3
- package/lib/utils/index.d.ts +2 -2
- package/package.json +10 -10
- package/src/behaviors/behavior.abstract.deserialize.ts +247 -0
- package/src/behaviors/behavior.abstract.serialize.ts +91 -0
- package/src/behaviors/behavior.abstract.ts +4 -216
- package/src/behaviors/behavior.perform-event.ts +16 -4
- package/src/behaviors/behavior.types.action.ts +26 -2
- package/src/behaviors/behavior.types.event.ts +23 -0
- package/src/editor/editor-machine.ts +12 -1
- package/src/internal-utils/test-editor.tsx +15 -0
package/lib/plugins/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Behavior, Editor, EditorEmittedEvent, EditorSchema } from "../_chunks-dts/behavior.types.action.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react12 from "react";
|
|
3
3
|
import React from "react";
|
|
4
4
|
/**
|
|
5
5
|
* @beta
|
|
@@ -181,7 +181,7 @@ type MarkdownPluginConfig = MarkdownBehaviorsConfig & {
|
|
|
181
181
|
*/
|
|
182
182
|
declare function MarkdownPlugin(props: {
|
|
183
183
|
config: MarkdownPluginConfig;
|
|
184
|
-
}):
|
|
184
|
+
}): react12.JSX.Element;
|
|
185
185
|
/**
|
|
186
186
|
* @beta
|
|
187
187
|
* Restrict the editor to one line. The plugin takes care of blocking
|
|
@@ -192,5 +192,5 @@ declare function MarkdownPlugin(props: {
|
|
|
192
192
|
*
|
|
193
193
|
* @deprecated Install the plugin from `@portabletext/plugin-one-line`
|
|
194
194
|
*/
|
|
195
|
-
declare function OneLinePlugin():
|
|
195
|
+
declare function OneLinePlugin(): react12.JSX.Element;
|
|
196
196
|
export { BehaviorPlugin, DecoratorShortcutPlugin, EditorRefPlugin, EventListenerPlugin, MarkdownPlugin, type MarkdownPluginConfig, OneLinePlugin };
|
package/lib/utils/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BlockOffset, BlockPath, ChildPath, EditorContext, EditorSelection, EditorSelectionPoint } from "../_chunks-dts/behavior.types.action.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as _sanity_types8 from "@sanity/types";
|
|
3
3
|
import { KeyedSegment, PortableTextBlock, PortableTextChild, PortableTextSpan, PortableTextTextBlock } from "@sanity/types";
|
|
4
4
|
/**
|
|
5
5
|
* @public
|
|
@@ -150,7 +150,7 @@ declare function mergeTextBlocks({
|
|
|
150
150
|
context: Pick<EditorContext, 'keyGenerator' | 'schema'>;
|
|
151
151
|
targetBlock: PortableTextTextBlock;
|
|
152
152
|
incomingBlock: PortableTextTextBlock;
|
|
153
|
-
}): PortableTextTextBlock<
|
|
153
|
+
}): PortableTextTextBlock<_sanity_types8.PortableTextObject | _sanity_types8.PortableTextSpan>;
|
|
154
154
|
/**
|
|
155
155
|
* @public
|
|
156
156
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -79,16 +79,16 @@
|
|
|
79
79
|
"slate-dom": "^0.117.4",
|
|
80
80
|
"slate-react": "0.117.4",
|
|
81
81
|
"xstate": "^5.20.2",
|
|
82
|
-
"@portabletext/block-tools": "^3.
|
|
82
|
+
"@portabletext/block-tools": "^3.3.0",
|
|
83
83
|
"@portabletext/keyboard-shortcuts": "^1.1.1",
|
|
84
|
-
"@portabletext/
|
|
85
|
-
"@portabletext/
|
|
84
|
+
"@portabletext/schema": "^1.0.0",
|
|
85
|
+
"@portabletext/patches": "^1.1.6"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
88
|
"@sanity/diff-match-patch": "^3.2.0",
|
|
89
89
|
"@sanity/pkg-utils": "^7.11.1",
|
|
90
|
-
"@sanity/schema": "^4.
|
|
91
|
-
"@sanity/types": "^4.
|
|
90
|
+
"@sanity/schema": "^4.5.0",
|
|
91
|
+
"@sanity/types": "^4.5.0",
|
|
92
92
|
"@testing-library/react": "^16.3.0",
|
|
93
93
|
"@types/debug": "^4.1.12",
|
|
94
94
|
"@types/lodash": "^4.17.16",
|
|
@@ -111,12 +111,12 @@
|
|
|
111
111
|
"vite": "^7.0.6",
|
|
112
112
|
"vitest": "^3.2.4",
|
|
113
113
|
"vitest-browser-react": "^1.0.1",
|
|
114
|
-
"
|
|
115
|
-
"
|
|
114
|
+
"racejar": "1.2.12",
|
|
115
|
+
"@portabletext/sanity-bridge": "1.1.2"
|
|
116
116
|
},
|
|
117
117
|
"peerDependencies": {
|
|
118
|
-
"@sanity/schema": "^4.
|
|
119
|
-
"@sanity/types": "^4.
|
|
118
|
+
"@sanity/schema": "^4.5.0",
|
|
119
|
+
"@sanity/types": "^4.5.0",
|
|
120
120
|
"react": "^18.3 || ^19",
|
|
121
121
|
"rxjs": "^7.8.2",
|
|
122
122
|
"@portabletext/sanity-bridge": "^1.1.2"
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import {isTextBlock} from '../internal-utils/parse-blocks'
|
|
2
|
+
import * as selectors from '../selectors'
|
|
3
|
+
import {getActiveDecorators} from '../selectors/selector.get-active-decorators'
|
|
4
|
+
import {getTextBlockText} from '../utils/util.get-text-block-text'
|
|
5
|
+
import {raise} from './behavior.types.action'
|
|
6
|
+
import {defineBehavior} from './behavior.types.behavior'
|
|
7
|
+
|
|
8
|
+
export const abstractDeserializeBehaviors = [
|
|
9
|
+
defineBehavior({
|
|
10
|
+
on: 'deserialize',
|
|
11
|
+
guard: ({event}) => {
|
|
12
|
+
const portableText = event.originEvent.originEvent.dataTransfer.getData(
|
|
13
|
+
'application/x-portable-text',
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
if (portableText) {
|
|
17
|
+
return {
|
|
18
|
+
type: 'deserialize.data',
|
|
19
|
+
mimeType: 'application/x-portable-text',
|
|
20
|
+
data: portableText,
|
|
21
|
+
originEvent: event.originEvent,
|
|
22
|
+
} as const
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const json =
|
|
26
|
+
event.originEvent.originEvent.dataTransfer.getData('application/json')
|
|
27
|
+
|
|
28
|
+
if (json) {
|
|
29
|
+
return {
|
|
30
|
+
type: 'deserialize.data',
|
|
31
|
+
mimeType: 'application/json',
|
|
32
|
+
data: json,
|
|
33
|
+
originEvent: event.originEvent,
|
|
34
|
+
} as const
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const html =
|
|
38
|
+
event.originEvent.originEvent.dataTransfer.getData('text/html')
|
|
39
|
+
|
|
40
|
+
if (html) {
|
|
41
|
+
return {
|
|
42
|
+
type: 'deserialize.data',
|
|
43
|
+
mimeType: 'text/html',
|
|
44
|
+
data: html,
|
|
45
|
+
originEvent: event.originEvent,
|
|
46
|
+
} as const
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const text =
|
|
50
|
+
event.originEvent.originEvent.dataTransfer.getData('text/plain')
|
|
51
|
+
|
|
52
|
+
if (text) {
|
|
53
|
+
return {
|
|
54
|
+
type: 'deserialize.data',
|
|
55
|
+
mimeType: 'text/plain',
|
|
56
|
+
data: text,
|
|
57
|
+
originEvent: event.originEvent,
|
|
58
|
+
} as const
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return false
|
|
62
|
+
},
|
|
63
|
+
actions: [(_, deserializeEvent) => [raise(deserializeEvent)]],
|
|
64
|
+
}),
|
|
65
|
+
defineBehavior({
|
|
66
|
+
on: 'deserialize',
|
|
67
|
+
actions: [
|
|
68
|
+
({event}) => [
|
|
69
|
+
raise({
|
|
70
|
+
type: 'deserialization.failure',
|
|
71
|
+
mimeType: '*/*',
|
|
72
|
+
reason: 'No Behavior was able to handle the incoming data',
|
|
73
|
+
originEvent: event.originEvent,
|
|
74
|
+
}),
|
|
75
|
+
],
|
|
76
|
+
],
|
|
77
|
+
}),
|
|
78
|
+
defineBehavior({
|
|
79
|
+
on: 'deserialize.data',
|
|
80
|
+
guard: ({snapshot, event}) => {
|
|
81
|
+
const converter = snapshot.context.converters.find(
|
|
82
|
+
(converter) => converter.mimeType === event.mimeType,
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
if (!converter) {
|
|
86
|
+
return false
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return converter.deserialize({
|
|
90
|
+
snapshot,
|
|
91
|
+
event: {
|
|
92
|
+
type: 'deserialize',
|
|
93
|
+
data: event.data,
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
},
|
|
97
|
+
actions: [
|
|
98
|
+
({event}, deserializeEvent) => [
|
|
99
|
+
raise({
|
|
100
|
+
...deserializeEvent,
|
|
101
|
+
originEvent: event.originEvent,
|
|
102
|
+
}),
|
|
103
|
+
],
|
|
104
|
+
],
|
|
105
|
+
}),
|
|
106
|
+
/**
|
|
107
|
+
* If we are pasting text/plain into a text block then we can probably
|
|
108
|
+
* assume that the intended behavior is that the pasted text inherits
|
|
109
|
+
* formatting from the text it's pasted into.
|
|
110
|
+
*/
|
|
111
|
+
defineBehavior({
|
|
112
|
+
on: 'deserialization.success',
|
|
113
|
+
guard: ({snapshot, event}) => {
|
|
114
|
+
const focusTextBlock = selectors.getFocusTextBlock(snapshot)
|
|
115
|
+
|
|
116
|
+
if (
|
|
117
|
+
focusTextBlock &&
|
|
118
|
+
event.mimeType === 'text/plain' &&
|
|
119
|
+
event.originEvent.type === 'clipboard.paste'
|
|
120
|
+
) {
|
|
121
|
+
const activeDecorators = getActiveDecorators(snapshot)
|
|
122
|
+
const activeAnnotations = selectors.getActiveAnnotations(snapshot)
|
|
123
|
+
|
|
124
|
+
return {
|
|
125
|
+
activeAnnotations,
|
|
126
|
+
activeDecorators,
|
|
127
|
+
textRuns: event.data.flatMap((block) =>
|
|
128
|
+
isTextBlock(snapshot.context, block)
|
|
129
|
+
? [getTextBlockText(block)]
|
|
130
|
+
: [],
|
|
131
|
+
),
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return false
|
|
136
|
+
},
|
|
137
|
+
actions: [
|
|
138
|
+
(_, {activeAnnotations, activeDecorators, textRuns}) =>
|
|
139
|
+
textRuns.flatMap((textRun, index) =>
|
|
140
|
+
index !== textRuns.length - 1
|
|
141
|
+
? [
|
|
142
|
+
raise({
|
|
143
|
+
type: 'insert.span',
|
|
144
|
+
text: textRun,
|
|
145
|
+
decorators: activeDecorators,
|
|
146
|
+
annotations: activeAnnotations.map(
|
|
147
|
+
({_key, _type, ...value}) => ({
|
|
148
|
+
name: _type,
|
|
149
|
+
value,
|
|
150
|
+
}),
|
|
151
|
+
),
|
|
152
|
+
}),
|
|
153
|
+
raise({type: 'insert.break'}),
|
|
154
|
+
]
|
|
155
|
+
: [
|
|
156
|
+
raise({
|
|
157
|
+
type: 'insert.span',
|
|
158
|
+
text: textRun,
|
|
159
|
+
decorators: activeDecorators,
|
|
160
|
+
annotations: activeAnnotations.map(
|
|
161
|
+
({_key, _type, ...value}) => ({
|
|
162
|
+
name: _type,
|
|
163
|
+
value,
|
|
164
|
+
}),
|
|
165
|
+
),
|
|
166
|
+
}),
|
|
167
|
+
],
|
|
168
|
+
),
|
|
169
|
+
],
|
|
170
|
+
}),
|
|
171
|
+
defineBehavior({
|
|
172
|
+
on: 'deserialization.success',
|
|
173
|
+
actions: [
|
|
174
|
+
({event}) => [
|
|
175
|
+
raise({
|
|
176
|
+
type: 'insert.blocks',
|
|
177
|
+
blocks: event.data,
|
|
178
|
+
placement: 'auto',
|
|
179
|
+
}),
|
|
180
|
+
],
|
|
181
|
+
],
|
|
182
|
+
}),
|
|
183
|
+
defineBehavior({
|
|
184
|
+
on: 'deserialization.failure',
|
|
185
|
+
guard: ({event}) => {
|
|
186
|
+
if (event.mimeType === 'application/x-portable-text') {
|
|
187
|
+
const json =
|
|
188
|
+
event.originEvent.originEvent.dataTransfer.getData('application/json')
|
|
189
|
+
|
|
190
|
+
if (json) {
|
|
191
|
+
return {
|
|
192
|
+
type: 'deserialize.data',
|
|
193
|
+
mimeType: 'application/json',
|
|
194
|
+
data: json,
|
|
195
|
+
originEvent: event.originEvent,
|
|
196
|
+
} as const
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (event.mimeType === 'application/json') {
|
|
201
|
+
const html =
|
|
202
|
+
event.originEvent.originEvent.dataTransfer.getData('text/html')
|
|
203
|
+
|
|
204
|
+
if (html) {
|
|
205
|
+
return {
|
|
206
|
+
type: 'deserialize.data',
|
|
207
|
+
mimeType: 'text/html',
|
|
208
|
+
data: html,
|
|
209
|
+
originEvent: event.originEvent,
|
|
210
|
+
} as const
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
if (event.mimeType === 'text/html') {
|
|
215
|
+
const text =
|
|
216
|
+
event.originEvent.originEvent.dataTransfer.getData('text/plain')
|
|
217
|
+
|
|
218
|
+
if (text) {
|
|
219
|
+
return {
|
|
220
|
+
type: 'deserialize.data',
|
|
221
|
+
mimeType: 'text/plain',
|
|
222
|
+
data: text,
|
|
223
|
+
originEvent: event.originEvent,
|
|
224
|
+
} as const
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
return false
|
|
229
|
+
},
|
|
230
|
+
actions: [(_, deserializeDataEvent) => [raise(deserializeDataEvent)]],
|
|
231
|
+
}),
|
|
232
|
+
defineBehavior({
|
|
233
|
+
on: 'deserialization.failure',
|
|
234
|
+
actions: [
|
|
235
|
+
({event}) => [
|
|
236
|
+
{
|
|
237
|
+
type: 'effect',
|
|
238
|
+
effect: () => {
|
|
239
|
+
console.warn(
|
|
240
|
+
`Deserialization of ${event.mimeType} failed with reason "${event.reason}"`,
|
|
241
|
+
)
|
|
242
|
+
},
|
|
243
|
+
},
|
|
244
|
+
],
|
|
245
|
+
],
|
|
246
|
+
}),
|
|
247
|
+
]
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import {raise} from './behavior.types.action'
|
|
2
|
+
import {defineBehavior} from './behavior.types.behavior'
|
|
3
|
+
|
|
4
|
+
export const abstractSerializeBehaviors = [
|
|
5
|
+
defineBehavior({
|
|
6
|
+
on: 'serialize',
|
|
7
|
+
actions: [
|
|
8
|
+
({event}) => [
|
|
9
|
+
raise({
|
|
10
|
+
type: 'serialize.data',
|
|
11
|
+
mimeType: 'application/x-portable-text',
|
|
12
|
+
originEvent: event.originEvent,
|
|
13
|
+
}),
|
|
14
|
+
raise({
|
|
15
|
+
type: 'serialize.data',
|
|
16
|
+
mimeType: 'application/json',
|
|
17
|
+
originEvent: event.originEvent,
|
|
18
|
+
}),
|
|
19
|
+
raise({
|
|
20
|
+
type: 'serialize.data',
|
|
21
|
+
mimeType: 'text/html',
|
|
22
|
+
originEvent: event.originEvent,
|
|
23
|
+
}),
|
|
24
|
+
raise({
|
|
25
|
+
type: 'serialize.data',
|
|
26
|
+
mimeType: 'text/plain',
|
|
27
|
+
originEvent: event.originEvent,
|
|
28
|
+
}),
|
|
29
|
+
],
|
|
30
|
+
],
|
|
31
|
+
}),
|
|
32
|
+
defineBehavior({
|
|
33
|
+
on: 'serialize.data',
|
|
34
|
+
guard: ({snapshot, event}) => {
|
|
35
|
+
const converter = snapshot.context.converters.find(
|
|
36
|
+
(converter) => converter.mimeType === event.mimeType,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
if (!converter) {
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return converter.serialize({
|
|
44
|
+
snapshot,
|
|
45
|
+
event: {
|
|
46
|
+
type: 'serialize',
|
|
47
|
+
originEvent: event.originEvent.type,
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
},
|
|
51
|
+
actions: [
|
|
52
|
+
({event}, serializeEvent) => [
|
|
53
|
+
raise({
|
|
54
|
+
...serializeEvent,
|
|
55
|
+
originEvent: event.originEvent,
|
|
56
|
+
}),
|
|
57
|
+
],
|
|
58
|
+
],
|
|
59
|
+
}),
|
|
60
|
+
defineBehavior({
|
|
61
|
+
on: 'serialization.success',
|
|
62
|
+
actions: [
|
|
63
|
+
({event}) => [
|
|
64
|
+
{
|
|
65
|
+
type: 'effect',
|
|
66
|
+
effect: () => {
|
|
67
|
+
event.originEvent.originEvent.dataTransfer.setData(
|
|
68
|
+
event.mimeType,
|
|
69
|
+
event.data,
|
|
70
|
+
)
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
],
|
|
74
|
+
],
|
|
75
|
+
}),
|
|
76
|
+
defineBehavior({
|
|
77
|
+
on: 'serialization.failure',
|
|
78
|
+
actions: [
|
|
79
|
+
({event}) => [
|
|
80
|
+
{
|
|
81
|
+
type: 'effect',
|
|
82
|
+
effect: () => {
|
|
83
|
+
console.warn(
|
|
84
|
+
`Serialization of ${event.mimeType} failed with reason "${event.reason}"`,
|
|
85
|
+
)
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
],
|
|
89
|
+
],
|
|
90
|
+
}),
|
|
91
|
+
]
|
|
@@ -1,108 +1,19 @@
|
|
|
1
|
-
import type {ConverterEvent} from '../converters/converter.types'
|
|
2
|
-
import {isTextBlock} from '../internal-utils/parse-blocks'
|
|
3
1
|
import * as selectors from '../selectors'
|
|
4
|
-
import {getActiveDecorators} from '../selectors/selector.get-active-decorators'
|
|
5
|
-
import type {PickFromUnion} from '../type-utils'
|
|
6
|
-
import {getTextBlockText} from '../utils'
|
|
7
2
|
import {abstractAnnotationBehaviors} from './behavior.abstract.annotation'
|
|
8
3
|
import {abstractDecoratorBehaviors} from './behavior.abstract.decorator'
|
|
9
4
|
import {abstractDeleteBehaviors} from './behavior.abstract.delete'
|
|
5
|
+
import {abstractDeserializeBehaviors} from './behavior.abstract.deserialize'
|
|
10
6
|
import {abstractInsertBehaviors} from './behavior.abstract.insert'
|
|
11
7
|
import {abstractKeyboardBehaviors} from './behavior.abstract.keyboard'
|
|
12
8
|
import {abstractListItemBehaviors} from './behavior.abstract.list-item'
|
|
13
9
|
import {abstractMoveBehaviors} from './behavior.abstract.move'
|
|
14
10
|
import {abstractSelectBehaviors} from './behavior.abstract.select'
|
|
11
|
+
import {abstractSerializeBehaviors} from './behavior.abstract.serialize'
|
|
15
12
|
import {abstractSplitBehaviors} from './behavior.abstract.split'
|
|
16
13
|
import {abstractStyleBehaviors} from './behavior.abstract.style'
|
|
17
14
|
import {raise} from './behavior.types.action'
|
|
18
15
|
import {defineBehavior} from './behavior.types.behavior'
|
|
19
16
|
|
|
20
|
-
const raiseDeserializationSuccessOrFailure = defineBehavior({
|
|
21
|
-
on: 'deserialize',
|
|
22
|
-
guard: ({snapshot, event}) => {
|
|
23
|
-
let success:
|
|
24
|
-
| PickFromUnion<ConverterEvent, 'type', 'deserialization.success'>
|
|
25
|
-
| undefined
|
|
26
|
-
const failures: Array<
|
|
27
|
-
PickFromUnion<ConverterEvent, 'type', 'deserialization.failure'>
|
|
28
|
-
> = []
|
|
29
|
-
|
|
30
|
-
for (const converter of snapshot.context.converters) {
|
|
31
|
-
const data = event.originEvent.originEvent.dataTransfer.getData(
|
|
32
|
-
converter.mimeType,
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
if (!data) {
|
|
36
|
-
continue
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const deserializeEvent = converter.deserialize({
|
|
40
|
-
snapshot,
|
|
41
|
-
event: {type: 'deserialize', data},
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
if (deserializeEvent.type === 'deserialization.success') {
|
|
45
|
-
success = deserializeEvent
|
|
46
|
-
break
|
|
47
|
-
} else {
|
|
48
|
-
failures.push(deserializeEvent)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
if (!success) {
|
|
53
|
-
return {
|
|
54
|
-
type: 'deserialization.failure',
|
|
55
|
-
mimeType: '*/*',
|
|
56
|
-
reason: failures.map((failure) => failure.reason).join(', '),
|
|
57
|
-
} as const
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return success
|
|
61
|
-
},
|
|
62
|
-
actions: [
|
|
63
|
-
({event}, deserializeEvent) => [
|
|
64
|
-
raise({
|
|
65
|
-
...deserializeEvent,
|
|
66
|
-
originEvent: event.originEvent,
|
|
67
|
-
}),
|
|
68
|
-
],
|
|
69
|
-
],
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
const raiseSerializationSuccessOrFailure = defineBehavior({
|
|
73
|
-
on: 'serialize',
|
|
74
|
-
guard: ({snapshot, event}) => {
|
|
75
|
-
if (snapshot.context.converters.length === 0) {
|
|
76
|
-
return false
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const serializeEvents = snapshot.context.converters.map((converter) =>
|
|
80
|
-
converter.serialize({
|
|
81
|
-
snapshot,
|
|
82
|
-
event: {
|
|
83
|
-
...event,
|
|
84
|
-
originEvent: event.originEvent.type,
|
|
85
|
-
},
|
|
86
|
-
}),
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
if (serializeEvents.length === 0) {
|
|
90
|
-
return false
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
return serializeEvents
|
|
94
|
-
},
|
|
95
|
-
actions: [
|
|
96
|
-
({event}, serializeEvents) =>
|
|
97
|
-
serializeEvents.map((serializeEvent) => {
|
|
98
|
-
return raise({
|
|
99
|
-
...serializeEvent,
|
|
100
|
-
originEvent: event.originEvent,
|
|
101
|
-
})
|
|
102
|
-
}),
|
|
103
|
-
],
|
|
104
|
-
})
|
|
105
|
-
|
|
106
17
|
export const abstractBehaviors = [
|
|
107
18
|
defineBehavior({
|
|
108
19
|
on: 'clipboard.copy',
|
|
@@ -168,130 +79,7 @@ export const abstractBehaviors = [
|
|
|
168
79
|
],
|
|
169
80
|
],
|
|
170
81
|
}),
|
|
171
|
-
defineBehavior({
|
|
172
|
-
on: 'serialization.success',
|
|
173
|
-
actions: [
|
|
174
|
-
({event}) => [
|
|
175
|
-
{
|
|
176
|
-
type: 'effect',
|
|
177
|
-
effect: () => {
|
|
178
|
-
event.originEvent.originEvent.dataTransfer.setData(
|
|
179
|
-
event.mimeType,
|
|
180
|
-
event.data,
|
|
181
|
-
)
|
|
182
|
-
},
|
|
183
|
-
},
|
|
184
|
-
],
|
|
185
|
-
],
|
|
186
|
-
}),
|
|
187
|
-
defineBehavior({
|
|
188
|
-
on: 'serialization.failure',
|
|
189
|
-
actions: [
|
|
190
|
-
({event}) => [
|
|
191
|
-
{
|
|
192
|
-
type: 'effect',
|
|
193
|
-
effect: () => {
|
|
194
|
-
console.warn(
|
|
195
|
-
`Serialization of ${event.mimeType} failed with reason "${event.reason}"`,
|
|
196
|
-
)
|
|
197
|
-
},
|
|
198
|
-
},
|
|
199
|
-
],
|
|
200
|
-
],
|
|
201
|
-
}),
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* If we are pasting text/plain into a text block then we can probably
|
|
205
|
-
* assume that the intended behavior is that the pasted text inherits
|
|
206
|
-
* formatting from the text it's pasted into.
|
|
207
|
-
*/
|
|
208
|
-
defineBehavior({
|
|
209
|
-
on: 'deserialization.success',
|
|
210
|
-
guard: ({snapshot, event}) => {
|
|
211
|
-
const focusTextBlock = selectors.getFocusTextBlock(snapshot)
|
|
212
82
|
|
|
213
|
-
if (
|
|
214
|
-
focusTextBlock &&
|
|
215
|
-
event.mimeType === 'text/plain' &&
|
|
216
|
-
event.originEvent.type === 'clipboard.paste'
|
|
217
|
-
) {
|
|
218
|
-
const activeDecorators = getActiveDecorators(snapshot)
|
|
219
|
-
const activeAnnotations = selectors.getActiveAnnotations(snapshot)
|
|
220
|
-
|
|
221
|
-
return {
|
|
222
|
-
activeAnnotations,
|
|
223
|
-
activeDecorators,
|
|
224
|
-
textRuns: event.data.flatMap((block) =>
|
|
225
|
-
isTextBlock(snapshot.context, block)
|
|
226
|
-
? [getTextBlockText(block)]
|
|
227
|
-
: [],
|
|
228
|
-
),
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
return false
|
|
233
|
-
},
|
|
234
|
-
actions: [
|
|
235
|
-
(_, {activeAnnotations, activeDecorators, textRuns}) =>
|
|
236
|
-
textRuns.flatMap((textRun, index) =>
|
|
237
|
-
index !== textRuns.length - 1
|
|
238
|
-
? [
|
|
239
|
-
raise({
|
|
240
|
-
type: 'insert.span',
|
|
241
|
-
text: textRun,
|
|
242
|
-
decorators: activeDecorators,
|
|
243
|
-
annotations: activeAnnotations.map(
|
|
244
|
-
({_key, _type, ...value}) => ({
|
|
245
|
-
name: _type,
|
|
246
|
-
value,
|
|
247
|
-
}),
|
|
248
|
-
),
|
|
249
|
-
}),
|
|
250
|
-
raise({type: 'insert.break'}),
|
|
251
|
-
]
|
|
252
|
-
: [
|
|
253
|
-
raise({
|
|
254
|
-
type: 'insert.span',
|
|
255
|
-
text: textRun,
|
|
256
|
-
decorators: activeDecorators,
|
|
257
|
-
annotations: activeAnnotations.map(
|
|
258
|
-
({_key, _type, ...value}) => ({
|
|
259
|
-
name: _type,
|
|
260
|
-
value,
|
|
261
|
-
}),
|
|
262
|
-
),
|
|
263
|
-
}),
|
|
264
|
-
],
|
|
265
|
-
),
|
|
266
|
-
],
|
|
267
|
-
}),
|
|
268
|
-
defineBehavior({
|
|
269
|
-
on: 'deserialization.success',
|
|
270
|
-
actions: [
|
|
271
|
-
({event}) => [
|
|
272
|
-
raise({
|
|
273
|
-
type: 'insert.blocks',
|
|
274
|
-
blocks: event.data,
|
|
275
|
-
placement: 'auto',
|
|
276
|
-
}),
|
|
277
|
-
],
|
|
278
|
-
],
|
|
279
|
-
}),
|
|
280
|
-
defineBehavior({
|
|
281
|
-
on: 'deserialization.failure',
|
|
282
|
-
actions: [
|
|
283
|
-
({event}) => [
|
|
284
|
-
{
|
|
285
|
-
type: 'effect',
|
|
286
|
-
effect: () => {
|
|
287
|
-
console.warn(
|
|
288
|
-
`Deserialization of ${event.mimeType} failed with reason "${event.reason}"`,
|
|
289
|
-
)
|
|
290
|
-
},
|
|
291
|
-
},
|
|
292
|
-
],
|
|
293
|
-
],
|
|
294
|
-
}),
|
|
295
83
|
defineBehavior({
|
|
296
84
|
on: 'clipboard.paste',
|
|
297
85
|
guard: ({snapshot}) => {
|
|
@@ -338,13 +126,13 @@ export const abstractBehaviors = [
|
|
|
338
126
|
...abstractAnnotationBehaviors,
|
|
339
127
|
...abstractDecoratorBehaviors,
|
|
340
128
|
...abstractDeleteBehaviors,
|
|
129
|
+
...abstractDeserializeBehaviors,
|
|
341
130
|
...abstractInsertBehaviors,
|
|
342
131
|
...abstractKeyboardBehaviors,
|
|
343
132
|
...abstractListItemBehaviors,
|
|
344
133
|
...abstractMoveBehaviors,
|
|
345
134
|
...abstractStyleBehaviors,
|
|
346
135
|
...abstractSelectBehaviors,
|
|
136
|
+
...abstractSerializeBehaviors,
|
|
347
137
|
...abstractSplitBehaviors,
|
|
348
|
-
raiseDeserializationSuccessOrFailure,
|
|
349
|
-
raiseSerializationSuccessOrFailure,
|
|
350
138
|
]
|