@portabletext/editor 1.7.1 → 1.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/index.d.mts +24 -15
- package/lib/index.d.ts +24 -15
- package/lib/index.esm.js +111 -46
- package/lib/index.esm.js.map +1 -1
- package/lib/index.js +111 -46
- package/lib/index.js.map +1 -1
- package/lib/index.mjs +111 -46
- package/lib/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/editor/behavior/behavior.actions.ts +9 -0
- package/src/editor/behavior/behavior.markdown.ts +78 -11
- package/src/editor/behavior/behavior.types.ts +5 -0
- package/src/editor/plugins/createWithEditableAPI.ts +91 -71
- package/src/editor/plugins/with-plugins.ts +7 -2
- package/src/index.ts +1 -1
- package/src/types/options.ts +0 -9
- package/src/utils/__tests__/operationToPatches.test.ts +1 -1
- package/src/utils/__tests__/patchToOperations.test.ts +1 -1
package/lib/index.js
CHANGED
|
@@ -296,6 +296,21 @@ const breakingBlockObject = {
|
|
|
296
296
|
blockObjects: coreBlockObjectBehaviors,
|
|
297
297
|
lists: coreListBehaviors
|
|
298
298
|
};
|
|
299
|
+
function isPortableTextSpan(node) {
|
|
300
|
+
return node._type === "span" && "text" in node && typeof node.text == "string" && (typeof node.marks > "u" || Array.isArray(node.marks) && node.marks.every((mark) => typeof mark == "string"));
|
|
301
|
+
}
|
|
302
|
+
function isPortableTextBlock(node) {
|
|
303
|
+
return (
|
|
304
|
+
// A block doesn't _have_ to be named 'block' - to differentiate between
|
|
305
|
+
// allowed child types and marks, one might name them differently
|
|
306
|
+
typeof node._type == "string" && // Toolkit-types like nested spans are @-prefixed
|
|
307
|
+
node._type[0] !== "@" && // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array
|
|
308
|
+
(!("markDefs" in node) || !node.markDefs || Array.isArray(node.markDefs) && // Every mark definition needs to have an `_key` to be mappable in child spans
|
|
309
|
+
node.markDefs.every((def) => typeof def._key == "string")) && // `children` is required and needs to be an array
|
|
310
|
+
"children" in node && Array.isArray(node.children) && // All children are objects with `_type` (usually spans, but can contain other stuff)
|
|
311
|
+
node.children.every((child) => typeof child == "object" && "_type" in child)
|
|
312
|
+
);
|
|
313
|
+
}
|
|
299
314
|
function createMarkdownBehaviors(config) {
|
|
300
315
|
const automaticBlockquoteOnSpace = {
|
|
301
316
|
on: "insert text",
|
|
@@ -308,7 +323,7 @@ function createMarkdownBehaviors(config) {
|
|
|
308
323
|
const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
|
|
309
324
|
if (!selectionCollapsed || !focusTextBlock || !focusSpan)
|
|
310
325
|
return !1;
|
|
311
|
-
const caretAtTheEndOfQuote = context.selection.focus.offset === 1, looksLikeMarkdownQuote = /^>/.test(focusSpan.node.text), blockquoteStyle = config.mapBlockquoteStyle(context.schema);
|
|
326
|
+
const caretAtTheEndOfQuote = context.selection.focus.offset === 1, looksLikeMarkdownQuote = /^>/.test(focusSpan.node.text), blockquoteStyle = config.mapBlockquoteStyle?.(context.schema);
|
|
312
327
|
return caretAtTheEndOfQuote && looksLikeMarkdownQuote && blockquoteStyle !== void 0 ? {
|
|
313
328
|
focusTextBlock,
|
|
314
329
|
focusSpan,
|
|
@@ -343,6 +358,48 @@ function createMarkdownBehaviors(config) {
|
|
|
343
358
|
}
|
|
344
359
|
}
|
|
345
360
|
}]]
|
|
361
|
+
}, automaticBreak = {
|
|
362
|
+
on: "insert text",
|
|
363
|
+
guard: ({
|
|
364
|
+
context,
|
|
365
|
+
event
|
|
366
|
+
}) => {
|
|
367
|
+
if (event.text !== "-")
|
|
368
|
+
return !1;
|
|
369
|
+
const breakObject = config.mapBreakObject?.(context.schema), focusBlock = getFocusTextBlock(context), selectionCollapsed = selectionIsCollapsed(context);
|
|
370
|
+
if (!breakObject || !focusBlock || !selectionCollapsed)
|
|
371
|
+
return !1;
|
|
372
|
+
const onlyText = focusBlock.node.children.every(isPortableTextSpan), blockText = focusBlock.node.children.map((child) => child.text ?? "").join("");
|
|
373
|
+
return onlyText && blockText === "--" ? {
|
|
374
|
+
breakObject,
|
|
375
|
+
focusBlock
|
|
376
|
+
} : !1;
|
|
377
|
+
},
|
|
378
|
+
actions: [() => [{
|
|
379
|
+
type: "insert text",
|
|
380
|
+
text: "-"
|
|
381
|
+
}], (_, {
|
|
382
|
+
breakObject,
|
|
383
|
+
focusBlock
|
|
384
|
+
}) => [{
|
|
385
|
+
type: "insert block object",
|
|
386
|
+
...breakObject
|
|
387
|
+
}, {
|
|
388
|
+
type: "delete",
|
|
389
|
+
selection: {
|
|
390
|
+
anchor: {
|
|
391
|
+
path: focusBlock.path,
|
|
392
|
+
offset: 0
|
|
393
|
+
},
|
|
394
|
+
focus: {
|
|
395
|
+
path: focusBlock.path,
|
|
396
|
+
offset: 0
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}, {
|
|
400
|
+
type: "insert text block",
|
|
401
|
+
decorators: []
|
|
402
|
+
}]]
|
|
346
403
|
}, automaticHeadingOnSpace = {
|
|
347
404
|
on: "insert text",
|
|
348
405
|
guard: ({
|
|
@@ -357,7 +414,7 @@ function createMarkdownBehaviors(config) {
|
|
|
357
414
|
const markdownHeadingSearch = /^#+/.exec(focusSpan.node.text), headingLevel = markdownHeadingSearch ? markdownHeadingSearch[0].length : void 0;
|
|
358
415
|
if (context.selection.focus.offset !== headingLevel)
|
|
359
416
|
return !1;
|
|
360
|
-
const headingStyle = headingLevel !== void 0 ? config.mapHeadingStyle(context.schema, headingLevel) : void 0;
|
|
417
|
+
const headingStyle = headingLevel !== void 0 ? config.mapHeadingStyle?.(context.schema, headingLevel) : void 0;
|
|
361
418
|
return headingLevel !== void 0 && headingStyle !== void 0 ? {
|
|
362
419
|
focusTextBlock,
|
|
363
420
|
focusSpan,
|
|
@@ -402,7 +459,7 @@ function createMarkdownBehaviors(config) {
|
|
|
402
459
|
const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
|
|
403
460
|
if (!selectionCollapsed || !focusTextBlock || !focusSpan)
|
|
404
461
|
return !1;
|
|
405
|
-
const atTheBeginningOfBLock = focusTextBlock.node.children[0]._key === focusSpan.node._key && context.selection.focus.offset === 0, defaultStyle = config.mapDefaultStyle(context.schema);
|
|
462
|
+
const atTheBeginningOfBLock = focusTextBlock.node.children[0]._key === focusSpan.node._key && context.selection.focus.offset === 0, defaultStyle = config.mapDefaultStyle?.(context.schema);
|
|
406
463
|
return atTheBeginningOfBLock && defaultStyle && focusTextBlock.node.style !== defaultStyle ? {
|
|
407
464
|
defaultStyle,
|
|
408
465
|
focusTextBlock
|
|
@@ -427,7 +484,7 @@ function createMarkdownBehaviors(config) {
|
|
|
427
484
|
const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
|
|
428
485
|
if (!selectionCollapsed || !focusTextBlock || !focusSpan)
|
|
429
486
|
return !1;
|
|
430
|
-
const defaultStyle = config.mapDefaultStyle(context.schema), looksLikeUnorderedList = /^(-|\*)/.test(focusSpan.node.text), unorderedListStyle = config.mapUnorderedListStyle(context.schema), caretAtTheEndOfUnorderedList = context.selection.focus.offset === 1;
|
|
487
|
+
const defaultStyle = config.mapDefaultStyle?.(context.schema), looksLikeUnorderedList = /^(-|\*)/.test(focusSpan.node.text), unorderedListStyle = config.mapUnorderedListStyle?.(context.schema), caretAtTheEndOfUnorderedList = context.selection.focus.offset === 1;
|
|
431
488
|
if (defaultStyle && caretAtTheEndOfUnorderedList && looksLikeUnorderedList && unorderedListStyle !== void 0)
|
|
432
489
|
return {
|
|
433
490
|
focusTextBlock,
|
|
@@ -436,7 +493,7 @@ function createMarkdownBehaviors(config) {
|
|
|
436
493
|
listItemLength: 1,
|
|
437
494
|
style: defaultStyle
|
|
438
495
|
};
|
|
439
|
-
const looksLikeOrderedList = /^1./.test(focusSpan.node.text), orderedListStyle = config.mapOrderedListStyle(context.schema), caretAtTheEndOfOrderedList = context.selection.focus.offset === 2;
|
|
496
|
+
const looksLikeOrderedList = /^1./.test(focusSpan.node.text), orderedListStyle = config.mapOrderedListStyle?.(context.schema), caretAtTheEndOfOrderedList = context.selection.focus.offset === 2;
|
|
440
497
|
return defaultStyle && caretAtTheEndOfOrderedList && looksLikeOrderedList && orderedListStyle !== void 0 ? {
|
|
441
498
|
focusTextBlock,
|
|
442
499
|
focusSpan,
|
|
@@ -474,7 +531,7 @@ function createMarkdownBehaviors(config) {
|
|
|
474
531
|
}
|
|
475
532
|
}]]
|
|
476
533
|
};
|
|
477
|
-
return [automaticBlockquoteOnSpace, automaticHeadingOnSpace, clearStyleOnBackspace, automaticListOnSpace];
|
|
534
|
+
return [automaticBlockquoteOnSpace, automaticBreak, automaticHeadingOnSpace, clearStyleOnBackspace, automaticListOnSpace];
|
|
478
535
|
}
|
|
479
536
|
function getPortableTextMemberSchemaTypes(portableTextType) {
|
|
480
537
|
if (!portableTextType)
|
|
@@ -3904,21 +3961,6 @@ function createWithPortableTextLists(types2) {
|
|
|
3904
3961
|
}, editor;
|
|
3905
3962
|
};
|
|
3906
3963
|
}
|
|
3907
|
-
function isPortableTextSpan(node) {
|
|
3908
|
-
return node._type === "span" && "text" in node && typeof node.text == "string" && (typeof node.marks > "u" || Array.isArray(node.marks) && node.marks.every((mark) => typeof mark == "string"));
|
|
3909
|
-
}
|
|
3910
|
-
function isPortableTextBlock(node) {
|
|
3911
|
-
return (
|
|
3912
|
-
// A block doesn't _have_ to be named 'block' - to differentiate between
|
|
3913
|
-
// allowed child types and marks, one might name them differently
|
|
3914
|
-
typeof node._type == "string" && // Toolkit-types like nested spans are @-prefixed
|
|
3915
|
-
node._type[0] !== "@" && // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array
|
|
3916
|
-
(!("markDefs" in node) || !node.markDefs || Array.isArray(node.markDefs) && // Every mark definition needs to have an `_key` to be mappable in child spans
|
|
3917
|
-
node.markDefs.every((def) => typeof def._key == "string")) && // `children` is required and needs to be an array
|
|
3918
|
-
"children" in node && Array.isArray(node.children) && // All children are objects with `_type` (usually spans, but can contain other stuff)
|
|
3919
|
-
node.children.every((child) => typeof child == "object" && "_type" in child)
|
|
3920
|
-
);
|
|
3921
|
-
}
|
|
3922
3964
|
function getPreviousSpan({
|
|
3923
3965
|
editor,
|
|
3924
3966
|
blockPath,
|
|
@@ -4731,32 +4773,18 @@ function createEditableAPI(editor, editorActor) {
|
|
|
4731
4773
|
at: editor.selection
|
|
4732
4774
|
}), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types2.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types2)?.focus.path || [];
|
|
4733
4775
|
},
|
|
4734
|
-
insertBlock: (type, value) => {
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
match: (n) => !slate.Editor.isEditor(n),
|
|
4745
|
-
at: [],
|
|
4746
|
-
reverse: !0
|
|
4747
|
-
}))[0];
|
|
4748
|
-
return slate.Editor.insertNode(editor, block), lastBlock && isEqualToEmptyEditor([lastBlock[0]], types2) && slate.Transforms.removeNodes(editor, {
|
|
4749
|
-
at: lastBlock[1]
|
|
4750
|
-
}), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types2.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types2)?.focus.path ?? [];
|
|
4776
|
+
insertBlock: (type, value) => insertBlockObjectActionImplementation({
|
|
4777
|
+
context: {
|
|
4778
|
+
keyGenerator: editorActor.getSnapshot().context.keyGenerator,
|
|
4779
|
+
schema: types2
|
|
4780
|
+
},
|
|
4781
|
+
action: {
|
|
4782
|
+
type: "insert block object",
|
|
4783
|
+
name: type.name,
|
|
4784
|
+
value,
|
|
4785
|
+
editor
|
|
4751
4786
|
}
|
|
4752
|
-
|
|
4753
|
-
at: editor.selection.focus.path.slice(0, 1),
|
|
4754
|
-
match: (n) => n._type === types2.block.name
|
|
4755
|
-
}))[0];
|
|
4756
|
-
return slate.Editor.insertNode(editor, block), focusBlock && isEqualToEmptyEditor([focusBlock[0]], types2) && slate.Transforms.removeNodes(editor, {
|
|
4757
|
-
at: focusBlock[1]
|
|
4758
|
-
}), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types2.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types2)?.focus.path || [];
|
|
4759
|
-
},
|
|
4787
|
+
}),
|
|
4760
4788
|
hasBlockStyle: (style) => {
|
|
4761
4789
|
try {
|
|
4762
4790
|
return editor.pteHasBlockStyle(style);
|
|
@@ -4926,6 +4954,35 @@ function createEditableAPI(editor, editorActor) {
|
|
|
4926
4954
|
}
|
|
4927
4955
|
};
|
|
4928
4956
|
}
|
|
4957
|
+
const insertBlockObjectActionImplementation = ({
|
|
4958
|
+
context,
|
|
4959
|
+
action
|
|
4960
|
+
}) => {
|
|
4961
|
+
const editor = action.editor, types2 = context.schema, block = toSlateValue([{
|
|
4962
|
+
_key: context.keyGenerator(),
|
|
4963
|
+
_type: action.name,
|
|
4964
|
+
...action.value ? action.value : {}
|
|
4965
|
+
}], {
|
|
4966
|
+
schemaTypes: context.schema
|
|
4967
|
+
})[0];
|
|
4968
|
+
if (!editor.selection) {
|
|
4969
|
+
const lastBlock = Array.from(slate.Editor.nodes(editor, {
|
|
4970
|
+
match: (n) => !slate.Editor.isEditor(n),
|
|
4971
|
+
at: [],
|
|
4972
|
+
reverse: !0
|
|
4973
|
+
}))[0];
|
|
4974
|
+
return slate.Editor.insertNode(editor, block), lastBlock && isEqualToEmptyEditor([lastBlock[0]], types2) && slate.Transforms.removeNodes(editor, {
|
|
4975
|
+
at: lastBlock[1]
|
|
4976
|
+
}), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types2.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types2)?.focus.path ?? [];
|
|
4977
|
+
}
|
|
4978
|
+
const focusBlock = Array.from(slate.Editor.nodes(editor, {
|
|
4979
|
+
at: editor.selection.focus.path.slice(0, 1),
|
|
4980
|
+
match: (n) => n._type === types2.block.name
|
|
4981
|
+
}))[0];
|
|
4982
|
+
return slate.Editor.insertNode(editor, block), focusBlock && isEqualToEmptyEditor([focusBlock[0]], types2) && slate.Transforms.removeNodes(editor, {
|
|
4983
|
+
at: focusBlock[1]
|
|
4984
|
+
}), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types2.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types2)?.focus.path || [];
|
|
4985
|
+
};
|
|
4929
4986
|
function isAnnotationActive({
|
|
4930
4987
|
editor,
|
|
4931
4988
|
annotation
|
|
@@ -5306,6 +5363,7 @@ const addAnnotationActionImplementation = ({
|
|
|
5306
5363
|
at: location
|
|
5307
5364
|
});
|
|
5308
5365
|
},
|
|
5366
|
+
"insert block object": insertBlockObjectActionImplementation,
|
|
5309
5367
|
"insert break": insertBreakActionImplementation,
|
|
5310
5368
|
"insert soft break": insertSoftBreakActionImplementation,
|
|
5311
5369
|
"insert text": ({
|
|
@@ -5363,6 +5421,13 @@ function performAction({
|
|
|
5363
5421
|
});
|
|
5364
5422
|
break;
|
|
5365
5423
|
}
|
|
5424
|
+
case "insert block object": {
|
|
5425
|
+
behaviorActionImplementations["insert block object"]({
|
|
5426
|
+
context,
|
|
5427
|
+
action
|
|
5428
|
+
});
|
|
5429
|
+
break;
|
|
5430
|
+
}
|
|
5366
5431
|
case "insert text block": {
|
|
5367
5432
|
behaviorActionImplementations["insert text block"]({
|
|
5368
5433
|
context,
|