@portabletext/editor 3.0.7 → 3.0.9
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-es/util.slice-blocks.js +45 -33
- package/lib/_chunks-es/util.slice-blocks.js.map +1 -1
- package/lib/_chunks-es/util.slice-text-block.js.map +1 -1
- package/lib/index.js +93 -78
- package/lib/index.js.map +1 -1
- package/lib/utils/index.d.ts +1 -1
- package/package.json +8 -8
- package/src/converters/converter.portable-text.deserialize.test.ts +0 -13
- package/src/editor/Editable.tsx +5 -4
- package/src/editor/plugins/createWithPortableTextMarkModel.ts +19 -0
- package/src/internal-utils/__tests__/values.test.ts +0 -2
- package/src/internal-utils/values.test.ts +0 -7
- package/src/internal-utils/values.ts +70 -26
- package/src/operations/behavior.operation.block.set.ts +82 -27
- package/src/operations/behavior.operation.block.unset.ts +26 -58
- package/src/operations/behavior.operation.insert.block.ts +4 -4
- package/src/utils/parse-blocks.test.ts +0 -16
- package/src/utils/parse-blocks.ts +70 -50
- package/src/utils/util.is-empty-text-block.ts +1 -1
- package/src/behaviors/behavior.decorator-pair.ts +0 -212
- package/src/behaviors/behavior.markdown.ts +0 -478
- package/src/internal-utils/get-text-to-emphasize.test.ts +0 -60
- package/src/internal-utils/get-text-to-emphasize.ts +0 -40
package/lib/utils/index.d.ts
CHANGED
|
@@ -115,7 +115,7 @@ declare function getTextBlockText(block: PortableTextTextBlock): string;
|
|
|
115
115
|
/**
|
|
116
116
|
* @public
|
|
117
117
|
*/
|
|
118
|
-
declare function isEmptyTextBlock(context: Pick<EditorContext, 'schema'>, block: PortableTextBlock): boolean;
|
|
118
|
+
declare function isEmptyTextBlock(context: Pick<EditorContext, 'schema'>, block: PortableTextBlock | unknown): boolean;
|
|
119
119
|
/**
|
|
120
120
|
* @public
|
|
121
121
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@portabletext/editor",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.9",
|
|
4
4
|
"description": "Portable Text Editor made in React",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"sanity",
|
|
@@ -73,7 +73,7 @@
|
|
|
73
73
|
"slate-dom": "^0.119.0",
|
|
74
74
|
"slate-react": "0.119.0",
|
|
75
75
|
"xstate": "^5.24.0",
|
|
76
|
-
"@portabletext/block-tools": "^4.1.
|
|
76
|
+
"@portabletext/block-tools": "^4.1.3",
|
|
77
77
|
"@portabletext/keyboard-shortcuts": "^2.1.0",
|
|
78
78
|
"@portabletext/patches": "^2.0.0",
|
|
79
79
|
"@portabletext/schema": "^2.0.0"
|
|
@@ -81,8 +81,8 @@
|
|
|
81
81
|
"devDependencies": {
|
|
82
82
|
"@sanity/diff-match-patch": "^3.2.0",
|
|
83
83
|
"@sanity/pkg-utils": "^9.0.3",
|
|
84
|
-
"@sanity/schema": "^4.
|
|
85
|
-
"@sanity/types": "^4.
|
|
84
|
+
"@sanity/schema": "^4.19.0",
|
|
85
|
+
"@sanity/types": "^4.19.0",
|
|
86
86
|
"@types/debug": "^4.1.12",
|
|
87
87
|
"@types/lodash": "^4.17.20",
|
|
88
88
|
"@types/lodash.startcase": "^4.4.9",
|
|
@@ -106,14 +106,14 @@
|
|
|
106
106
|
"vite": "^7.1.12",
|
|
107
107
|
"vitest": "^4.0.9",
|
|
108
108
|
"vitest-browser-react": "^2.0.2",
|
|
109
|
-
"@portabletext/sanity-bridge": "1.2.
|
|
109
|
+
"@portabletext/sanity-bridge": "1.2.6",
|
|
110
110
|
"@portabletext/test": "^1.0.0",
|
|
111
111
|
"racejar": "2.0.0"
|
|
112
112
|
},
|
|
113
113
|
"peerDependencies": {
|
|
114
|
-
"@portabletext/sanity-bridge": "^1.2.
|
|
115
|
-
"@sanity/schema": "^4.
|
|
116
|
-
"@sanity/types": "^4.
|
|
114
|
+
"@portabletext/sanity-bridge": "^1.2.6",
|
|
115
|
+
"@sanity/schema": "^4.19.0",
|
|
116
|
+
"@sanity/types": "^4.19.0",
|
|
117
117
|
"react": "^18.3 || ^19",
|
|
118
118
|
"rxjs": "^7.8.2"
|
|
119
119
|
},
|
|
@@ -81,7 +81,6 @@ describe(converterPortableText.deserialize, () => {
|
|
|
81
81
|
marks: [],
|
|
82
82
|
},
|
|
83
83
|
],
|
|
84
|
-
markDefs: [],
|
|
85
84
|
},
|
|
86
85
|
],
|
|
87
86
|
})
|
|
@@ -117,7 +116,6 @@ describe(converterPortableText.deserialize, () => {
|
|
|
117
116
|
marks: [],
|
|
118
117
|
},
|
|
119
118
|
],
|
|
120
|
-
markDefs: [],
|
|
121
119
|
},
|
|
122
120
|
],
|
|
123
121
|
})
|
|
@@ -263,8 +261,6 @@ describe(converterPortableText.deserialize, () => {
|
|
|
263
261
|
marks: [],
|
|
264
262
|
},
|
|
265
263
|
],
|
|
266
|
-
markDefs: [],
|
|
267
|
-
style: 'normal',
|
|
268
264
|
},
|
|
269
265
|
])
|
|
270
266
|
})
|
|
@@ -299,8 +295,6 @@ describe(converterPortableText.deserialize, () => {
|
|
|
299
295
|
marks: [],
|
|
300
296
|
},
|
|
301
297
|
],
|
|
302
|
-
markDefs: [],
|
|
303
|
-
style: 'normal',
|
|
304
298
|
},
|
|
305
299
|
])
|
|
306
300
|
})
|
|
@@ -336,8 +330,6 @@ describe(converterPortableText.deserialize, () => {
|
|
|
336
330
|
marks: [],
|
|
337
331
|
},
|
|
338
332
|
],
|
|
339
|
-
markDefs: [],
|
|
340
|
-
style: 'normal',
|
|
341
333
|
},
|
|
342
334
|
])
|
|
343
335
|
})
|
|
@@ -377,7 +369,6 @@ describe(converterPortableText.deserialize, () => {
|
|
|
377
369
|
marks: [],
|
|
378
370
|
},
|
|
379
371
|
],
|
|
380
|
-
markDefs: [],
|
|
381
372
|
style: 'h1',
|
|
382
373
|
},
|
|
383
374
|
])
|
|
@@ -415,9 +406,7 @@ describe(converterPortableText.deserialize, () => {
|
|
|
415
406
|
marks: [],
|
|
416
407
|
},
|
|
417
408
|
],
|
|
418
|
-
markDefs: [],
|
|
419
409
|
level: 1,
|
|
420
|
-
style: 'normal',
|
|
421
410
|
},
|
|
422
411
|
])
|
|
423
412
|
})
|
|
@@ -458,10 +447,8 @@ describe(converterPortableText.deserialize, () => {
|
|
|
458
447
|
marks: [],
|
|
459
448
|
},
|
|
460
449
|
],
|
|
461
|
-
markDefs: [],
|
|
462
450
|
listItem: 'bullet',
|
|
463
451
|
level: 1,
|
|
464
|
-
style: 'normal',
|
|
465
452
|
},
|
|
466
453
|
])
|
|
467
454
|
})
|
package/src/editor/Editable.tsx
CHANGED
|
@@ -25,7 +25,6 @@ import {getEventPosition} from '../internal-utils/event-position'
|
|
|
25
25
|
import {normalizeSelection} from '../internal-utils/selection'
|
|
26
26
|
import {slateRangeToSelection} from '../internal-utils/slate-utils'
|
|
27
27
|
import {toSlateRange} from '../internal-utils/to-slate-range'
|
|
28
|
-
import {isEqualToEmptyEditor} from '../internal-utils/values'
|
|
29
28
|
import type {
|
|
30
29
|
EditorSelection,
|
|
31
30
|
OnCopyFn,
|
|
@@ -41,6 +40,7 @@ import type {
|
|
|
41
40
|
ScrollSelectionIntoViewFunction,
|
|
42
41
|
} from '../types/editor'
|
|
43
42
|
import type {HotkeyOptions} from '../types/options'
|
|
43
|
+
import {isEmptyTextBlock} from '../utils'
|
|
44
44
|
import {parseBlocks} from '../utils/parse-blocks'
|
|
45
45
|
import {RenderElement} from './components/render-element'
|
|
46
46
|
import {RenderLeaf} from './components/render-leaf'
|
|
@@ -526,9 +526,10 @@ export const PortableTextEditable = forwardRef<
|
|
|
526
526
|
|
|
527
527
|
if (
|
|
528
528
|
!slateEditor.selection &&
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
editorActor.getSnapshot().context
|
|
529
|
+
slateEditor.children.length === 1 &&
|
|
530
|
+
isEmptyTextBlock(
|
|
531
|
+
editorActor.getSnapshot().context,
|
|
532
|
+
slateEditor.value.at(0),
|
|
532
533
|
)
|
|
533
534
|
) {
|
|
534
535
|
Transforms.select(slateEditor, Editor.start(slateEditor, []))
|
|
@@ -30,6 +30,9 @@ export function createWithPortableTextMarkModel(
|
|
|
30
30
|
const decorators = editorActor
|
|
31
31
|
.getSnapshot()
|
|
32
32
|
.context.schema.decorators.map((t) => t.name)
|
|
33
|
+
const defaultStyle = editorActor
|
|
34
|
+
.getSnapshot()
|
|
35
|
+
.context.schema.styles.at(0)?.name
|
|
33
36
|
|
|
34
37
|
// Extend Slate's default normalization. Merge spans with same set of .marks when doing merge_node operations, and clean up markDefs / marks
|
|
35
38
|
editor.normalizeNode = (nodeEntry) => {
|
|
@@ -74,6 +77,22 @@ export function createWithPortableTextMarkModel(
|
|
|
74
77
|
return
|
|
75
78
|
}
|
|
76
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Add missing .style to block nodes
|
|
82
|
+
*/
|
|
83
|
+
if (
|
|
84
|
+
defaultStyle &&
|
|
85
|
+
editor.isTextBlock(node) &&
|
|
86
|
+
typeof node.style === 'undefined'
|
|
87
|
+
) {
|
|
88
|
+
debug('Adding .style to block node')
|
|
89
|
+
|
|
90
|
+
withNormalizeNode(editor, () => {
|
|
91
|
+
Transforms.setNodes(editor, {style: defaultStyle}, {at: path})
|
|
92
|
+
})
|
|
93
|
+
return
|
|
94
|
+
}
|
|
95
|
+
|
|
77
96
|
/**
|
|
78
97
|
* Add missing .marks to span nodes
|
|
79
98
|
*/
|
|
@@ -32,7 +32,6 @@ describe(toSlateBlock.name, () => {
|
|
|
32
32
|
text: 'foo',
|
|
33
33
|
},
|
|
34
34
|
],
|
|
35
|
-
style: 'normal',
|
|
36
35
|
})
|
|
37
36
|
})
|
|
38
37
|
|
|
@@ -62,7 +61,6 @@ describe(toSlateBlock.name, () => {
|
|
|
62
61
|
text: 'foo',
|
|
63
62
|
},
|
|
64
63
|
],
|
|
65
|
-
style: 'normal',
|
|
66
64
|
})
|
|
67
65
|
})
|
|
68
66
|
|
|
@@ -101,7 +99,6 @@ describe(toSlateBlock.name, () => {
|
|
|
101
99
|
__inline: true,
|
|
102
100
|
},
|
|
103
101
|
],
|
|
104
|
-
style: 'normal',
|
|
105
102
|
})
|
|
106
103
|
})
|
|
107
104
|
})
|
|
@@ -148,7 +145,6 @@ describe(toSlateBlock.name, () => {
|
|
|
148
145
|
},
|
|
149
146
|
},
|
|
150
147
|
],
|
|
151
|
-
style: 'normal',
|
|
152
148
|
})
|
|
153
149
|
})
|
|
154
150
|
|
|
@@ -191,7 +187,6 @@ describe(toSlateBlock.name, () => {
|
|
|
191
187
|
},
|
|
192
188
|
},
|
|
193
189
|
],
|
|
194
|
-
style: 'normal',
|
|
195
190
|
})
|
|
196
191
|
})
|
|
197
192
|
})
|
|
@@ -238,7 +233,6 @@ describe(toSlateBlock.name, () => {
|
|
|
238
233
|
},
|
|
239
234
|
},
|
|
240
235
|
],
|
|
241
|
-
style: 'normal',
|
|
242
236
|
})
|
|
243
237
|
})
|
|
244
238
|
|
|
@@ -281,7 +275,6 @@ describe(toSlateBlock.name, () => {
|
|
|
281
275
|
},
|
|
282
276
|
},
|
|
283
277
|
],
|
|
284
|
-
style: 'normal',
|
|
285
278
|
})
|
|
286
279
|
})
|
|
287
280
|
})
|
|
@@ -35,7 +35,6 @@ export function toSlateBlock(
|
|
|
35
35
|
if (isPortableText) {
|
|
36
36
|
const textBlock = block as PortableTextTextBlock
|
|
37
37
|
let hasInlines = false
|
|
38
|
-
const hasMissingStyle = typeof textBlock.style === 'undefined'
|
|
39
38
|
const hasMissingMarkDefs = typeof textBlock.markDefs === 'undefined'
|
|
40
39
|
const hasMissingChildren = typeof textBlock.children === 'undefined'
|
|
41
40
|
|
|
@@ -86,7 +85,6 @@ export function toSlateBlock(
|
|
|
86
85
|
|
|
87
86
|
// Return original block
|
|
88
87
|
if (
|
|
89
|
-
!hasMissingStyle &&
|
|
90
88
|
!hasMissingMarkDefs &&
|
|
91
89
|
!hasMissingChildren &&
|
|
92
90
|
!hasInlines &&
|
|
@@ -96,11 +94,6 @@ export function toSlateBlock(
|
|
|
96
94
|
return block
|
|
97
95
|
}
|
|
98
96
|
|
|
99
|
-
// TODO: remove this when we have a better way to handle missing style
|
|
100
|
-
if (hasMissingStyle) {
|
|
101
|
-
rest.style = schemaTypes.styles[0].name
|
|
102
|
-
}
|
|
103
|
-
|
|
104
97
|
return keepObjectEquality(
|
|
105
98
|
{_type, _key, ...rest, children},
|
|
106
99
|
keyMap,
|
|
@@ -176,25 +169,76 @@ export function fromSlateBlock(
|
|
|
176
169
|
}
|
|
177
170
|
|
|
178
171
|
export function isEqualToEmptyEditor(
|
|
179
|
-
|
|
172
|
+
blocks: Array<Descendant> | Array<PortableTextBlock>,
|
|
180
173
|
schemaTypes: EditorSchema,
|
|
181
174
|
): boolean {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
175
|
+
// Must have exactly one block
|
|
176
|
+
if (blocks.length !== 1) {
|
|
177
|
+
return false
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const firstBlock = blocks.at(0)
|
|
181
|
+
|
|
182
|
+
if (!firstBlock) {
|
|
183
|
+
return true
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (!Element.isElement(firstBlock)) {
|
|
187
|
+
return false
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Must be a text block
|
|
191
|
+
if (firstBlock._type !== schemaTypes.block.name) {
|
|
192
|
+
return false
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
// Must not be a list item
|
|
196
|
+
if ('listItem' in firstBlock) {
|
|
197
|
+
return false
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Style must exist and be the default style
|
|
201
|
+
if (
|
|
202
|
+
!('style' in firstBlock) ||
|
|
203
|
+
firstBlock.style !== schemaTypes.styles.at(0)?.name
|
|
204
|
+
) {
|
|
205
|
+
return false
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Must have children array
|
|
209
|
+
if (!Array.isArray(firstBlock.children)) {
|
|
210
|
+
return false
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Must have exactly one child
|
|
214
|
+
if (firstBlock.children.length !== 1) {
|
|
215
|
+
return false
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
const firstChild = firstBlock.children.at(0)
|
|
219
|
+
|
|
220
|
+
if (!firstChild) {
|
|
221
|
+
return false
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (!Text.isText(firstChild)) {
|
|
225
|
+
return false
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Must be a span type
|
|
229
|
+
if (!('_type' in firstChild) || firstChild._type !== schemaTypes.span.name) {
|
|
230
|
+
return false
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
// Must have empty text
|
|
234
|
+
if (firstChild.text !== '') {
|
|
235
|
+
return false
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Must have no marks (marks can be undefined or empty array)
|
|
239
|
+
if (firstChild.marks?.join('')) {
|
|
240
|
+
return false
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return true
|
|
200
244
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import {applyAll, set} from '@portabletext/patches'
|
|
2
|
+
import {isTextBlock} from '@portabletext/schema'
|
|
3
|
+
import {Transforms, type Node} from 'slate'
|
|
4
|
+
import {parseMarkDefs} from '../utils/parse-blocks'
|
|
4
5
|
import type {BehaviorOperationImplementation} from './behavior.operations'
|
|
5
6
|
|
|
6
7
|
export const blockSetOperationImplementation: BehaviorOperationImplementation<
|
|
@@ -14,36 +15,90 @@ export const blockSetOperationImplementation: BehaviorOperationImplementation<
|
|
|
14
15
|
)
|
|
15
16
|
}
|
|
16
17
|
|
|
17
|
-
const
|
|
18
|
+
const slateBlock = operation.editor.children.at(blockIndex)
|
|
18
19
|
|
|
19
|
-
if (!
|
|
20
|
+
if (!slateBlock) {
|
|
20
21
|
throw new Error(`Unable to find block at ${JSON.stringify(operation.at)}`)
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
if (isTextBlock(context, slateBlock)) {
|
|
25
|
+
const filteredProps: Record<string, unknown> = {}
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
27
|
+
for (const key of Object.keys(operation.props)) {
|
|
28
|
+
if (key === '_type' || key === 'children') {
|
|
29
|
+
continue
|
|
30
|
+
}
|
|
29
31
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
32
|
+
if (key === 'style') {
|
|
33
|
+
if (
|
|
34
|
+
context.schema.styles.some(
|
|
35
|
+
(style) => style.name === operation.props[key],
|
|
36
|
+
)
|
|
37
|
+
) {
|
|
38
|
+
filteredProps[key] = operation.props[key]
|
|
39
|
+
}
|
|
40
|
+
continue
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (key === 'listItem') {
|
|
44
|
+
if (
|
|
45
|
+
context.schema.lists.some(
|
|
46
|
+
(list) => list.name === operation.props[key],
|
|
47
|
+
)
|
|
48
|
+
) {
|
|
49
|
+
filteredProps[key] = operation.props[key]
|
|
50
|
+
}
|
|
51
|
+
continue
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (key === 'level') {
|
|
55
|
+
filteredProps[key] = operation.props[key]
|
|
56
|
+
continue
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (key === 'markDefs') {
|
|
60
|
+
const {markDefs} = parseMarkDefs({
|
|
61
|
+
context,
|
|
62
|
+
markDefs: operation.props[key],
|
|
63
|
+
options: {validateFields: true},
|
|
64
|
+
})
|
|
65
|
+
filteredProps[key] = markDefs
|
|
66
|
+
continue
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (context.schema.block.fields?.some((field) => field.name === key)) {
|
|
70
|
+
filteredProps[key] = operation.props[key]
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
Transforms.setNodes(operation.editor, filteredProps, {at: [blockIndex]})
|
|
75
|
+
} else {
|
|
76
|
+
const schemaDefinition = context.schema.blockObjects.find(
|
|
77
|
+
(definition) => definition.name === slateBlock._type,
|
|
78
|
+
)
|
|
79
|
+
const filteredProps: Record<string, unknown> = {}
|
|
80
|
+
|
|
81
|
+
for (const key of Object.keys(operation.props)) {
|
|
82
|
+
if (key === '_type') {
|
|
83
|
+
continue
|
|
84
|
+
}
|
|
43
85
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
86
|
+
if (key === '_key') {
|
|
87
|
+
filteredProps[key] = operation.props[key]
|
|
88
|
+
continue
|
|
89
|
+
}
|
|
47
90
|
|
|
48
|
-
|
|
91
|
+
if (schemaDefinition?.fields.some((field) => field.name === key)) {
|
|
92
|
+
filteredProps[key] = operation.props[key]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const patches = Object.entries(filteredProps).map(([key, value]) =>
|
|
97
|
+
key === '_key' ? set(value, ['_key']) : set(value, ['value', key]),
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
const updatedSlateBlock = applyAll(slateBlock, patches) as Partial<Node>
|
|
101
|
+
|
|
102
|
+
Transforms.setNodes(operation.editor, updatedSlateBlock, {at: [blockIndex]})
|
|
103
|
+
}
|
|
49
104
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
+
import {applyAll, set, unset} from '@portabletext/patches'
|
|
1
2
|
import {isTextBlock} from '@portabletext/schema'
|
|
2
|
-
import {
|
|
3
|
-
import {Transforms} from 'slate'
|
|
4
|
-
import {parseBlock} from '../utils/parse-blocks'
|
|
3
|
+
import {Transforms, type Node} from 'slate'
|
|
5
4
|
import type {BehaviorOperationImplementation} from './behavior.operations'
|
|
6
5
|
|
|
7
6
|
export const blockUnsetOperationImplementation: BehaviorOperationImplementation<
|
|
@@ -14,73 +13,42 @@ export const blockUnsetOperationImplementation: BehaviorOperationImplementation<
|
|
|
14
13
|
throw new Error(`Unable to find block index for block key ${blockKey}`)
|
|
15
14
|
}
|
|
16
15
|
|
|
17
|
-
const
|
|
18
|
-
blockIndex !== undefined
|
|
16
|
+
const slateBlock =
|
|
17
|
+
blockIndex !== undefined
|
|
18
|
+
? operation.editor.children.at(blockIndex)
|
|
19
|
+
: undefined
|
|
19
20
|
|
|
20
|
-
if (!
|
|
21
|
+
if (!slateBlock) {
|
|
21
22
|
throw new Error(`Unable to find block at ${JSON.stringify(operation.at)}`)
|
|
22
23
|
}
|
|
23
24
|
|
|
24
|
-
if (isTextBlock(context,
|
|
25
|
-
const propsToRemove = operation.props.filter(
|
|
25
|
+
if (isTextBlock(context, slateBlock)) {
|
|
26
|
+
const propsToRemove = operation.props.filter(
|
|
27
|
+
(prop) => prop !== '_type' && prop !== '_key' && prop !== 'children',
|
|
28
|
+
)
|
|
26
29
|
|
|
27
|
-
|
|
28
|
-
context,
|
|
29
|
-
block: omit(block, propsToRemove),
|
|
30
|
-
options: {
|
|
31
|
-
normalize: false,
|
|
32
|
-
removeUnusedMarkDefs: true,
|
|
33
|
-
validateFields: true,
|
|
34
|
-
},
|
|
35
|
-
})
|
|
30
|
+
Transforms.unsetNodes(operation.editor, propsToRemove, {at: [blockIndex]})
|
|
36
31
|
|
|
37
|
-
if (
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
if (operation.props.includes('_key')) {
|
|
33
|
+
Transforms.setNodes(
|
|
34
|
+
operation.editor,
|
|
35
|
+
{_key: context.keyGenerator()},
|
|
36
|
+
{at: [blockIndex]},
|
|
40
37
|
)
|
|
41
38
|
}
|
|
42
39
|
|
|
43
|
-
const propsToSet: Record<string, unknown> = {}
|
|
44
|
-
|
|
45
|
-
for (const prop of propsToRemove) {
|
|
46
|
-
if (!(prop in updatedTextBlock)) {
|
|
47
|
-
propsToSet[prop] = undefined
|
|
48
|
-
} else {
|
|
49
|
-
propsToSet[prop] = (updatedTextBlock as Record<string, unknown>)[prop]
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
Transforms.setNodes(operation.editor, propsToSet, {at: [blockIndex]})
|
|
54
|
-
|
|
55
40
|
return
|
|
56
41
|
}
|
|
57
42
|
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
normalize: false,
|
|
66
|
-
removeUnusedMarkDefs: true,
|
|
67
|
-
validateFields: true,
|
|
68
|
-
},
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
if (!updatedBlockObject) {
|
|
72
|
-
throw new Error(`Unable to update block at ${JSON.stringify(operation.at)}`)
|
|
73
|
-
}
|
|
43
|
+
const patches = operation.props.flatMap((key) =>
|
|
44
|
+
key === '_type'
|
|
45
|
+
? []
|
|
46
|
+
: key === '_key'
|
|
47
|
+
? set(context.keyGenerator(), ['_key'])
|
|
48
|
+
: unset(['value', key]),
|
|
49
|
+
)
|
|
74
50
|
|
|
75
|
-
const
|
|
51
|
+
const updatedSlateBlock = applyAll(slateBlock, patches) as Partial<Node>
|
|
76
52
|
|
|
77
|
-
Transforms.setNodes(
|
|
78
|
-
operation.editor,
|
|
79
|
-
{
|
|
80
|
-
_type,
|
|
81
|
-
_key,
|
|
82
|
-
value: props,
|
|
83
|
-
},
|
|
84
|
-
{at: [blockIndex]},
|
|
85
|
-
)
|
|
53
|
+
Transforms.setNodes(operation.editor, updatedSlateBlock, {at: [blockIndex]})
|
|
86
54
|
}
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import {DOMEditor} from 'slate-dom'
|
|
13
13
|
import {getFocusBlock, getFocusChild} from '../internal-utils/slate-utils'
|
|
14
14
|
import {toSlateRange} from '../internal-utils/to-slate-range'
|
|
15
|
-
import {
|
|
15
|
+
import {toSlateBlock} from '../internal-utils/values'
|
|
16
16
|
import type {EditorSelection, PortableTextSlateEditor} from '../types/editor'
|
|
17
17
|
import {parseBlock} from '../utils/parse-blocks'
|
|
18
18
|
import {isEmptyTextBlock} from '../utils/util.is-empty-text-block'
|
|
@@ -121,7 +121,7 @@ export function insertBlock(options: {
|
|
|
121
121
|
} else {
|
|
122
122
|
// placement === 'auto'
|
|
123
123
|
|
|
124
|
-
if (
|
|
124
|
+
if (isEmptyTextBlock(context, endBlock)) {
|
|
125
125
|
Transforms.insertNodes(editor, [block], {
|
|
126
126
|
at: endBlockPath,
|
|
127
127
|
select: false,
|
|
@@ -234,7 +234,7 @@ export function insertBlock(options: {
|
|
|
234
234
|
Transforms.select(editor, atAfterInsert)
|
|
235
235
|
}
|
|
236
236
|
|
|
237
|
-
if (
|
|
237
|
+
if (isEmptyTextBlock(context, focusBlock)) {
|
|
238
238
|
Transforms.removeNodes(editor, {at: focusBlockPath})
|
|
239
239
|
}
|
|
240
240
|
|
|
@@ -244,7 +244,7 @@ export function insertBlock(options: {
|
|
|
244
244
|
if (editor.isTextBlock(endBlock) && editor.isTextBlock(block)) {
|
|
245
245
|
const selectionStartPoint = Range.start(at)
|
|
246
246
|
|
|
247
|
-
if (
|
|
247
|
+
if (isEmptyTextBlock(context, endBlock)) {
|
|
248
248
|
Transforms.insertNodes(editor, [block], {
|
|
249
249
|
at: endBlockPath,
|
|
250
250
|
select: false,
|