@portabletext/editor 1.25.0 → 1.26.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.
Files changed (81) hide show
  1. package/lib/_chunks-cjs/behavior.core.cjs +131 -36
  2. package/lib/_chunks-cjs/behavior.core.cjs.map +1 -1
  3. package/lib/_chunks-cjs/selector.get-text-before.cjs +8 -8
  4. package/lib/_chunks-cjs/selector.get-text-before.cjs.map +1 -1
  5. package/lib/_chunks-cjs/{selector.is-active-style.cjs → selector.is-at-the-start-of-block.cjs} +29 -3
  6. package/lib/_chunks-cjs/selector.is-at-the-start-of-block.cjs.map +1 -0
  7. package/lib/_chunks-cjs/util.is-empty-text-block.cjs +2 -2
  8. package/lib/_chunks-cjs/util.is-empty-text-block.cjs.map +1 -1
  9. package/lib/_chunks-cjs/util.is-equal-selection-points.cjs +46 -0
  10. package/lib/_chunks-cjs/util.is-equal-selection-points.cjs.map +1 -0
  11. package/lib/_chunks-cjs/util.reverse-selection.cjs +0 -16
  12. package/lib/_chunks-cjs/util.reverse-selection.cjs.map +1 -1
  13. package/lib/_chunks-es/behavior.core.js +99 -4
  14. package/lib/_chunks-es/behavior.core.js.map +1 -1
  15. package/lib/_chunks-es/selector.get-text-before.js +2 -2
  16. package/lib/_chunks-es/{selector.is-active-style.js → selector.is-at-the-start-of-block.js} +29 -2
  17. package/lib/_chunks-es/selector.is-at-the-start-of-block.js.map +1 -0
  18. package/lib/_chunks-es/util.is-empty-text-block.js +1 -1
  19. package/lib/_chunks-es/util.is-equal-selection-points.js +47 -0
  20. package/lib/_chunks-es/util.is-equal-selection-points.js.map +1 -0
  21. package/lib/_chunks-es/util.reverse-selection.js +0 -16
  22. package/lib/_chunks-es/util.reverse-selection.js.map +1 -1
  23. package/lib/behaviors/index.cjs +27 -27
  24. package/lib/behaviors/index.cjs.map +1 -1
  25. package/lib/behaviors/index.d.cts +413 -0
  26. package/lib/behaviors/index.d.ts +413 -0
  27. package/lib/behaviors/index.js +1 -1
  28. package/lib/index.cjs +147 -106
  29. package/lib/index.cjs.map +1 -1
  30. package/lib/index.d.cts +1653 -222
  31. package/lib/index.d.ts +1653 -222
  32. package/lib/index.js +143 -102
  33. package/lib/index.js.map +1 -1
  34. package/lib/selectors/index.cjs +25 -23
  35. package/lib/selectors/index.cjs.map +1 -1
  36. package/lib/selectors/index.d.cts +16 -0
  37. package/lib/selectors/index.d.ts +16 -0
  38. package/lib/selectors/index.js +3 -1
  39. package/lib/utils/index.cjs +5 -3
  40. package/lib/utils/index.cjs.map +1 -1
  41. package/lib/utils/index.d.cts +19 -0
  42. package/lib/utils/index.d.ts +19 -0
  43. package/lib/utils/index.js +4 -2
  44. package/package.json +1 -1
  45. package/src/behavior-actions/behavior.action-utils.insert-block.ts +3 -3
  46. package/src/behavior-actions/behavior.action.block.set.ts +23 -0
  47. package/src/behavior-actions/behavior.action.block.unset.ts +21 -0
  48. package/src/behavior-actions/behavior.action.insert-break.ts +2 -69
  49. package/src/behavior-actions/behavior.action.insert.block.ts +29 -0
  50. package/src/behavior-actions/behavior.actions.ts +28 -9
  51. package/src/behaviors/behavior.core.insert-break.ts +122 -0
  52. package/src/behaviors/behavior.core.ts +6 -2
  53. package/src/behaviors/behavior.types.ts +16 -1
  54. package/src/converters/converter.json.ts +4 -4
  55. package/src/converters/converter.portable-text.deserialize.test.ts +1 -1
  56. package/src/converters/converter.portable-text.ts +4 -4
  57. package/src/converters/converter.text-html.deserialize.test.ts +1 -1
  58. package/src/converters/converter.text-html.serialize.test.ts +1 -1
  59. package/src/converters/converter.text-html.ts +4 -4
  60. package/src/converters/converter.text-plain.test.ts +1 -1
  61. package/src/converters/converter.text-plain.ts +3 -3
  62. package/src/converters/{converter.ts → converter.types.ts} +6 -0
  63. package/src/editor/create-editor.ts +4 -1
  64. package/src/editor/editor-machine.ts +8 -2
  65. package/src/editor/editor-snapshot.ts +1 -1
  66. package/src/editor/plugins/__tests__/withPortableTextMarkModel.test.tsx +2 -2
  67. package/src/editor/plugins/create-with-event-listeners.ts +3 -0
  68. package/src/selectors/index.ts +2 -0
  69. package/src/selectors/selector.is-at-the-end-of-block.ts +22 -0
  70. package/src/selectors/selector.is-at-the-start-of-block.ts +25 -0
  71. package/src/selectors/selector.is-selection-collapsed.ts +6 -2
  72. package/src/utils/index.ts +2 -0
  73. package/src/utils/util.get-block-end-point.ts +34 -0
  74. package/src/utils/util.is-equal-selection-points.ts +13 -0
  75. package/lib/_chunks-cjs/selector.is-active-style.cjs.map +0 -1
  76. package/lib/_chunks-cjs/util.is-keyed-segment.cjs +0 -6
  77. package/lib/_chunks-cjs/util.is-keyed-segment.cjs.map +0 -1
  78. package/lib/_chunks-es/selector.is-active-style.js.map +0 -1
  79. package/lib/_chunks-es/util.is-keyed-segment.js +0 -7
  80. package/lib/_chunks-es/util.is-keyed-segment.js.map +0 -1
  81. /package/src/converters/{converters.ts → converters.core.ts} +0 -0
package/lib/index.js CHANGED
@@ -23,7 +23,7 @@ import { toHTML } from "@portabletext/to-html";
23
23
  import get from "lodash/get.js";
24
24
  import isUndefined from "lodash/isUndefined.js";
25
25
  import omitBy from "lodash/omitBy.js";
26
- import { createGuards } from "./_chunks-es/selector.is-active-style.js";
26
+ import { createGuards } from "./_chunks-es/selector.is-at-the-start-of-block.js";
27
27
  import { blockOffsetToSpanSelectionPoint } from "./_chunks-es/util.is-empty-text-block.js";
28
28
  import { coreBehaviors, isCustomBehaviorEvent, isHotkey } from "./_chunks-es/behavior.core.js";
29
29
  import getRandomValues from "get-random-values-esm";
@@ -2523,6 +2523,7 @@ function _temp(s) {
2523
2523
  }
2524
2524
  Synchronizer.displayName = "Synchronizer";
2525
2525
  const converterJson = {
2526
+ mimeType: "application/json",
2526
2527
  serialize: ({
2527
2528
  context,
2528
2529
  event
@@ -2558,8 +2559,7 @@ const converterJson = {
2558
2559
  mimeType: "application/json",
2559
2560
  reason: "No application/x-portable-text Converter found"
2560
2561
  };
2561
- },
2562
- mimeType: "application/json"
2562
+ }
2563
2563
  };
2564
2564
  function isTypedObject(object) {
2565
2565
  return isRecord(object) && typeof object._type == "string";
@@ -2621,6 +2621,7 @@ function parseBlock({
2621
2621
  return context.schema.lists.find((list) => list.value === block.listItem) || (delete parsedBlock.listItem, delete parsedBlock.level), parsedBlock;
2622
2622
  }
2623
2623
  const converterPortableText = {
2624
+ mimeType: "application/x-portable-text",
2624
2625
  serialize: ({
2625
2626
  context,
2626
2627
  event
@@ -2670,9 +2671,9 @@ const converterPortableText = {
2670
2671
  data: parsedBlocks,
2671
2672
  mimeType: "application/x-portable-text"
2672
2673
  };
2673
- },
2674
- mimeType: "application/x-portable-text"
2674
+ }
2675
2675
  }, converterTextHtml = {
2676
+ mimeType: "text/html",
2676
2677
  serialize: ({
2677
2678
  context,
2678
2679
  event
@@ -2717,8 +2718,7 @@ const converterPortableText = {
2717
2718
  unstable_whitespaceOnPasteMode: context.schema.block.options.unstable_whitespaceOnPasteMode
2718
2719
  }),
2719
2720
  mimeType: "text/html"
2720
- }),
2721
- mimeType: "text/html"
2721
+ })
2722
2722
  }, converterTextPlain = {
2723
2723
  mimeType: "text/plain",
2724
2724
  serialize: ({
@@ -3013,6 +3013,8 @@ function createWithEventListeners(editorActor, subscriptions) {
3013
3013
  case "annotation.add":
3014
3014
  case "annotation.remove":
3015
3015
  case "annotation.toggle":
3016
+ case "block.set":
3017
+ case "block.unset":
3016
3018
  case "blur":
3017
3019
  case "data transfer.set":
3018
3020
  case "decorator.add":
@@ -3025,6 +3027,7 @@ function createWithEventListeners(editorActor, subscriptions) {
3025
3027
  case "deserialization.failure":
3026
3028
  case "deserialization.success":
3027
3029
  case "focus":
3030
+ case "insert.block":
3028
3031
  case "insert.block object":
3029
3032
  case "insert.inline object":
3030
3033
  case "insert.span":
@@ -5074,10 +5077,9 @@ function insertBlock({
5074
5077
  });
5075
5078
  } else placement === "before" ? Transforms.insertNodes(editor, block, {
5076
5079
  at: focusBlockPath
5077
- }) : Editor.insertNode(editor, block);
5078
- focusBlock && isEqualToEmptyEditor([focusBlock], schema) && Transforms.removeNodes(editor, {
5080
+ }) : (Editor.insertNode(editor, block), focusBlock && isEqualToEmptyEditor([focusBlock], schema) && Transforms.removeNodes(editor, {
5079
5081
  at: focusBlockPath
5080
- });
5082
+ }));
5081
5083
  } else {
5082
5084
  const lastBlock = Array.from(Editor.nodes(editor, {
5083
5085
  match: (n) => !Editor.isEditor(n),
@@ -5089,7 +5091,47 @@ function insertBlock({
5089
5091
  });
5090
5092
  }
5091
5093
  }
5092
- const dataTransferSetActionImplementation = ({
5094
+ const blockSetBehaviorActionImplementation = ({
5095
+ action
5096
+ }) => {
5097
+ const location = toSlateRange({
5098
+ anchor: {
5099
+ path: action.at,
5100
+ offset: 0
5101
+ },
5102
+ focus: {
5103
+ path: action.at,
5104
+ offset: 0
5105
+ }
5106
+ }, action.editor);
5107
+ if (!location)
5108
+ return;
5109
+ const {
5110
+ at,
5111
+ editor,
5112
+ type,
5113
+ ...payload
5114
+ } = action;
5115
+ Transforms.setNodes(action.editor, payload, {
5116
+ at: location
5117
+ });
5118
+ }, blockUnsetBehaviorActionImplementation = ({
5119
+ action
5120
+ }) => {
5121
+ const location = toSlateRange({
5122
+ anchor: {
5123
+ path: action.at,
5124
+ offset: 0
5125
+ },
5126
+ focus: {
5127
+ path: action.at,
5128
+ offset: 0
5129
+ }
5130
+ }, action.editor);
5131
+ location && Transforms.unsetNodes(action.editor, action.props, {
5132
+ at: location
5133
+ });
5134
+ }, dataTransferSetActionImplementation = ({
5093
5135
  action
5094
5136
  }) => {
5095
5137
  action.dataTransfer.setData(action.mimeType, action.data);
@@ -5146,96 +5188,54 @@ const dataTransferSetActionImplementation = ({
5146
5188
  const keyGenerator = context.keyGenerator, schema = context.schema, editor = action.editor;
5147
5189
  if (!editor.selection)
5148
5190
  return;
5149
- const [focusSpan] = Array.from(Editor.nodes(editor, {
5150
- mode: "lowest",
5151
- at: editor.selection.focus,
5152
- match: (n) => editor.isTextSpan(n),
5153
- voids: !1
5154
- }))[0] ?? [void 0], focusDecorators = focusSpan?.marks?.filter((mark) => schema.decorators.some((decorator) => decorator.value === mark)) ?? [], focusAnnotations = focusSpan?.marks?.filter((mark) => !schema.decorators.some((decorator) => decorator.value === mark)) ?? [], anchorBlockPath = editor.selection.anchor.path.slice(0, 1), focusBlockPath = editor.selection.focus.path.slice(0, 1), focusBlock = Node.descendant(editor, focusBlockPath);
5155
- if (editor.isTextBlock(focusBlock)) {
5156
- const [start, end] = Range.edges(editor.selection), lastFocusBlockChild = focusBlock.children[focusBlock.children.length - 1], atTheEndOfBlock = isEqual(start, {
5157
- path: [...focusBlockPath, focusBlock.children.length - 1],
5158
- offset: editor.isTextSpan(lastFocusBlockChild) ? lastFocusBlockChild.text.length : 0
5159
- }), atTheStartOfBlock = isEqual(end, {
5160
- path: [...focusBlockPath, 0],
5161
- offset: 0
5162
- });
5163
- if (atTheEndOfBlock && Range.isCollapsed(editor.selection)) {
5164
- Editor.insertNode(editor, editor.pteCreateTextBlock({
5165
- decorators: [],
5166
- listItem: focusBlock.listItem,
5167
- level: focusBlock.level
5168
- }));
5169
- return;
5170
- }
5171
- if (atTheStartOfBlock && Range.isCollapsed(editor.selection)) {
5172
- Editor.insertNode(editor, editor.pteCreateTextBlock({
5173
- decorators: focusAnnotations.length === 0 ? focusDecorators : [],
5174
- listItem: focusBlock.listItem,
5175
- level: focusBlock.level
5176
- }));
5177
- const [nextBlockPath] = Path.next(focusBlockPath);
5178
- Transforms.select(editor, {
5191
+ const anchorBlockPath = editor.selection.anchor.path.slice(0, 1), focusBlockPath = editor.selection.focus.path.slice(0, 1), focusBlock = Node.descendant(editor, focusBlockPath);
5192
+ if (editor.isTextBlock(focusBlock) && anchorBlockPath[0] === focusBlockPath[0]) {
5193
+ Editor.withoutNormalizing(editor, () => {
5194
+ if (!editor.selection)
5195
+ return;
5196
+ Transforms.splitNodes(editor, {
5197
+ at: editor.selection
5198
+ });
5199
+ const [nextNode, nextNodePath] = Editor.node(editor, Path.next(focusBlockPath), {
5200
+ depth: 1
5201
+ });
5202
+ if (Transforms.setSelection(editor, {
5179
5203
  anchor: {
5180
- path: [nextBlockPath, 0],
5204
+ path: [...nextNodePath, 0],
5181
5205
  offset: 0
5182
5206
  },
5183
5207
  focus: {
5184
- path: [nextBlockPath, 0],
5208
+ path: [...nextNodePath, 0],
5185
5209
  offset: 0
5186
5210
  }
5187
- });
5188
- return;
5189
- }
5190
- const selectionAcrossBlocks = anchorBlockPath[0] !== focusBlockPath[0];
5191
- if (!atTheStartOfBlock && !atTheEndOfBlock && !selectionAcrossBlocks) {
5192
- Editor.withoutNormalizing(editor, () => {
5193
- if (!editor.selection)
5194
- return;
5195
- Transforms.splitNodes(editor, {
5196
- at: editor.selection
5197
- });
5198
- const [nextNode, nextNodePath] = Editor.node(editor, Path.next(focusBlockPath), {
5199
- depth: 1
5200
- });
5201
- if (Transforms.setSelection(editor, {
5202
- anchor: {
5203
- path: [...nextNodePath, 0],
5204
- offset: 0
5205
- },
5206
- focus: {
5207
- path: [...nextNodePath, 0],
5208
- offset: 0
5209
- }
5210
- }), editor.isTextBlock(nextNode) && nextNode.markDefs && nextNode.markDefs.length > 0) {
5211
- const newMarkDefKeys = /* @__PURE__ */ new Map(), prevNodeSpans = Array.from(Node.children(editor, focusBlockPath)).map((entry) => entry[0]).filter((node) => editor.isTextSpan(node)), children = Node.children(editor, nextNodePath);
5212
- for (const [child, childPath] of children) {
5213
- if (!editor.isTextSpan(child))
5214
- continue;
5215
- const marks = child.marks ?? [];
5216
- for (const mark of marks)
5217
- schema.decorators.some((decorator) => decorator.value === mark) || prevNodeSpans.some((prevNodeSpan) => prevNodeSpan.marks?.includes(mark)) && !newMarkDefKeys.has(mark) && newMarkDefKeys.set(mark, keyGenerator());
5218
- const newMarks = marks.map((mark) => newMarkDefKeys.get(mark) ?? mark);
5219
- isEqual(marks, newMarks) || Transforms.setNodes(editor, {
5220
- marks: newMarks
5221
- }, {
5222
- at: childPath
5223
- });
5224
- }
5225
- const newMarkDefs = nextNode.markDefs.map((markDef) => ({
5226
- ...markDef,
5227
- _key: newMarkDefKeys.get(markDef._key) ?? markDef._key
5228
- }));
5229
- isEqual(nextNode.markDefs, newMarkDefs) || Transforms.setNodes(editor, {
5230
- markDefs: newMarkDefs
5211
+ }), editor.isTextBlock(nextNode) && nextNode.markDefs && nextNode.markDefs.length > 0) {
5212
+ const newMarkDefKeys = /* @__PURE__ */ new Map(), prevNodeSpans = Array.from(Node.children(editor, focusBlockPath)).map((entry) => entry[0]).filter((node) => editor.isTextSpan(node)), children = Node.children(editor, nextNodePath);
5213
+ for (const [child, childPath] of children) {
5214
+ if (!editor.isTextSpan(child))
5215
+ continue;
5216
+ const marks = child.marks ?? [];
5217
+ for (const mark of marks)
5218
+ schema.decorators.some((decorator) => decorator.value === mark) || prevNodeSpans.some((prevNodeSpan) => prevNodeSpan.marks?.includes(mark)) && !newMarkDefKeys.has(mark) && newMarkDefKeys.set(mark, keyGenerator());
5219
+ const newMarks = marks.map((mark) => newMarkDefKeys.get(mark) ?? mark);
5220
+ isEqual(marks, newMarks) || Transforms.setNodes(editor, {
5221
+ marks: newMarks
5231
5222
  }, {
5232
- at: nextNodePath,
5233
- match: (node) => editor.isTextBlock(node)
5223
+ at: childPath
5234
5224
  });
5235
5225
  }
5236
- }), editor.onChange();
5237
- return;
5238
- }
5226
+ const newMarkDefs = nextNode.markDefs.map((markDef) => ({
5227
+ ...markDef,
5228
+ _key: newMarkDefKeys.get(markDef._key) ?? markDef._key
5229
+ }));
5230
+ isEqual(nextNode.markDefs, newMarkDefs) || Transforms.setNodes(editor, {
5231
+ markDefs: newMarkDefs
5232
+ }, {
5233
+ at: nextNodePath,
5234
+ match: (node) => editor.isTextBlock(node)
5235
+ });
5236
+ }
5237
+ }), editor.onChange();
5238
+ return;
5239
5239
  }
5240
5240
  Transforms.splitNodes(editor, {
5241
5241
  always: !0
@@ -5316,6 +5316,27 @@ const dataTransferSetActionImplementation = ({
5316
5316
  text: action.text,
5317
5317
  marks: [...annotations?.map((annotation) => annotation._key) ?? [], ...action.decorators ?? []]
5318
5318
  });
5319
+ }, insertBlockActionImplementation = ({
5320
+ context,
5321
+ action
5322
+ }) => {
5323
+ const parsedBlock = parseBlock({
5324
+ block: action.block,
5325
+ context
5326
+ });
5327
+ if (!parsedBlock)
5328
+ throw new Error(`Failed to parse block ${JSON.stringify(action.block)}`);
5329
+ const fragment = toSlateValue([parsedBlock], {
5330
+ schemaTypes: context.schema
5331
+ })[0];
5332
+ if (!fragment)
5333
+ throw new Error(`Failed to convert block to Slate fragment ${JSON.stringify(parsedBlock)}`);
5334
+ insertBlock({
5335
+ block: fragment,
5336
+ placement: action.placement,
5337
+ editor: action.editor,
5338
+ schema: context.schema
5339
+ });
5319
5340
  }, textBlockSetActionImplementation = ({
5320
5341
  action
5321
5342
  }) => {
@@ -5362,6 +5383,8 @@ const dataTransferSetActionImplementation = ({
5362
5383
  "annotation.add": addAnnotationActionImplementation,
5363
5384
  "annotation.remove": removeAnnotationActionImplementation,
5364
5385
  "annotation.toggle": toggleAnnotationActionImplementation,
5386
+ "block.set": blockSetBehaviorActionImplementation,
5387
+ "block.unset": blockUnsetBehaviorActionImplementation,
5365
5388
  blur: ({
5366
5389
  action
5367
5390
  }) => {
@@ -5452,6 +5475,7 @@ const dataTransferSetActionImplementation = ({
5452
5475
  }
5453
5476
  });
5454
5477
  },
5478
+ "insert.block": insertBlockActionImplementation,
5455
5479
  "insert.blocks": insertBlocksActionImplementation,
5456
5480
  "insert.block object": insertBlockObjectActionImplementation,
5457
5481
  "insert.break": insertBreakActionImplementation,
@@ -5601,13 +5625,6 @@ function performAction({
5601
5625
  });
5602
5626
  break;
5603
5627
  }
5604
- case "select": {
5605
- behaviorActionImplementations.select({
5606
- context,
5607
- action
5608
- });
5609
- break;
5610
- }
5611
5628
  default:
5612
5629
  performDefaultAction({
5613
5630
  context,
@@ -5641,6 +5658,20 @@ function performDefaultAction({
5641
5658
  });
5642
5659
  break;
5643
5660
  }
5661
+ case "block.set": {
5662
+ behaviorActionImplementations["block.set"]({
5663
+ context,
5664
+ action
5665
+ });
5666
+ break;
5667
+ }
5668
+ case "block.unset": {
5669
+ behaviorActionImplementations["block.unset"]({
5670
+ context,
5671
+ action
5672
+ });
5673
+ break;
5674
+ }
5644
5675
  case "blur": {
5645
5676
  behaviorActionImplementations.blur({
5646
5677
  context,
@@ -5725,6 +5756,13 @@ function performDefaultAction({
5725
5756
  });
5726
5757
  break;
5727
5758
  }
5759
+ case "insert.block": {
5760
+ behaviorActionImplementations["insert.block"]({
5761
+ context,
5762
+ action
5763
+ });
5764
+ break;
5765
+ }
5728
5766
  case "insert.blocks": {
5729
5767
  behaviorActionImplementations["insert.blocks"]({
5730
5768
  context,
@@ -5886,13 +5924,11 @@ function performDefaultAction({
5886
5924
  });
5887
5925
  break;
5888
5926
  }
5889
- case "text block.unset": {
5927
+ default:
5890
5928
  behaviorActionImplementations["text block.unset"]({
5891
5929
  context,
5892
5930
  action
5893
5931
  });
5894
- break;
5895
- }
5896
5932
  }
5897
5933
  }
5898
5934
  function getActiveDecorators({
@@ -6273,6 +6309,11 @@ const editorMachine = setup({
6273
6309
  event
6274
6310
  }) => event)
6275
6311
  },
6312
+ "block.*": {
6313
+ actions: emit(({
6314
+ event
6315
+ }) => event)
6316
+ },
6276
6317
  blur: {
6277
6318
  actions: emit(({
6278
6319
  event