@portabletext/editor 1.11.3 → 1.12.1

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.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- import { isPortableTextTextBlock, isPortableTextSpan as isPortableTextSpan$1, isKeySegment, defineType, defineField, isPortableTextListBlock } from "@sanity/types";
1
+ import { isKeySegment, isPortableTextTextBlock, isPortableTextSpan as isPortableTextSpan$1, defineType, defineField, isPortableTextListBlock } from "@sanity/types";
2
2
  import { Schema } from "@sanity/schema";
3
3
  import startCase from "lodash.startcase";
4
4
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
@@ -138,7 +138,13 @@ function getNextBlock(context) {
138
138
  return nextBlock;
139
139
  }
140
140
  function isEmptyTextBlock(block) {
141
- return block.children.length === 1 && block.children[0].text === "";
141
+ if (!isPortableTextTextBlock(block))
142
+ return !1;
143
+ const onlyText = block.children.every(isPortableTextSpan$1), blockText = getTextBlockText(block);
144
+ return onlyText && blockText === "";
145
+ }
146
+ function getTextBlockText(block) {
147
+ return block.children.map((child) => child.text ?? "").join("");
142
148
  }
143
149
  const breakingBlockObject = {
144
150
  on: "insert break",
@@ -147,7 +153,7 @@ const breakingBlockObject = {
147
153
  }) => !!getFocusBlockObject(context),
148
154
  actions: [() => [{
149
155
  type: "insert text block",
150
- decorators: []
156
+ placement: "after"
151
157
  }]]
152
158
  }, deletingEmptyTextBlockAfterBlockObject = {
153
159
  on: "delete backward",
@@ -164,17 +170,8 @@ const breakingBlockObject = {
164
170
  focusTextBlock,
165
171
  previousBlock
166
172
  }) => [{
167
- type: "delete",
168
- selection: {
169
- anchor: {
170
- path: focusTextBlock.path,
171
- offset: 0
172
- },
173
- focus: {
174
- path: focusTextBlock.path,
175
- offset: 0
176
- }
177
- }
173
+ type: "delete block",
174
+ blockPath: focusTextBlock.path
178
175
  }, {
179
176
  type: "select",
180
177
  selection: {
@@ -203,17 +200,8 @@ const breakingBlockObject = {
203
200
  focusTextBlock,
204
201
  nextBlock
205
202
  }) => [{
206
- type: "delete",
207
- selection: {
208
- anchor: {
209
- path: focusTextBlock.path,
210
- offset: 0
211
- },
212
- focus: {
213
- path: focusTextBlock.path,
214
- offset: 0
215
- }
216
- }
203
+ type: "delete block",
204
+ blockPath: focusTextBlock.path
217
205
  }, {
218
206
  type: "select",
219
207
  selection: {
@@ -376,20 +364,138 @@ function looksLikeUrl(text) {
376
364
  }
377
365
  return looksLikeUrl2;
378
366
  }
379
- function isPortableTextSpan(node) {
380
- 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"));
367
+ function blockOffsetToSpanSelectionPoint({
368
+ value,
369
+ blockOffset
370
+ }) {
371
+ let offsetLeft = blockOffset.offset, selectionPoint;
372
+ for (const block of value)
373
+ if (block._key === blockOffset.path[0]._key && isPortableTextTextBlock(block)) {
374
+ for (const child of block.children)
375
+ if (isPortableTextSpan$1(child)) {
376
+ if (offsetLeft === 0) {
377
+ selectionPoint = {
378
+ path: [...blockOffset.path, "children", {
379
+ _key: child._key
380
+ }],
381
+ offset: 0
382
+ };
383
+ break;
384
+ }
385
+ if (offsetLeft <= child.text.length) {
386
+ selectionPoint = {
387
+ path: [...blockOffset.path, "children", {
388
+ _key: child._key
389
+ }],
390
+ offset: offsetLeft
391
+ };
392
+ break;
393
+ }
394
+ offsetLeft -= child.text.length;
395
+ }
396
+ }
397
+ return selectionPoint;
381
398
  }
382
- function isPortableTextBlock(node) {
383
- return (
384
- // A block doesn't _have_ to be named 'block' - to differentiate between
385
- // allowed child types and marks, one might name them differently
386
- typeof node._type == "string" && // Toolkit-types like nested spans are @-prefixed
387
- node._type[0] !== "@" && // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array
388
- (!("markDefs" in node) || !node.markDefs || Array.isArray(node.markDefs) && // Every mark definition needs to have an `_key` to be mappable in child spans
389
- node.markDefs.every((def) => typeof def._key == "string")) && // `children` is required and needs to be an array
390
- "children" in node && Array.isArray(node.children) && // All children are objects with `_type` (usually spans, but can contain other stuff)
391
- node.children.every((child) => typeof child == "object" && "_type" in child)
392
- );
399
+ function spanSelectionPointToBlockOffset({
400
+ value,
401
+ selectionPoint
402
+ }) {
403
+ let offset = 0;
404
+ for (const block of value)
405
+ if (block._key === selectionPoint.path[0]._key && isPortableTextTextBlock(block)) {
406
+ for (const child of block.children)
407
+ if (isPortableTextSpan$1(child)) {
408
+ if (child._key === selectionPoint.path[2]._key)
409
+ return {
410
+ path: [{
411
+ _key: block._key
412
+ }],
413
+ offset: offset + selectionPoint.offset
414
+ };
415
+ offset += child.text.length;
416
+ }
417
+ }
418
+ }
419
+ function isKeyedSegment$1(segment) {
420
+ return typeof segment == "object" && segment !== null && "_key" in segment;
421
+ }
422
+ function reverseSelection(selection) {
423
+ return selection && (selection.backward ? {
424
+ anchor: selection.focus,
425
+ focus: selection.anchor,
426
+ backward: !1
427
+ } : {
428
+ anchor: selection.focus,
429
+ focus: selection.anchor,
430
+ backward: !0
431
+ });
432
+ }
433
+ function getSelectionText({
434
+ value,
435
+ selection
436
+ }) {
437
+ let text = "";
438
+ if (!value || !selection)
439
+ return text;
440
+ const forwardSelection = selection.backward ? reverseSelection(selection) : selection;
441
+ if (!forwardSelection)
442
+ return text;
443
+ for (const block of value)
444
+ if (!(isKeyedSegment$1(forwardSelection.anchor.path[0]) && block._key !== forwardSelection.anchor.path[0]._key) && isPortableTextTextBlock(block)) {
445
+ for (const child of block.children)
446
+ if (isPortableTextSpan$1(child)) {
447
+ if (isKeyedSegment$1(forwardSelection.anchor.path[2]) && child._key === forwardSelection.anchor.path[2]._key && isKeyedSegment$1(forwardSelection.focus.path[2]) && child._key === forwardSelection.focus.path[2]._key) {
448
+ text = text + child.text.slice(forwardSelection.anchor.offset, forwardSelection.focus.offset);
449
+ break;
450
+ }
451
+ if (isKeyedSegment$1(forwardSelection.anchor.path[2]) && child._key === forwardSelection.anchor.path[2]._key) {
452
+ text = text + child.text.slice(forwardSelection.anchor.offset);
453
+ continue;
454
+ }
455
+ if (isKeyedSegment$1(forwardSelection.focus.path[2]) && child._key === forwardSelection.focus.path[2]._key) {
456
+ text = text + child.text.slice(0, forwardSelection.focus.offset);
457
+ break;
458
+ }
459
+ }
460
+ if (isKeyedSegment$1(forwardSelection.focus.path[0]) && block._key === forwardSelection.focus.path[0]._key)
461
+ break;
462
+ }
463
+ return text;
464
+ }
465
+ function getStartPoint({
466
+ node,
467
+ path
468
+ }) {
469
+ return isPortableTextTextBlock(node) ? {
470
+ path: [...path, "children", {
471
+ _key: node.children[0]._key
472
+ }],
473
+ offset: 0
474
+ } : {
475
+ path,
476
+ offset: 0
477
+ };
478
+ }
479
+ function getBlockTextBefore({
480
+ value,
481
+ point
482
+ }) {
483
+ const key = isKeyedSegment$1(point.path[0]) ? point.path[0]._key : void 0, block = key ? value.find((block2) => block2._key === key) : void 0;
484
+ if (!block)
485
+ return "";
486
+ const startPoint = getStartPoint({
487
+ node: block,
488
+ path: [{
489
+ _key: block._key
490
+ }]
491
+ });
492
+ return getSelectionText({
493
+ value,
494
+ selection: {
495
+ anchor: startPoint,
496
+ focus: point
497
+ }
498
+ });
393
499
  }
394
500
  function createMarkdownBehaviors(config) {
395
501
  const automaticBlockquoteOnSpace = {
@@ -403,12 +509,24 @@ function createMarkdownBehaviors(config) {
403
509
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
404
510
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
405
511
  return !1;
406
- const caretAtTheEndOfQuote = context.selection.focus.offset === 1, looksLikeMarkdownQuote = /^>/.test(focusSpan.node.text), blockquoteStyle = config.blockquoteStyle?.({
512
+ const blockOffset = spanSelectionPointToBlockOffset({
513
+ value: context.value,
514
+ selectionPoint: {
515
+ path: [{
516
+ _key: focusTextBlock.node._key
517
+ }, "children", {
518
+ _key: focusSpan.node._key
519
+ }],
520
+ offset: context.selection.focus.offset
521
+ }
522
+ });
523
+ if (!blockOffset)
524
+ return !1;
525
+ const blockText = getTextBlockText(focusTextBlock.node), caretAtTheEndOfQuote = blockOffset.offset === 1, looksLikeMarkdownQuote = /^>/.test(blockText), blockquoteStyle = config.blockquoteStyle?.({
407
526
  schema: context.schema
408
527
  });
409
528
  return caretAtTheEndOfQuote && looksLikeMarkdownQuote && blockquoteStyle !== void 0 ? {
410
529
  focusTextBlock,
411
- focusSpan,
412
530
  style: blockquoteStyle
413
531
  } : !1;
414
532
  },
@@ -417,7 +535,6 @@ function createMarkdownBehaviors(config) {
417
535
  text: " "
418
536
  }], (_, {
419
537
  focusTextBlock,
420
- focusSpan,
421
538
  style
422
539
  }) => [{
423
540
  type: "unset block",
@@ -428,19 +545,17 @@ function createMarkdownBehaviors(config) {
428
545
  style,
429
546
  paths: [focusTextBlock.path]
430
547
  }, {
431
- type: "delete",
432
- selection: {
433
- anchor: {
434
- path: focusSpan.path,
435
- offset: 0
436
- },
437
- focus: {
438
- path: focusSpan.path,
439
- offset: 2
440
- }
548
+ type: "delete text",
549
+ anchor: {
550
+ path: focusTextBlock.path,
551
+ offset: 0
552
+ },
553
+ focus: {
554
+ path: focusTextBlock.path,
555
+ offset: 2
441
556
  }
442
557
  }]]
443
- }, automaticBreak = {
558
+ }, automaticHr = {
444
559
  on: "insert text",
445
560
  guard: ({
446
561
  context,
@@ -449,16 +564,29 @@ function createMarkdownBehaviors(config) {
449
564
  const hrCharacter = event.text === "-" ? "-" : event.text === "*" ? "*" : event.text === "_" ? "_" : void 0;
450
565
  if (hrCharacter === void 0)
451
566
  return !1;
452
- const breakObject = config.horizontalRuleObject?.({
567
+ const hrObject = config.horizontalRuleObject?.({
453
568
  schema: context.schema
454
569
  }), focusBlock = getFocusTextBlock(context), selectionCollapsed = selectionIsCollapsed(context);
455
- if (!breakObject || !focusBlock || !selectionCollapsed)
570
+ if (!hrObject || !focusBlock || !selectionCollapsed)
456
571
  return !1;
457
- const onlyText = focusBlock.node.children.every(isPortableTextSpan), blockText = focusBlock.node.children.map((child) => child.text ?? "").join("");
458
- return onlyText && blockText === `${hrCharacter}${hrCharacter}` ? {
459
- breakObject,
572
+ const textBefore = getBlockTextBefore({
573
+ value: context.value,
574
+ point: context.selection.focus
575
+ }), hrBlockOffsets = {
576
+ anchor: {
577
+ path: focusBlock.path,
578
+ offset: 0
579
+ },
580
+ focus: {
581
+ path: focusBlock.path,
582
+ offset: 3
583
+ }
584
+ };
585
+ return textBefore === `${hrCharacter}${hrCharacter}` ? {
586
+ hrObject,
460
587
  focusBlock,
461
- hrCharacter
588
+ hrCharacter,
589
+ hrBlockOffsets
462
590
  } : !1;
463
591
  },
464
592
  actions: [(_, {
@@ -467,26 +595,56 @@ function createMarkdownBehaviors(config) {
467
595
  type: "insert text",
468
596
  text: hrCharacter
469
597
  }], (_, {
470
- breakObject,
471
- focusBlock
598
+ hrObject,
599
+ hrBlockOffsets
472
600
  }) => [{
473
601
  type: "insert block object",
474
- ...breakObject
475
- }, {
476
- type: "delete",
477
- selection: {
478
- anchor: {
479
- path: focusBlock.path,
480
- offset: 0
481
- },
482
- focus: {
483
- path: focusBlock.path,
484
- offset: 0
485
- }
486
- }
602
+ placement: "before",
603
+ blockObject: hrObject
487
604
  }, {
605
+ type: "delete text",
606
+ ...hrBlockOffsets
607
+ }]]
608
+ }, automaticHrOnPaste = {
609
+ on: "paste",
610
+ guard: ({
611
+ context,
612
+ event
613
+ }) => {
614
+ const text = event.clipboardData.getData("text/plain"), hrRegExp = /^(---)$|(___)$|(\*\*\*)$/gm, hrCharacters = text.match(hrRegExp)?.[0], hrObject = config.horizontalRuleObject?.({
615
+ schema: context.schema
616
+ }), focusBlock = getFocusBlock(context);
617
+ return !hrCharacters || !hrObject || !focusBlock ? !1 : {
618
+ hrCharacters,
619
+ hrObject,
620
+ focusBlock
621
+ };
622
+ },
623
+ actions: [(_, {
624
+ hrCharacters
625
+ }) => [{
626
+ type: "insert text",
627
+ text: hrCharacters
628
+ }], (_, {
629
+ hrObject,
630
+ focusBlock
631
+ }) => isPortableTextTextBlock(focusBlock.node) ? [{
488
632
  type: "insert text block",
489
- decorators: []
633
+ textBlock: {
634
+ children: focusBlock.node.children
635
+ },
636
+ placement: "after"
637
+ }, {
638
+ type: "insert block object",
639
+ blockObject: hrObject,
640
+ placement: "after"
641
+ }, {
642
+ type: "delete block",
643
+ blockPath: focusBlock.path
644
+ }] : [{
645
+ type: "insert block object",
646
+ blockObject: hrObject,
647
+ placement: "after"
490
648
  }]]
491
649
  }, automaticHeadingOnSpace = {
492
650
  on: "insert text",
@@ -499,8 +657,21 @@ function createMarkdownBehaviors(config) {
499
657
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
500
658
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
501
659
  return !1;
502
- const markdownHeadingSearch = /^#+/.exec(focusSpan.node.text), level = markdownHeadingSearch ? markdownHeadingSearch[0].length : void 0;
503
- if (context.selection.focus.offset !== level)
660
+ const blockOffset = spanSelectionPointToBlockOffset({
661
+ value: context.value,
662
+ selectionPoint: {
663
+ path: [{
664
+ _key: focusTextBlock.node._key
665
+ }, "children", {
666
+ _key: focusSpan.node._key
667
+ }],
668
+ offset: context.selection.focus.offset
669
+ }
670
+ });
671
+ if (!blockOffset)
672
+ return !1;
673
+ const blockText = getTextBlockText(focusTextBlock.node), markdownHeadingSearch = /^#+/.exec(blockText), level = markdownHeadingSearch ? markdownHeadingSearch[0].length : void 0;
674
+ if (blockOffset.offset !== level)
504
675
  return !1;
505
676
  const style = level !== void 0 ? config.headingStyle?.({
506
677
  schema: context.schema,
@@ -508,7 +679,6 @@ function createMarkdownBehaviors(config) {
508
679
  }) : void 0;
509
680
  return level !== void 0 && style !== void 0 ? {
510
681
  focusTextBlock,
511
- focusSpan,
512
682
  style,
513
683
  level
514
684
  } : !1;
@@ -518,7 +688,6 @@ function createMarkdownBehaviors(config) {
518
688
  text: " "
519
689
  }], (_, {
520
690
  focusTextBlock,
521
- focusSpan,
522
691
  style,
523
692
  level
524
693
  }) => [{
@@ -530,16 +699,14 @@ function createMarkdownBehaviors(config) {
530
699
  style,
531
700
  paths: [focusTextBlock.path]
532
701
  }, {
533
- type: "delete",
534
- selection: {
535
- anchor: {
536
- path: focusSpan.path,
537
- offset: 0
538
- },
539
- focus: {
540
- path: focusSpan.path,
541
- offset: level + 1
542
- }
702
+ type: "delete text",
703
+ anchor: {
704
+ path: focusTextBlock.path,
705
+ offset: 0
706
+ },
707
+ focus: {
708
+ path: focusTextBlock.path,
709
+ offset: level + 1
543
710
  }
544
711
  }]]
545
712
  }, clearStyleOnBackspace = {
@@ -577,15 +744,27 @@ function createMarkdownBehaviors(config) {
577
744
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
578
745
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
579
746
  return !1;
580
- const defaultStyle = config.defaultStyle?.({
747
+ const blockOffset = spanSelectionPointToBlockOffset({
748
+ value: context.value,
749
+ selectionPoint: {
750
+ path: [{
751
+ _key: focusTextBlock.node._key
752
+ }, "children", {
753
+ _key: focusSpan.node._key
754
+ }],
755
+ offset: context.selection.focus.offset
756
+ }
757
+ });
758
+ if (!blockOffset)
759
+ return !1;
760
+ const blockText = getTextBlockText(focusTextBlock.node), defaultStyle = config.defaultStyle?.({
581
761
  schema: context.schema
582
- }), looksLikeUnorderedList = /^(-|\*)/.test(focusSpan.node.text), unorderedListStyle = config.unorderedListStyle?.({
762
+ }), looksLikeUnorderedList = /^(-|\*)/.test(blockText), unorderedListStyle = config.unorderedListStyle?.({
583
763
  schema: context.schema
584
- }), caretAtTheEndOfUnorderedList = context.selection.focus.offset === 1;
764
+ }), caretAtTheEndOfUnorderedList = blockOffset.offset === 1;
585
765
  if (defaultStyle && caretAtTheEndOfUnorderedList && looksLikeUnorderedList && unorderedListStyle !== void 0)
586
766
  return {
587
767
  focusTextBlock,
588
- focusSpan,
589
768
  listItem: unorderedListStyle,
590
769
  listItemLength: 1,
591
770
  style: defaultStyle
@@ -595,7 +774,6 @@ function createMarkdownBehaviors(config) {
595
774
  }), caretAtTheEndOfOrderedList = context.selection.focus.offset === 2;
596
775
  return defaultStyle && caretAtTheEndOfOrderedList && looksLikeOrderedList && orderedListStyle !== void 0 ? {
597
776
  focusTextBlock,
598
- focusSpan,
599
777
  listItem: orderedListStyle,
600
778
  listItemLength: 2,
601
779
  style: defaultStyle
@@ -606,7 +784,6 @@ function createMarkdownBehaviors(config) {
606
784
  text: " "
607
785
  }], (_, {
608
786
  focusTextBlock,
609
- focusSpan,
610
787
  style,
611
788
  listItem,
612
789
  listItemLength
@@ -617,20 +794,18 @@ function createMarkdownBehaviors(config) {
617
794
  style,
618
795
  paths: [focusTextBlock.path]
619
796
  }, {
620
- type: "delete",
621
- selection: {
622
- anchor: {
623
- path: focusSpan.path,
624
- offset: 0
625
- },
626
- focus: {
627
- path: focusSpan.path,
628
- offset: listItemLength + 1
629
- }
797
+ type: "delete text",
798
+ anchor: {
799
+ path: focusTextBlock.path,
800
+ offset: 0
801
+ },
802
+ focus: {
803
+ path: focusTextBlock.path,
804
+ offset: listItemLength + 1
630
805
  }
631
806
  }]]
632
807
  };
633
- return [automaticBlockquoteOnSpace, automaticBreak, automaticHeadingOnSpace, clearStyleOnBackspace, automaticListOnSpace];
808
+ return [automaticBlockquoteOnSpace, automaticHeadingOnSpace, automaticHr, automaticHrOnPaste, clearStyleOnBackspace, automaticListOnSpace];
634
809
  }
635
810
  function getPortableTextMemberSchemaTypes(portableTextType) {
636
811
  if (!portableTextType)
@@ -4028,6 +4203,21 @@ function createWithPortableTextLists(types) {
4028
4203
  }, editor;
4029
4204
  };
4030
4205
  }
4206
+ function isPortableTextSpan(node) {
4207
+ 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"));
4208
+ }
4209
+ function isPortableTextBlock(node) {
4210
+ return (
4211
+ // A block doesn't _have_ to be named 'block' - to differentiate between
4212
+ // allowed child types and marks, one might name them differently
4213
+ typeof node._type == "string" && // Toolkit-types like nested spans are @-prefixed
4214
+ node._type[0] !== "@" && // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array
4215
+ (!("markDefs" in node) || !node.markDefs || Array.isArray(node.markDefs) && // Every mark definition needs to have an `_key` to be mappable in child spans
4216
+ node.markDefs.every((def) => typeof def._key == "string")) && // `children` is required and needs to be an array
4217
+ "children" in node && Array.isArray(node.children) && // All children are objects with `_type` (usually spans, but can contain other stuff)
4218
+ node.children.every((child) => typeof child == "object" && "_type" in child)
4219
+ );
4220
+ }
4031
4221
  function getPreviousSpan({
4032
4222
  editor,
4033
4223
  blockPath,
@@ -4728,7 +4918,66 @@ function createSlateEditor(config) {
4728
4918
  };
4729
4919
  return slateEditors.set(config.editorActor, slateEditor), slateEditor;
4730
4920
  }
4731
- const debug$5 = debugWithName("API:editable");
4921
+ function insertBlock({
4922
+ block,
4923
+ placement,
4924
+ editor,
4925
+ schema
4926
+ }) {
4927
+ if (editor.selection) {
4928
+ const [focusBlock, focusBlockPath] = Array.from(Editor.nodes(editor, {
4929
+ at: editor.selection.focus.path.slice(0, 1),
4930
+ match: (n) => !Editor.isEditor(n)
4931
+ }))[0] ?? [void 0, void 0];
4932
+ if (placement === "after") {
4933
+ const nextPath = [focusBlockPath[0] + 1];
4934
+ Transforms.insertNodes(editor, block, {
4935
+ at: nextPath
4936
+ }), Transforms.select(editor, {
4937
+ anchor: {
4938
+ path: [nextPath[0], 0],
4939
+ offset: 0
4940
+ },
4941
+ focus: {
4942
+ path: [nextPath[0], 0],
4943
+ offset: 0
4944
+ }
4945
+ });
4946
+ } else placement === "before" ? Transforms.insertNodes(editor, block, {
4947
+ at: focusBlockPath
4948
+ }) : Editor.insertNode(editor, block);
4949
+ focusBlock && isEqualToEmptyEditor([focusBlock], schema) && Transforms.removeNodes(editor, {
4950
+ at: focusBlockPath
4951
+ });
4952
+ } else {
4953
+ const lastBlock = Array.from(Editor.nodes(editor, {
4954
+ match: (n) => !Editor.isEditor(n),
4955
+ at: [],
4956
+ reverse: !0
4957
+ }))[0];
4958
+ Editor.insertNode(editor, block), lastBlock && isEqualToEmptyEditor([lastBlock[0]], schema) && Transforms.removeNodes(editor, {
4959
+ at: lastBlock[1]
4960
+ });
4961
+ }
4962
+ }
4963
+ const insertBlockObjectActionImplementation = ({
4964
+ context,
4965
+ action
4966
+ }) => {
4967
+ const block = toSlateValue([{
4968
+ _key: context.keyGenerator(),
4969
+ _type: action.blockObject.name,
4970
+ ...action.blockObject.value ? action.blockObject.value : {}
4971
+ }], {
4972
+ schemaTypes: context.schema
4973
+ })[0];
4974
+ insertBlock({
4975
+ block,
4976
+ placement: action.placement,
4977
+ editor: action.editor,
4978
+ schema: context.schema
4979
+ });
4980
+ }, debug$5 = debugWithName("API:editable");
4732
4981
  function createEditableAPI(editor, editorActor) {
4733
4982
  const types = editorActor.getSnapshot().context.schema;
4734
4983
  return {
@@ -4817,18 +5066,21 @@ function createEditableAPI(editor, editorActor) {
4817
5066
  at: editor.selection
4818
5067
  }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path || [];
4819
5068
  },
4820
- insertBlock: (type, value) => insertBlockObjectActionImplementation({
5069
+ insertBlock: (type, value) => (insertBlockObjectActionImplementation({
4821
5070
  context: {
4822
5071
  keyGenerator: editorActor.getSnapshot().context.keyGenerator,
4823
5072
  schema: types
4824
5073
  },
4825
5074
  action: {
4826
5075
  type: "insert block object",
4827
- name: type.name,
4828
- value,
5076
+ blockObject: {
5077
+ name: type.name,
5078
+ value
5079
+ },
5080
+ placement: "auto",
4829
5081
  editor
4830
5082
  }
4831
- }),
5083
+ }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path ?? []),
4832
5084
  hasBlockStyle: (style) => {
4833
5085
  try {
4834
5086
  return editor.pteHasBlockStyle(style);
@@ -4998,35 +5250,6 @@ function createEditableAPI(editor, editorActor) {
4998
5250
  }
4999
5251
  };
5000
5252
  }
5001
- const insertBlockObjectActionImplementation = ({
5002
- context,
5003
- action
5004
- }) => {
5005
- const editor = action.editor, types = context.schema, block = toSlateValue([{
5006
- _key: context.keyGenerator(),
5007
- _type: action.name,
5008
- ...action.value ? action.value : {}
5009
- }], {
5010
- schemaTypes: context.schema
5011
- })[0];
5012
- if (!editor.selection) {
5013
- const lastBlock = Array.from(Editor.nodes(editor, {
5014
- match: (n) => !Editor.isEditor(n),
5015
- at: [],
5016
- reverse: !0
5017
- }))[0];
5018
- return Editor.insertNode(editor, block), lastBlock && isEqualToEmptyEditor([lastBlock[0]], types) && Transforms.removeNodes(editor, {
5019
- at: lastBlock[1]
5020
- }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path ?? [];
5021
- }
5022
- const focusBlock = Array.from(Editor.nodes(editor, {
5023
- at: editor.selection.focus.path.slice(0, 1),
5024
- match: (n) => n._type === types.block.name
5025
- }))[0];
5026
- return Editor.insertNode(editor, block), focusBlock && isEqualToEmptyEditor([focusBlock[0]], types) && Transforms.removeNodes(editor, {
5027
- at: focusBlock[1]
5028
- }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path || [];
5029
- };
5030
5253
  function isAnnotationActive({
5031
5254
  editor,
5032
5255
  annotation
@@ -5422,18 +5645,52 @@ const addAnnotationActionImplementation = ({
5422
5645
  }) => {
5423
5646
  deleteForward(action.editor, action.unit);
5424
5647
  },
5425
- delete: ({
5648
+ "delete block": ({
5649
+ action
5650
+ }) => {
5651
+ const range = toSlateRange({
5652
+ anchor: {
5653
+ path: action.blockPath,
5654
+ offset: 0
5655
+ },
5656
+ focus: {
5657
+ path: action.blockPath,
5658
+ offset: 0
5659
+ }
5660
+ }, action.editor);
5661
+ if (!range) {
5662
+ console.error("Unable to find Slate range from selection points");
5663
+ return;
5664
+ }
5665
+ Transforms.removeNodes(action.editor, {
5666
+ at: range
5667
+ });
5668
+ },
5669
+ "delete text": ({
5670
+ context,
5426
5671
  action
5427
5672
  }) => {
5428
- const location = toSlateRange(action.selection, action.editor);
5429
- if (!location) {
5430
- console.error(`Could not find Slate location from selection ${action.selection}`);
5673
+ const value = fromSlateValue(action.editor.children, context.schema.block.name, KEY_TO_VALUE_ELEMENT.get(action.editor)), anchor = blockOffsetToSpanSelectionPoint({
5674
+ value,
5675
+ blockOffset: action.anchor
5676
+ }), focus = blockOffsetToSpanSelectionPoint({
5677
+ value,
5678
+ blockOffset: action.focus
5679
+ });
5680
+ if (!anchor || !focus) {
5681
+ console.error("Unable to find anchor or focus selection point");
5431
5682
  return;
5432
5683
  }
5433
- location.anchor.path.length === 1 && location.focus.path.length === 1 ? Transforms.removeNodes(action.editor, {
5434
- at: location
5435
- }) : Transforms.delete(action.editor, {
5436
- at: location
5684
+ const range = toSlateRange({
5685
+ anchor,
5686
+ focus
5687
+ }, action.editor);
5688
+ if (!range) {
5689
+ console.error("Unable to find Slate range from selection points");
5690
+ return;
5691
+ }
5692
+ Transforms.delete(action.editor, {
5693
+ at: range
5437
5694
  });
5438
5695
  },
5439
5696
  "insert block object": insertBlockObjectActionImplementation,
@@ -5449,16 +5706,27 @@ const addAnnotationActionImplementation = ({
5449
5706
  context,
5450
5707
  action
5451
5708
  }) => {
5452
- Editor.insertNode(action.editor, {
5709
+ const block = toSlateValue([{
5453
5710
  _key: context.keyGenerator(),
5454
5711
  _type: context.schema.block.name,
5455
5712
  style: context.schema.styles[0].value ?? "normal",
5456
5713
  markDefs: [],
5457
- children: [{
5714
+ children: action.textBlock?.children?.map((child) => ({
5715
+ ...child,
5716
+ _key: context.keyGenerator()
5717
+ })) ?? [{
5718
+ _type: context.schema.span.name,
5458
5719
  _key: context.keyGenerator(),
5459
- _type: "span",
5460
5720
  text: ""
5461
5721
  }]
5722
+ }], {
5723
+ schemaTypes: context.schema
5724
+ })[0];
5725
+ insertBlock({
5726
+ block,
5727
+ editor: action.editor,
5728
+ schema: context.schema,
5729
+ placement: action.placement
5462
5730
  });
5463
5731
  },
5464
5732
  effect: ({
@@ -5493,8 +5761,15 @@ function performAction({
5493
5761
  action
5494
5762
  }) {
5495
5763
  switch (action.type) {
5496
- case "delete": {
5497
- behaviorActionImplementations.delete({
5764
+ case "delete block": {
5765
+ behaviorActionImplementations["delete block"]({
5766
+ context,
5767
+ action
5768
+ });
5769
+ break;
5770
+ }
5771
+ case "delete text": {
5772
+ behaviorActionImplementations["delete text"]({
5498
5773
  context,
5499
5774
  action
5500
5775
  });