@portabletext/editor 1.7.0 → 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.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,
@@ -4626,17 +4668,19 @@ function createSlateEditor(config) {
4626
4668
  KEY_TO_VALUE_ELEMENT.set(instance, {}), KEY_TO_SLATE_ELEMENT.set(instance, {});
4627
4669
  for (const subscription of subscriptions)
4628
4670
  unsubscriptions.push(subscription());
4629
- const initialValue = [instance.pteCreateTextBlock({
4630
- decorators: []
4631
- })], slateEditor = {
4632
- instance,
4633
- initialValue,
4634
- destroy: () => {
4671
+ config.editorActor.subscribe((snapshot) => {
4672
+ if (snapshot.status !== "active") {
4635
4673
  debug$7("Destroying Slate editor"), instance.destroy();
4636
4674
  for (const unsubscribe of unsubscriptions)
4637
4675
  unsubscribe();
4638
4676
  subscriptions = [], unsubscriptions = [];
4639
4677
  }
4678
+ });
4679
+ const initialValue = [instance.pteCreateTextBlock({
4680
+ decorators: []
4681
+ })], slateEditor = {
4682
+ instance,
4683
+ initialValue
4640
4684
  };
4641
4685
  return slateEditors.set(config.editorActor, slateEditor), slateEditor;
4642
4686
  }
@@ -4729,32 +4773,18 @@ function createEditableAPI(editor, editorActor) {
4729
4773
  at: editor.selection
4730
4774
  }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types2.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types2)?.focus.path || [];
4731
4775
  },
4732
- insertBlock: (type, value) => {
4733
- const block = toSlateValue([{
4734
- _key: editorActor.getSnapshot().context.keyGenerator(),
4735
- _type: type.name,
4736
- ...value || {}
4737
- }], {
4738
- schemaTypes: editorActor.getSnapshot().context.schema
4739
- })[0];
4740
- if (!editor.selection) {
4741
- const lastBlock = Array.from(slate.Editor.nodes(editor, {
4742
- match: (n) => !slate.Editor.isEditor(n),
4743
- at: [],
4744
- reverse: !0
4745
- }))[0];
4746
- return slate.Editor.insertNode(editor, block), lastBlock && isEqualToEmptyEditor([lastBlock[0]], types2) && slate.Transforms.removeNodes(editor, {
4747
- at: lastBlock[1]
4748
- }), 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
4749
4786
  }
4750
- const focusBlock = Array.from(slate.Editor.nodes(editor, {
4751
- at: editor.selection.focus.path.slice(0, 1),
4752
- match: (n) => n._type === types2.block.name
4753
- }))[0];
4754
- return slate.Editor.insertNode(editor, block), focusBlock && isEqualToEmptyEditor([focusBlock[0]], types2) && slate.Transforms.removeNodes(editor, {
4755
- at: focusBlock[1]
4756
- }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types2.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types2)?.focus.path || [];
4757
- },
4787
+ }),
4758
4788
  hasBlockStyle: (style) => {
4759
4789
  try {
4760
4790
  return editor.pteHasBlockStyle(style);
@@ -4924,6 +4954,35 @@ function createEditableAPI(editor, editorActor) {
4924
4954
  }
4925
4955
  };
4926
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
+ };
4927
4986
  function isAnnotationActive({
4928
4987
  editor,
4929
4988
  annotation
@@ -5304,6 +5363,7 @@ const addAnnotationActionImplementation = ({
5304
5363
  at: location
5305
5364
  });
5306
5365
  },
5366
+ "insert block object": insertBlockObjectActionImplementation,
5307
5367
  "insert break": insertBreakActionImplementation,
5308
5368
  "insert soft break": insertSoftBreakActionImplementation,
5309
5369
  "insert text": ({
@@ -5361,6 +5421,13 @@ function performAction({
5361
5421
  });
5362
5422
  break;
5363
5423
  }
5424
+ case "insert block object": {
5425
+ behaviorActionImplementations["insert block object"]({
5426
+ context,
5427
+ action
5428
+ });
5429
+ break;
5430
+ }
5364
5431
  case "insert text block": {
5365
5432
  behaviorActionImplementations["insert text block"]({
5366
5433
  context,
@@ -5891,7 +5958,7 @@ class PortableTextEditor extends react.Component {
5891
5958
  constructor(props) {
5892
5959
  if (super(props), props.editor) {
5893
5960
  const editor = props.editor;
5894
- this.editorActor = editor._internal.editorActor, this.editorActor.start(), this.schemaTypes = this.editorActor.getSnapshot().context.schema;
5961
+ this.editorActor = editor._internal.editorActor, this.slateEditor = editor._internal.slateEditor, this.editorActor.start(), this.schemaTypes = this.editorActor.getSnapshot().context.schema;
5895
5962
  } else {
5896
5963
  if (!props.schemaType)
5897
5964
  throw new Error('PortableTextEditor: missing "schemaType" property');
@@ -5900,16 +5967,16 @@ class PortableTextEditor extends react.Component {
5900
5967
  keyGenerator: props.keyGenerator || defaultKeyGenerator,
5901
5968
  schema: this.schemaTypes
5902
5969
  }
5903
- }), this.editorActor.start(), props.readOnly && this.editorActor.send({
5970
+ }), this.editorActor.start(), this.slateEditor = createSlateEditor({
5971
+ editorActor: this.editorActor
5972
+ }), props.readOnly && this.editorActor.send({
5904
5973
  type: "toggle readOnly"
5905
5974
  }), props.maxBlocks && this.editorActor.send({
5906
5975
  type: "update maxBlocks",
5907
5976
  maxBlocks: props.maxBlocks === void 0 ? void 0 : Number.parseInt(props.maxBlocks.toString(), 10)
5908
5977
  });
5909
5978
  }
5910
- this.slateEditor = createSlateEditor({
5911
- editorActor: this.editorActor
5912
- }), this.editable = createEditableAPI(this.slateEditor.instance, this.editorActor);
5979
+ this.editable = createEditableAPI(this.slateEditor.instance, this.editorActor);
5913
5980
  }
5914
5981
  componentDidUpdate(prevProps) {
5915
5982
  !this.props.editor && !prevProps.editor && this.props.schemaType !== prevProps.schemaType && (this.schemaTypes = getPortableTextMemberSchemaTypes(this.props.schemaType.hasOwnProperty("jsonType") ? this.props.schemaType : compileType(this.props.schemaType)), this.editorActor.send({
@@ -5922,9 +5989,6 @@ class PortableTextEditor extends react.Component {
5922
5989
  maxBlocks: this.props.maxBlocks === void 0 ? void 0 : Number.parseInt(this.props.maxBlocks.toString(), 10)
5923
5990
  })), this.props.editorRef !== prevProps.editorRef && this.props.editorRef && (this.props.editorRef.current = this);
5924
5991
  }
5925
- componentWillUnmount() {
5926
- this.slateEditor.destroy();
5927
- }
5928
5992
  setEditable = (editable) => {
5929
5993
  this.editable = {
5930
5994
  ...this.editable,
@@ -6711,7 +6775,7 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6711
6775
  });
6712
6776
  PortableTextEditable.displayName = "ForwardRef(PortableTextEditable)";
6713
6777
  function useEditor(config) {
6714
- const $ = reactCompilerRuntime.c(17), t0 = config.keyGenerator ?? defaultKeyGenerator;
6778
+ const $ = reactCompilerRuntime.c(20), t0 = config.keyGenerator ?? defaultKeyGenerator;
6715
6779
  let t1;
6716
6780
  $[0] !== config.schema || $[1] !== config.schemaDefinition ? (t1 = config.schemaDefinition ? compileSchemaDefinition(config.schemaDefinition) : getPortableTextMemberSchemaTypes(config.schema.hasOwnProperty("jsonType") ? config.schema : compileType(config.schema)), $[0] = config.schema, $[1] = config.schemaDefinition, $[2] = t1) : t1 = $[2];
6717
6781
  let t2;
@@ -6722,22 +6786,28 @@ function useEditor(config) {
6722
6786
  schema: t1
6723
6787
  }
6724
6788
  }, $[3] = config.behaviors, $[4] = t0, $[5] = t1, $[6] = t2) : t2 = $[6];
6725
- const editorActor = react$1.useActorRef(editorMachine, t2), readOnly = react$1.useSelector(editorActor, _temp);
6726
- let t3, t4;
6727
- $[7] !== editorActor ? (t3 = (event) => {
6728
- editorActor.send(event);
6729
- }, t4 = (event_0, listener) => editorActor.on(event_0, listener), $[7] = editorActor, $[8] = t3, $[9] = t4) : (t3 = $[8], t4 = $[9]);
6730
- let t5;
6731
- $[10] !== editorActor ? (t5 = {
6789
+ const editorActor = react$1.useActorRef(editorMachine, t2);
6790
+ let t3;
6791
+ $[7] !== editorActor ? (t3 = createSlateEditor({
6732
6792
  editorActor
6733
- }, $[10] = editorActor, $[11] = t5) : t5 = $[11];
6793
+ }), $[7] = editorActor, $[8] = t3) : t3 = $[8];
6794
+ const slateEditor = t3, readOnly = react$1.useSelector(editorActor, _temp);
6795
+ let t4, t5;
6796
+ $[9] !== editorActor ? (t4 = (event) => {
6797
+ editorActor.send(event);
6798
+ }, t5 = (event_0, listener) => editorActor.on(event_0, listener), $[9] = editorActor, $[10] = t4, $[11] = t5) : (t4 = $[10], t5 = $[11]);
6734
6799
  let t6;
6735
- return $[12] !== readOnly || $[13] !== t3 || $[14] !== t4 || $[15] !== t5 ? (t6 = {
6736
- send: t3,
6737
- on: t4,
6800
+ $[12] !== editorActor || $[13] !== slateEditor ? (t6 = {
6801
+ editorActor,
6802
+ slateEditor
6803
+ }, $[12] = editorActor, $[13] = slateEditor, $[14] = t6) : t6 = $[14];
6804
+ let t7;
6805
+ return $[15] !== readOnly || $[16] !== t4 || $[17] !== t5 || $[18] !== t6 ? (t7 = {
6806
+ send: t4,
6807
+ on: t5,
6738
6808
  readOnly,
6739
- _internal: t5
6740
- }, $[12] = readOnly, $[13] = t3, $[14] = t4, $[15] = t5, $[16] = t6) : t6 = $[16], t6;
6809
+ _internal: t6
6810
+ }, $[15] = readOnly, $[16] = t4, $[17] = t5, $[18] = t6, $[19] = t7) : t7 = $[19], t7;
6741
6811
  }
6742
6812
  function _temp(s) {
6743
6813
  return s.context.readOnly;