@portabletext/editor 2.7.1 → 2.8.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/selector.is-selecting-entire-blocks.cjs +3 -1
- package/lib/_chunks-cjs/selector.is-selecting-entire-blocks.cjs.map +1 -1
- package/lib/_chunks-cjs/util.slice-blocks.cjs +60 -6
- package/lib/_chunks-cjs/util.slice-blocks.cjs.map +1 -1
- package/lib/_chunks-dts/behavior.types.action.d.cts +95 -95
- package/lib/_chunks-dts/behavior.types.action.d.ts +86 -86
- package/lib/_chunks-es/selector.is-selecting-entire-blocks.js +4 -2
- package/lib/_chunks-es/selector.is-selecting-entire-blocks.js.map +1 -1
- package/lib/_chunks-es/util.slice-blocks.js +56 -5
- package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
- package/lib/index.cjs +94 -121
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +90 -118
- package/lib/index.js.map +1 -1
- package/lib/plugins/index.d.cts +3 -3
- package/lib/selectors/index.d.cts +13 -3
- package/lib/selectors/index.d.ts +13 -3
- package/package.json +12 -13
- package/src/behaviors/behavior.abstract.insert.ts +58 -1
- package/src/behaviors/behavior.core.annotations.ts +24 -2
- package/src/behaviors/behavior.core.ts +1 -1
- package/src/behaviors/behavior.types.event.ts +18 -18
- package/src/converters/converter.text-html.serialize.test.ts +27 -17
- package/src/converters/converter.text-plain.test.ts +1 -1
- package/src/editor/plugins/createWithEditableAPI.ts +16 -0
- package/src/internal-utils/parse-blocks.ts +2 -1
- package/src/operations/behavior.operation.annotation.add.ts +1 -12
- package/src/operations/behavior.operations.ts +0 -18
- package/src/selectors/selector.is-active-annotation.test.ts +320 -0
- package/src/selectors/selector.is-active-annotation.ts +24 -0
- package/src/utils/util.slice-blocks.test.ts +39 -5
- package/src/utils/util.slice-blocks.ts +36 -3
- package/src/editor/__tests__/PortableTextEditor.test.tsx +0 -430
- package/src/editor/__tests__/PortableTextEditorTester.tsx +0 -58
- package/src/editor/__tests__/RangeDecorations.test.tsx +0 -213
- package/src/editor/__tests__/insert-block.test.tsx +0 -224
- package/src/editor/__tests__/self-solving.test.tsx +0 -183
- package/src/editor/plugins/__tests__/withEditableAPIDelete.test.tsx +0 -298
- package/src/editor/plugins/__tests__/withEditableAPIGetFragment.test.tsx +0 -177
- package/src/editor/plugins/__tests__/withEditableAPIInsert.test.tsx +0 -538
- package/src/editor/plugins/__tests__/withEditableAPISelectionsOverlapping.test.tsx +0 -162
- package/src/editor/plugins/__tests__/withPortableTextLists.test.tsx +0 -65
- package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +0 -612
- package/src/editor/plugins/__tests__/withPortableTextSelections.test.tsx +0 -103
- package/src/editor/plugins/__tests__/withUndoRedo.test.tsx +0 -147
- package/src/internal-utils/__tests__/valueNormalization.test.tsx +0 -79
- package/src/operations/behavior.operation.insert-inline-object.ts +0 -59
- package/src/operations/behavior.operation.insert-span.ts +0 -48
package/lib/plugins/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Behavior, Editor, EditorEmittedEvent, EditorSchema } from "../_chunks-dts/behavior.types.action.cjs";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react21 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
|
+
}): react21.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(): react21.JSX.Element;
|
|
196
196
|
export { BehaviorPlugin, DecoratorShortcutPlugin, EditorRefPlugin, EventListenerPlugin, MarkdownPlugin, type MarkdownPluginConfig, OneLinePlugin };
|
|
@@ -242,9 +242,19 @@ declare const getTrimmedSelection: EditorSelector<EditorSelection>;
|
|
|
242
242
|
*/
|
|
243
243
|
declare const getValue: EditorSelector<Array<PortableTextBlock>>;
|
|
244
244
|
/**
|
|
245
|
-
*
|
|
246
|
-
|
|
247
|
-
|
|
245
|
+
* Check whether an annotation is active in the given `snapshot`.
|
|
246
|
+
*
|
|
247
|
+
* @public
|
|
248
|
+
*/
|
|
249
|
+
declare function isActiveAnnotation(annotation: string, options?: {
|
|
250
|
+
/**
|
|
251
|
+
* Choose whether the annotation has to take up the entire selection in the
|
|
252
|
+
* `snapshot` or if the annotation can be partially selected.
|
|
253
|
+
*
|
|
254
|
+
* Defaults to 'full'
|
|
255
|
+
*/
|
|
256
|
+
mode?: 'partial' | 'full';
|
|
257
|
+
}): EditorSelector<boolean>;
|
|
248
258
|
/**
|
|
249
259
|
* @public
|
|
250
260
|
*/
|
package/lib/selectors/index.d.ts
CHANGED
|
@@ -242,9 +242,19 @@ declare const getTrimmedSelection: EditorSelector<EditorSelection>;
|
|
|
242
242
|
*/
|
|
243
243
|
declare const getValue: EditorSelector<Array<PortableTextBlock>>;
|
|
244
244
|
/**
|
|
245
|
-
*
|
|
246
|
-
|
|
247
|
-
|
|
245
|
+
* Check whether an annotation is active in the given `snapshot`.
|
|
246
|
+
*
|
|
247
|
+
* @public
|
|
248
|
+
*/
|
|
249
|
+
declare function isActiveAnnotation(annotation: string, options?: {
|
|
250
|
+
/**
|
|
251
|
+
* Choose whether the annotation has to take up the entire selection in the
|
|
252
|
+
* `snapshot` or if the annotation can be partially selected.
|
|
253
|
+
*
|
|
254
|
+
* Defaults to 'full'
|
|
255
|
+
*/
|
|
256
|
+
mode?: 'partial' | 'full';
|
|
257
|
+
}): EditorSelector<boolean>;
|
|
248
258
|
/**
|
|
249
259
|
* @public
|
|
250
260
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.8.0",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"@xstate/react": "^6.0.0",
|
|
72
72
|
"debug": "^4.4.1",
|
|
73
73
|
"get-random-values-esm": "^1.0.2",
|
|
74
|
-
"immer": "^10.1.
|
|
74
|
+
"immer": "^10.1.3",
|
|
75
75
|
"lodash": "^4.17.21",
|
|
76
76
|
"lodash.startcase": "^4.4.0",
|
|
77
77
|
"react-compiler-runtime": "19.1.0-rc.3",
|
|
@@ -79,17 +79,16 @@
|
|
|
79
79
|
"slate-dom": "^0.118.1",
|
|
80
80
|
"slate-react": "0.117.4",
|
|
81
81
|
"xstate": "^5.21.0",
|
|
82
|
-
"@portabletext/block-tools": "^3.5.
|
|
83
|
-
"@portabletext/keyboard-shortcuts": "^1.1.1",
|
|
82
|
+
"@portabletext/block-tools": "^3.5.3",
|
|
84
83
|
"@portabletext/patches": "^1.1.8",
|
|
85
|
-
"@portabletext/schema": "^1.2.0"
|
|
84
|
+
"@portabletext/schema": "^1.2.0",
|
|
85
|
+
"@portabletext/keyboard-shortcuts": "^1.1.1"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
88
|
"@sanity/diff-match-patch": "^3.2.0",
|
|
89
89
|
"@sanity/pkg-utils": "^8.1.4",
|
|
90
|
-
"@sanity/schema": "^4.6.
|
|
91
|
-
"@sanity/types": "^4.6.
|
|
92
|
-
"@testing-library/react": "^16.3.0",
|
|
90
|
+
"@sanity/schema": "^4.6.1",
|
|
91
|
+
"@sanity/types": "^4.6.1",
|
|
93
92
|
"@types/debug": "^4.1.12",
|
|
94
93
|
"@types/lodash": "^4.17.20",
|
|
95
94
|
"@types/lodash.startcase": "^4.4.9",
|
|
@@ -111,14 +110,14 @@
|
|
|
111
110
|
"vite": "^7.1.3",
|
|
112
111
|
"vitest": "^3.2.4",
|
|
113
112
|
"vitest-browser-react": "^1.0.1",
|
|
114
|
-
"@portabletext/sanity-bridge": "1.1.7",
|
|
115
113
|
"@portabletext/test": "^0.0.0",
|
|
116
|
-
"racejar": "1.2.
|
|
114
|
+
"racejar": "1.2.15",
|
|
115
|
+
"@portabletext/sanity-bridge": "1.1.8"
|
|
117
116
|
},
|
|
118
117
|
"peerDependencies": {
|
|
119
|
-
"@portabletext/sanity-bridge": "^1.1.
|
|
120
|
-
"@sanity/schema": "^4.6.
|
|
121
|
-
"@sanity/types": "^4.6.
|
|
118
|
+
"@portabletext/sanity-bridge": "^1.1.8",
|
|
119
|
+
"@sanity/schema": "^4.6.1",
|
|
120
|
+
"@sanity/types": "^4.6.1",
|
|
122
121
|
"react": "^18.3 || ^19",
|
|
123
122
|
"rxjs": "^7.8.2"
|
|
124
123
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {getFocusTextBlock} from '../selectors'
|
|
2
2
|
import {isEmptyTextBlock} from '../utils'
|
|
3
|
-
import {raise} from './behavior.types.action'
|
|
3
|
+
import {execute, raise} from './behavior.types.action'
|
|
4
4
|
import {defineBehavior} from './behavior.types.behavior'
|
|
5
5
|
|
|
6
6
|
export const abstractInsertBehaviors = [
|
|
@@ -129,8 +129,65 @@ export const abstractInsertBehaviors = [
|
|
|
129
129
|
on: 'insert.break',
|
|
130
130
|
actions: [() => [raise({type: 'split'})]],
|
|
131
131
|
}),
|
|
132
|
+
defineBehavior({
|
|
133
|
+
on: 'insert.inline object',
|
|
134
|
+
actions: [
|
|
135
|
+
({snapshot, event}) => [
|
|
136
|
+
execute({
|
|
137
|
+
type: 'insert.block',
|
|
138
|
+
block: {
|
|
139
|
+
_type: snapshot.context.schema.block.name,
|
|
140
|
+
children: [
|
|
141
|
+
{
|
|
142
|
+
_type: event.inlineObject.name,
|
|
143
|
+
...event.inlineObject.value,
|
|
144
|
+
},
|
|
145
|
+
],
|
|
146
|
+
},
|
|
147
|
+
placement: 'auto',
|
|
148
|
+
select: 'end',
|
|
149
|
+
}),
|
|
150
|
+
],
|
|
151
|
+
],
|
|
152
|
+
}),
|
|
132
153
|
defineBehavior({
|
|
133
154
|
on: 'insert.soft break',
|
|
134
155
|
actions: [() => [raise({type: 'insert.text', text: '\n'})]],
|
|
135
156
|
}),
|
|
157
|
+
defineBehavior({
|
|
158
|
+
on: 'insert.span',
|
|
159
|
+
guard: ({snapshot, event}) => {
|
|
160
|
+
const markDefs =
|
|
161
|
+
event.annotations?.map((annotation) => ({
|
|
162
|
+
_type: annotation.name,
|
|
163
|
+
_key: snapshot.context.keyGenerator(),
|
|
164
|
+
...annotation.value,
|
|
165
|
+
})) ?? []
|
|
166
|
+
|
|
167
|
+
return {markDefs}
|
|
168
|
+
},
|
|
169
|
+
actions: [
|
|
170
|
+
({snapshot, event}, {markDefs}) => [
|
|
171
|
+
execute({
|
|
172
|
+
type: 'insert.block',
|
|
173
|
+
block: {
|
|
174
|
+
_type: snapshot.context.schema.block.name,
|
|
175
|
+
children: [
|
|
176
|
+
{
|
|
177
|
+
_type: snapshot.context.schema.span.name,
|
|
178
|
+
text: event.text,
|
|
179
|
+
marks: [
|
|
180
|
+
...(event.decorators ?? []),
|
|
181
|
+
...markDefs.map((markDef) => markDef._key),
|
|
182
|
+
],
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
markDefs,
|
|
186
|
+
},
|
|
187
|
+
placement: 'auto',
|
|
188
|
+
select: 'end',
|
|
189
|
+
}),
|
|
190
|
+
],
|
|
191
|
+
],
|
|
192
|
+
}),
|
|
136
193
|
]
|
|
@@ -34,6 +34,28 @@ const addAnnotationOnCollapsedSelection = defineBehavior({
|
|
|
34
34
|
],
|
|
35
35
|
})
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
/**
|
|
38
|
+
* By default, same-type annotations can overlap. This Core Behavior ensures
|
|
39
|
+
* that annotations of the same type are mutually exclusive.
|
|
40
|
+
*/
|
|
41
|
+
const preventOverlappingAnnotations = defineBehavior({
|
|
42
|
+
// Given an `annotation.add` event
|
|
43
|
+
on: 'annotation.add',
|
|
44
|
+
// When the annotation is active in the selection
|
|
45
|
+
guard: ({snapshot, event}) =>
|
|
46
|
+
selectors.isActiveAnnotation(event.annotation.name, {mode: 'partial'})(
|
|
47
|
+
snapshot,
|
|
48
|
+
),
|
|
49
|
+
// Then the existing annotation is removed
|
|
50
|
+
actions: [
|
|
51
|
+
({event}) => [
|
|
52
|
+
raise({type: 'annotation.remove', annotation: event.annotation}),
|
|
53
|
+
raise(event),
|
|
54
|
+
],
|
|
55
|
+
],
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
export const coreAnnotationBehaviors = [
|
|
38
59
|
addAnnotationOnCollapsedSelection,
|
|
39
|
-
|
|
60
|
+
preventOverlappingAnnotations,
|
|
61
|
+
]
|
|
@@ -7,7 +7,7 @@ import {coreInsertBreakBehaviors} from './behavior.core.insert-break'
|
|
|
7
7
|
import {coreListBehaviors} from './behavior.core.lists'
|
|
8
8
|
|
|
9
9
|
export const coreBehaviorsConfig = [
|
|
10
|
-
coreAnnotationBehaviors
|
|
10
|
+
...coreAnnotationBehaviors,
|
|
11
11
|
coreDecoratorBehaviors.strongShortcut,
|
|
12
12
|
coreDecoratorBehaviors.emShortcut,
|
|
13
13
|
coreDecoratorBehaviors.underlineShortcut,
|
|
@@ -71,9 +71,7 @@ const syntheticBehaviorEventTypes = [
|
|
|
71
71
|
'delete',
|
|
72
72
|
'history.redo',
|
|
73
73
|
'history.undo',
|
|
74
|
-
'insert.inline object',
|
|
75
74
|
'insert.block',
|
|
76
|
-
'insert.span',
|
|
77
75
|
'insert.text',
|
|
78
76
|
'move.backward',
|
|
79
77
|
'move.block',
|
|
@@ -155,28 +153,12 @@ export type SyntheticBehaviorEvent =
|
|
|
155
153
|
| {
|
|
156
154
|
type: StrictExtract<SyntheticBehaviorEventType, 'history.undo'>
|
|
157
155
|
}
|
|
158
|
-
| {
|
|
159
|
-
type: StrictExtract<SyntheticBehaviorEventType, 'insert.inline object'>
|
|
160
|
-
inlineObject: {
|
|
161
|
-
name: string
|
|
162
|
-
value?: {[prop: string]: unknown}
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
156
|
| {
|
|
166
157
|
type: StrictExtract<SyntheticBehaviorEventType, 'insert.block'>
|
|
167
158
|
block: BlockWithOptionalKey
|
|
168
159
|
placement: InsertPlacement
|
|
169
160
|
select?: 'start' | 'end' | 'none'
|
|
170
161
|
}
|
|
171
|
-
| {
|
|
172
|
-
type: StrictExtract<SyntheticBehaviorEventType, 'insert.span'>
|
|
173
|
-
text: string
|
|
174
|
-
annotations?: Array<{
|
|
175
|
-
name: string
|
|
176
|
-
value: {[prop: string]: unknown}
|
|
177
|
-
}>
|
|
178
|
-
decorators?: Array<string>
|
|
179
|
-
}
|
|
180
162
|
| {
|
|
181
163
|
type: StrictExtract<SyntheticBehaviorEventType, 'insert.text'>
|
|
182
164
|
text: string
|
|
@@ -238,7 +220,9 @@ const abstractBehaviorEventTypes = [
|
|
|
238
220
|
'deserialization.failure',
|
|
239
221
|
'insert.blocks',
|
|
240
222
|
'insert.break',
|
|
223
|
+
'insert.inline object',
|
|
241
224
|
'insert.soft break',
|
|
225
|
+
'insert.span',
|
|
242
226
|
'list item.add',
|
|
243
227
|
'list item.remove',
|
|
244
228
|
'list item.toggle',
|
|
@@ -392,9 +376,25 @@ type AbstractBehaviorEvent =
|
|
|
392
376
|
| {
|
|
393
377
|
type: StrictExtract<SyntheticBehaviorEventType, 'insert.break'>
|
|
394
378
|
}
|
|
379
|
+
| {
|
|
380
|
+
type: StrictExtract<SyntheticBehaviorEventType, 'insert.inline object'>
|
|
381
|
+
inlineObject: {
|
|
382
|
+
name: string
|
|
383
|
+
value?: {[prop: string]: unknown}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
395
386
|
| {
|
|
396
387
|
type: StrictExtract<SyntheticBehaviorEventType, 'insert.soft break'>
|
|
397
388
|
}
|
|
389
|
+
| {
|
|
390
|
+
type: StrictExtract<SyntheticBehaviorEventType, 'insert.span'>
|
|
391
|
+
text: string
|
|
392
|
+
annotations?: Array<{
|
|
393
|
+
name: string
|
|
394
|
+
value: {[prop: string]: unknown}
|
|
395
|
+
}>
|
|
396
|
+
decorators?: Array<string>
|
|
397
|
+
}
|
|
398
398
|
| {
|
|
399
399
|
type: StrictExtract<SyntheticBehaviorEventType, 'list item.add'>
|
|
400
400
|
listItem: string
|
|
@@ -94,24 +94,29 @@ describe(converterTextHtml.serialize.name, () => {
|
|
|
94
94
|
test('paragraph with decorators', () => {
|
|
95
95
|
expect(
|
|
96
96
|
converterTextHtml.serialize({
|
|
97
|
-
snapshot: createSnapshot(
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
97
|
+
snapshot: createSnapshot(
|
|
98
|
+
defineSchema({
|
|
99
|
+
decorators: [{name: 'em'}, {name: 'code'}, {name: 'strong'}],
|
|
100
|
+
}),
|
|
101
|
+
{
|
|
102
|
+
anchor: {
|
|
103
|
+
path: [
|
|
104
|
+
{_key: decoratedParagraph._key},
|
|
105
|
+
'children',
|
|
106
|
+
{_key: decoratedParagraph.children[0]._key},
|
|
107
|
+
],
|
|
108
|
+
offset: 0,
|
|
109
|
+
},
|
|
110
|
+
focus: {
|
|
111
|
+
path: [
|
|
112
|
+
{_key: decoratedParagraph._key},
|
|
113
|
+
'children',
|
|
114
|
+
{_key: decoratedParagraph.children[2]._key},
|
|
115
|
+
],
|
|
116
|
+
offset: 4,
|
|
117
|
+
},
|
|
113
118
|
},
|
|
114
|
-
|
|
119
|
+
),
|
|
115
120
|
event: {
|
|
116
121
|
type: 'serialize',
|
|
117
122
|
originEvent: 'clipboard.copy',
|
|
@@ -181,6 +186,11 @@ describe(converterTextHtml.serialize.name, () => {
|
|
|
181
186
|
converterTextHtml.serialize({
|
|
182
187
|
snapshot: createTestSnapshot({
|
|
183
188
|
context: {
|
|
189
|
+
schema: compileSchema(
|
|
190
|
+
defineSchema({
|
|
191
|
+
lists: [{name: 'bullet'}, {name: 'number'}],
|
|
192
|
+
}),
|
|
193
|
+
),
|
|
184
194
|
converters: [],
|
|
185
195
|
value: [
|
|
186
196
|
{
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
import type {PortableTextBlock, PortableTextTextBlock} from '@sanity/types'
|
|
8
8
|
import {expect, test} from 'vitest'
|
|
9
9
|
import type {EditorSelection} from '..'
|
|
10
|
-
import {schemaDefinition} from '
|
|
10
|
+
import {schemaDefinition} from '../../tests/PortableTextEditorTester'
|
|
11
11
|
import {createTestSnapshot} from '../internal-utils/create-test-snapshot'
|
|
12
12
|
import {createConverterTextPlain} from './converter.text-plain'
|
|
13
13
|
|
|
@@ -426,6 +426,22 @@ export function createEditableAPI(
|
|
|
426
426
|
addAnnotation: (type, value) => {
|
|
427
427
|
let paths: ReturnType<EditableAPI['addAnnotation']>
|
|
428
428
|
|
|
429
|
+
const snapshot = getEditorSnapshot({
|
|
430
|
+
editorActorSnapshot: editorActor.getSnapshot(),
|
|
431
|
+
slateEditorInstance: editor,
|
|
432
|
+
})
|
|
433
|
+
|
|
434
|
+
if (isActiveAnnotation(type.name, {mode: 'partial'})(snapshot)) {
|
|
435
|
+
editorActor.send({
|
|
436
|
+
type: 'behavior event',
|
|
437
|
+
behaviorEvent: {
|
|
438
|
+
type: 'annotation.remove',
|
|
439
|
+
annotation: {name: type.name},
|
|
440
|
+
},
|
|
441
|
+
editor,
|
|
442
|
+
})
|
|
443
|
+
}
|
|
444
|
+
|
|
429
445
|
Editor.withoutNormalizing(editor, () => {
|
|
430
446
|
paths = addAnnotationOperationImplementation({
|
|
431
447
|
context: {
|
|
@@ -193,6 +193,7 @@ export function parseTextBlock({
|
|
|
193
193
|
parseInlineObject({inlineObject: child, context, options}),
|
|
194
194
|
)
|
|
195
195
|
.filter((child) => child !== undefined)
|
|
196
|
+
const marks = children.flatMap((child) => child.marks ?? [])
|
|
196
197
|
|
|
197
198
|
const parsedBlock: PortableTextTextBlock = {
|
|
198
199
|
_type: context.schema.block.name,
|
|
@@ -208,7 +209,7 @@ export function parseTextBlock({
|
|
|
208
209
|
marks: [],
|
|
209
210
|
},
|
|
210
211
|
],
|
|
211
|
-
markDefs,
|
|
212
|
+
markDefs: markDefs.filter((markDef) => marks.includes(markDef._key)),
|
|
212
213
|
...customFields,
|
|
213
214
|
}
|
|
214
215
|
|
|
@@ -116,22 +116,11 @@ export const addAnnotationOperationImplementation: BehaviorOperationImplementati
|
|
|
116
116
|
}
|
|
117
117
|
|
|
118
118
|
const marks = span.marks ?? []
|
|
119
|
-
const existingSameTypeAnnotations = marks.filter((mark) =>
|
|
120
|
-
markDefs.some(
|
|
121
|
-
(markDef) =>
|
|
122
|
-
markDef._key === mark && markDef._type === parsedAnnotation._type,
|
|
123
|
-
),
|
|
124
|
-
)
|
|
125
119
|
|
|
126
120
|
Transforms.setNodes(
|
|
127
121
|
editor,
|
|
128
122
|
{
|
|
129
|
-
marks: [
|
|
130
|
-
...marks.filter(
|
|
131
|
-
(mark) => !existingSameTypeAnnotations.includes(mark),
|
|
132
|
-
),
|
|
133
|
-
annotationKey,
|
|
134
|
-
],
|
|
123
|
+
marks: [...marks, annotationKey],
|
|
135
124
|
},
|
|
136
125
|
{at: path},
|
|
137
126
|
)
|
|
@@ -18,8 +18,6 @@ import {childSetOperationImplementation} from './behavior.operation.child.set'
|
|
|
18
18
|
import {childUnsetOperationImplementation} from './behavior.operation.child.unset'
|
|
19
19
|
import {decoratorAddOperationImplementation} from './behavior.operation.decorator.add'
|
|
20
20
|
import {deleteOperationImplementation} from './behavior.operation.delete'
|
|
21
|
-
import {insertInlineObjectOperationImplementation} from './behavior.operation.insert-inline-object'
|
|
22
|
-
import {insertSpanOperationImplementation} from './behavior.operation.insert-span'
|
|
23
21
|
import {insertBlockOperationImplementation} from './behavior.operation.insert.block'
|
|
24
22
|
import {insertTextOperationImplementation} from './behavior.operation.insert.text'
|
|
25
23
|
import {moveBackwardOperationImplementation} from './behavior.operation.move.backward'
|
|
@@ -68,8 +66,6 @@ const behaviorOperationImplementations: BehaviorOperationImplementations = {
|
|
|
68
66
|
'history.redo': historyRedoOperationImplementation,
|
|
69
67
|
'history.undo': historyUndoOperationImplementation,
|
|
70
68
|
'insert.block': insertBlockOperationImplementation,
|
|
71
|
-
'insert.inline object': insertInlineObjectOperationImplementation,
|
|
72
|
-
'insert.span': insertSpanOperationImplementation,
|
|
73
69
|
'insert.text': insertTextOperationImplementation,
|
|
74
70
|
'move.backward': moveBackwardOperationImplementation,
|
|
75
71
|
'move.block': moveBlockOperationImplementation,
|
|
@@ -170,20 +166,6 @@ export function performOperation({
|
|
|
170
166
|
})
|
|
171
167
|
break
|
|
172
168
|
}
|
|
173
|
-
case 'insert.inline object': {
|
|
174
|
-
behaviorOperationImplementations['insert.inline object']({
|
|
175
|
-
context,
|
|
176
|
-
operation: operation,
|
|
177
|
-
})
|
|
178
|
-
break
|
|
179
|
-
}
|
|
180
|
-
case 'insert.span': {
|
|
181
|
-
behaviorOperationImplementations['insert.span']({
|
|
182
|
-
context,
|
|
183
|
-
operation: operation,
|
|
184
|
-
})
|
|
185
|
-
break
|
|
186
|
-
}
|
|
187
169
|
case 'insert.text': {
|
|
188
170
|
behaviorOperationImplementations['insert.text']({
|
|
189
171
|
context,
|