@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.mjs CHANGED
@@ -317,6 +317,21 @@ const breakingBlockObject = {
317
317
  blockObjects: coreBlockObjectBehaviors,
318
318
  lists: coreListBehaviors
319
319
  };
320
+ function isPortableTextSpan(node) {
321
+ 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"));
322
+ }
323
+ function isPortableTextBlock(node) {
324
+ return (
325
+ // A block doesn't _have_ to be named 'block' - to differentiate between
326
+ // allowed child types and marks, one might name them differently
327
+ typeof node._type == "string" && // Toolkit-types like nested spans are @-prefixed
328
+ node._type[0] !== "@" && // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array
329
+ (!("markDefs" in node) || !node.markDefs || Array.isArray(node.markDefs) && // Every mark definition needs to have an `_key` to be mappable in child spans
330
+ node.markDefs.every((def) => typeof def._key == "string")) && // `children` is required and needs to be an array
331
+ "children" in node && Array.isArray(node.children) && // All children are objects with `_type` (usually spans, but can contain other stuff)
332
+ node.children.every((child) => typeof child == "object" && "_type" in child)
333
+ );
334
+ }
320
335
  function createMarkdownBehaviors(config) {
321
336
  const automaticBlockquoteOnSpace = {
322
337
  on: "insert text",
@@ -329,7 +344,7 @@ function createMarkdownBehaviors(config) {
329
344
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
330
345
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
331
346
  return !1;
332
- const caretAtTheEndOfQuote = context.selection.focus.offset === 1, looksLikeMarkdownQuote = /^>/.test(focusSpan.node.text), blockquoteStyle = config.mapBlockquoteStyle(context.schema);
347
+ const caretAtTheEndOfQuote = context.selection.focus.offset === 1, looksLikeMarkdownQuote = /^>/.test(focusSpan.node.text), blockquoteStyle = config.mapBlockquoteStyle?.(context.schema);
333
348
  return caretAtTheEndOfQuote && looksLikeMarkdownQuote && blockquoteStyle !== void 0 ? {
334
349
  focusTextBlock,
335
350
  focusSpan,
@@ -364,6 +379,48 @@ function createMarkdownBehaviors(config) {
364
379
  }
365
380
  }
366
381
  }]]
382
+ }, automaticBreak = {
383
+ on: "insert text",
384
+ guard: ({
385
+ context,
386
+ event
387
+ }) => {
388
+ if (event.text !== "-")
389
+ return !1;
390
+ const breakObject = config.mapBreakObject?.(context.schema), focusBlock = getFocusTextBlock(context), selectionCollapsed = selectionIsCollapsed(context);
391
+ if (!breakObject || !focusBlock || !selectionCollapsed)
392
+ return !1;
393
+ const onlyText = focusBlock.node.children.every(isPortableTextSpan), blockText = focusBlock.node.children.map((child) => child.text ?? "").join("");
394
+ return onlyText && blockText === "--" ? {
395
+ breakObject,
396
+ focusBlock
397
+ } : !1;
398
+ },
399
+ actions: [() => [{
400
+ type: "insert text",
401
+ text: "-"
402
+ }], (_, {
403
+ breakObject,
404
+ focusBlock
405
+ }) => [{
406
+ type: "insert block object",
407
+ ...breakObject
408
+ }, {
409
+ type: "delete",
410
+ selection: {
411
+ anchor: {
412
+ path: focusBlock.path,
413
+ offset: 0
414
+ },
415
+ focus: {
416
+ path: focusBlock.path,
417
+ offset: 0
418
+ }
419
+ }
420
+ }, {
421
+ type: "insert text block",
422
+ decorators: []
423
+ }]]
367
424
  }, automaticHeadingOnSpace = {
368
425
  on: "insert text",
369
426
  guard: ({
@@ -378,7 +435,7 @@ function createMarkdownBehaviors(config) {
378
435
  const markdownHeadingSearch = /^#+/.exec(focusSpan.node.text), headingLevel = markdownHeadingSearch ? markdownHeadingSearch[0].length : void 0;
379
436
  if (context.selection.focus.offset !== headingLevel)
380
437
  return !1;
381
- const headingStyle = headingLevel !== void 0 ? config.mapHeadingStyle(context.schema, headingLevel) : void 0;
438
+ const headingStyle = headingLevel !== void 0 ? config.mapHeadingStyle?.(context.schema, headingLevel) : void 0;
382
439
  return headingLevel !== void 0 && headingStyle !== void 0 ? {
383
440
  focusTextBlock,
384
441
  focusSpan,
@@ -423,7 +480,7 @@ function createMarkdownBehaviors(config) {
423
480
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
424
481
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
425
482
  return !1;
426
- const atTheBeginningOfBLock = focusTextBlock.node.children[0]._key === focusSpan.node._key && context.selection.focus.offset === 0, defaultStyle = config.mapDefaultStyle(context.schema);
483
+ const atTheBeginningOfBLock = focusTextBlock.node.children[0]._key === focusSpan.node._key && context.selection.focus.offset === 0, defaultStyle = config.mapDefaultStyle?.(context.schema);
427
484
  return atTheBeginningOfBLock && defaultStyle && focusTextBlock.node.style !== defaultStyle ? {
428
485
  defaultStyle,
429
486
  focusTextBlock
@@ -448,7 +505,7 @@ function createMarkdownBehaviors(config) {
448
505
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
449
506
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
450
507
  return !1;
451
- const defaultStyle = config.mapDefaultStyle(context.schema), looksLikeUnorderedList = /^(-|\*)/.test(focusSpan.node.text), unorderedListStyle = config.mapUnorderedListStyle(context.schema), caretAtTheEndOfUnorderedList = context.selection.focus.offset === 1;
508
+ const defaultStyle = config.mapDefaultStyle?.(context.schema), looksLikeUnorderedList = /^(-|\*)/.test(focusSpan.node.text), unorderedListStyle = config.mapUnorderedListStyle?.(context.schema), caretAtTheEndOfUnorderedList = context.selection.focus.offset === 1;
452
509
  if (defaultStyle && caretAtTheEndOfUnorderedList && looksLikeUnorderedList && unorderedListStyle !== void 0)
453
510
  return {
454
511
  focusTextBlock,
@@ -457,7 +514,7 @@ function createMarkdownBehaviors(config) {
457
514
  listItemLength: 1,
458
515
  style: defaultStyle
459
516
  };
460
- const looksLikeOrderedList = /^1./.test(focusSpan.node.text), orderedListStyle = config.mapOrderedListStyle(context.schema), caretAtTheEndOfOrderedList = context.selection.focus.offset === 2;
517
+ const looksLikeOrderedList = /^1./.test(focusSpan.node.text), orderedListStyle = config.mapOrderedListStyle?.(context.schema), caretAtTheEndOfOrderedList = context.selection.focus.offset === 2;
461
518
  return defaultStyle && caretAtTheEndOfOrderedList && looksLikeOrderedList && orderedListStyle !== void 0 ? {
462
519
  focusTextBlock,
463
520
  focusSpan,
@@ -495,7 +552,7 @@ function createMarkdownBehaviors(config) {
495
552
  }
496
553
  }]]
497
554
  };
498
- return [automaticBlockquoteOnSpace, automaticHeadingOnSpace, clearStyleOnBackspace, automaticListOnSpace];
555
+ return [automaticBlockquoteOnSpace, automaticBreak, automaticHeadingOnSpace, clearStyleOnBackspace, automaticListOnSpace];
499
556
  }
500
557
  function getPortableTextMemberSchemaTypes(portableTextType) {
501
558
  if (!portableTextType)
@@ -3925,21 +3982,6 @@ function createWithPortableTextLists(types) {
3925
3982
  }, editor;
3926
3983
  };
3927
3984
  }
3928
- function isPortableTextSpan(node) {
3929
- 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"));
3930
- }
3931
- function isPortableTextBlock(node) {
3932
- return (
3933
- // A block doesn't _have_ to be named 'block' - to differentiate between
3934
- // allowed child types and marks, one might name them differently
3935
- typeof node._type == "string" && // Toolkit-types like nested spans are @-prefixed
3936
- node._type[0] !== "@" && // `markDefs` isn't _required_ per say, but if it's there, it needs to be an array
3937
- (!("markDefs" in node) || !node.markDefs || Array.isArray(node.markDefs) && // Every mark definition needs to have an `_key` to be mappable in child spans
3938
- node.markDefs.every((def) => typeof def._key == "string")) && // `children` is required and needs to be an array
3939
- "children" in node && Array.isArray(node.children) && // All children are objects with `_type` (usually spans, but can contain other stuff)
3940
- node.children.every((child) => typeof child == "object" && "_type" in child)
3941
- );
3942
- }
3943
3985
  function getPreviousSpan({
3944
3986
  editor,
3945
3987
  blockPath,
@@ -4647,17 +4689,19 @@ function createSlateEditor(config) {
4647
4689
  KEY_TO_VALUE_ELEMENT.set(instance, {}), KEY_TO_SLATE_ELEMENT.set(instance, {});
4648
4690
  for (const subscription of subscriptions)
4649
4691
  unsubscriptions.push(subscription());
4650
- const initialValue = [instance.pteCreateTextBlock({
4651
- decorators: []
4652
- })], slateEditor = {
4653
- instance,
4654
- initialValue,
4655
- destroy: () => {
4692
+ config.editorActor.subscribe((snapshot) => {
4693
+ if (snapshot.status !== "active") {
4656
4694
  debug$7("Destroying Slate editor"), instance.destroy();
4657
4695
  for (const unsubscribe of unsubscriptions)
4658
4696
  unsubscribe();
4659
4697
  subscriptions = [], unsubscriptions = [];
4660
4698
  }
4699
+ });
4700
+ const initialValue = [instance.pteCreateTextBlock({
4701
+ decorators: []
4702
+ })], slateEditor = {
4703
+ instance,
4704
+ initialValue
4661
4705
  };
4662
4706
  return slateEditors.set(config.editorActor, slateEditor), slateEditor;
4663
4707
  }
@@ -4750,32 +4794,18 @@ function createEditableAPI(editor, editorActor) {
4750
4794
  at: editor.selection
4751
4795
  }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path || [];
4752
4796
  },
4753
- insertBlock: (type, value) => {
4754
- const block = toSlateValue([{
4755
- _key: editorActor.getSnapshot().context.keyGenerator(),
4756
- _type: type.name,
4757
- ...value || {}
4758
- }], {
4759
- schemaTypes: editorActor.getSnapshot().context.schema
4760
- })[0];
4761
- if (!editor.selection) {
4762
- const lastBlock = Array.from(Editor.nodes(editor, {
4763
- match: (n) => !Editor.isEditor(n),
4764
- at: [],
4765
- reverse: !0
4766
- }))[0];
4767
- return Editor.insertNode(editor, block), lastBlock && isEqualToEmptyEditor([lastBlock[0]], types) && Transforms.removeNodes(editor, {
4768
- at: lastBlock[1]
4769
- }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path ?? [];
4797
+ insertBlock: (type, value) => insertBlockObjectActionImplementation({
4798
+ context: {
4799
+ keyGenerator: editorActor.getSnapshot().context.keyGenerator,
4800
+ schema: types
4801
+ },
4802
+ action: {
4803
+ type: "insert block object",
4804
+ name: type.name,
4805
+ value,
4806
+ editor
4770
4807
  }
4771
- const focusBlock = Array.from(Editor.nodes(editor, {
4772
- at: editor.selection.focus.path.slice(0, 1),
4773
- match: (n) => n._type === types.block.name
4774
- }))[0];
4775
- return Editor.insertNode(editor, block), focusBlock && isEqualToEmptyEditor([focusBlock[0]], types) && Transforms.removeNodes(editor, {
4776
- at: focusBlock[1]
4777
- }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path || [];
4778
- },
4808
+ }),
4779
4809
  hasBlockStyle: (style) => {
4780
4810
  try {
4781
4811
  return editor.pteHasBlockStyle(style);
@@ -4945,6 +4975,35 @@ function createEditableAPI(editor, editorActor) {
4945
4975
  }
4946
4976
  };
4947
4977
  }
4978
+ const insertBlockObjectActionImplementation = ({
4979
+ context,
4980
+ action
4981
+ }) => {
4982
+ const editor = action.editor, types = context.schema, block = toSlateValue([{
4983
+ _key: context.keyGenerator(),
4984
+ _type: action.name,
4985
+ ...action.value ? action.value : {}
4986
+ }], {
4987
+ schemaTypes: context.schema
4988
+ })[0];
4989
+ if (!editor.selection) {
4990
+ const lastBlock = Array.from(Editor.nodes(editor, {
4991
+ match: (n) => !Editor.isEditor(n),
4992
+ at: [],
4993
+ reverse: !0
4994
+ }))[0];
4995
+ return Editor.insertNode(editor, block), lastBlock && isEqualToEmptyEditor([lastBlock[0]], types) && Transforms.removeNodes(editor, {
4996
+ at: lastBlock[1]
4997
+ }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path ?? [];
4998
+ }
4999
+ const focusBlock = Array.from(Editor.nodes(editor, {
5000
+ at: editor.selection.focus.path.slice(0, 1),
5001
+ match: (n) => n._type === types.block.name
5002
+ }))[0];
5003
+ return Editor.insertNode(editor, block), focusBlock && isEqualToEmptyEditor([focusBlock[0]], types) && Transforms.removeNodes(editor, {
5004
+ at: focusBlock[1]
5005
+ }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path || [];
5006
+ };
4948
5007
  function isAnnotationActive({
4949
5008
  editor,
4950
5009
  annotation
@@ -5325,6 +5384,7 @@ const addAnnotationActionImplementation = ({
5325
5384
  at: location
5326
5385
  });
5327
5386
  },
5387
+ "insert block object": insertBlockObjectActionImplementation,
5328
5388
  "insert break": insertBreakActionImplementation,
5329
5389
  "insert soft break": insertSoftBreakActionImplementation,
5330
5390
  "insert text": ({
@@ -5382,6 +5442,13 @@ function performAction({
5382
5442
  });
5383
5443
  break;
5384
5444
  }
5445
+ case "insert block object": {
5446
+ behaviorActionImplementations["insert block object"]({
5447
+ context,
5448
+ action
5449
+ });
5450
+ break;
5451
+ }
5385
5452
  case "insert text block": {
5386
5453
  behaviorActionImplementations["insert text block"]({
5387
5454
  context,
@@ -5912,7 +5979,7 @@ class PortableTextEditor extends Component {
5912
5979
  constructor(props) {
5913
5980
  if (super(props), props.editor) {
5914
5981
  const editor = props.editor;
5915
- this.editorActor = editor._internal.editorActor, this.editorActor.start(), this.schemaTypes = this.editorActor.getSnapshot().context.schema;
5982
+ this.editorActor = editor._internal.editorActor, this.slateEditor = editor._internal.slateEditor, this.editorActor.start(), this.schemaTypes = this.editorActor.getSnapshot().context.schema;
5916
5983
  } else {
5917
5984
  if (!props.schemaType)
5918
5985
  throw new Error('PortableTextEditor: missing "schemaType" property');
@@ -5921,16 +5988,16 @@ class PortableTextEditor extends Component {
5921
5988
  keyGenerator: props.keyGenerator || defaultKeyGenerator,
5922
5989
  schema: this.schemaTypes
5923
5990
  }
5924
- }), this.editorActor.start(), props.readOnly && this.editorActor.send({
5991
+ }), this.editorActor.start(), this.slateEditor = createSlateEditor({
5992
+ editorActor: this.editorActor
5993
+ }), props.readOnly && this.editorActor.send({
5925
5994
  type: "toggle readOnly"
5926
5995
  }), props.maxBlocks && this.editorActor.send({
5927
5996
  type: "update maxBlocks",
5928
5997
  maxBlocks: props.maxBlocks === void 0 ? void 0 : Number.parseInt(props.maxBlocks.toString(), 10)
5929
5998
  });
5930
5999
  }
5931
- this.slateEditor = createSlateEditor({
5932
- editorActor: this.editorActor
5933
- }), this.editable = createEditableAPI(this.slateEditor.instance, this.editorActor);
6000
+ this.editable = createEditableAPI(this.slateEditor.instance, this.editorActor);
5934
6001
  }
5935
6002
  componentDidUpdate(prevProps) {
5936
6003
  !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({
@@ -5943,9 +6010,6 @@ class PortableTextEditor extends Component {
5943
6010
  maxBlocks: this.props.maxBlocks === void 0 ? void 0 : Number.parseInt(this.props.maxBlocks.toString(), 10)
5944
6011
  })), this.props.editorRef !== prevProps.editorRef && this.props.editorRef && (this.props.editorRef.current = this);
5945
6012
  }
5946
- componentWillUnmount() {
5947
- this.slateEditor.destroy();
5948
- }
5949
6013
  setEditable = (editable) => {
5950
6014
  this.editable = {
5951
6015
  ...this.editable,
@@ -6732,7 +6796,7 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6732
6796
  });
6733
6797
  PortableTextEditable.displayName = "ForwardRef(PortableTextEditable)";
6734
6798
  function useEditor(config) {
6735
- const $ = c(17), t0 = config.keyGenerator ?? defaultKeyGenerator;
6799
+ const $ = c(20), t0 = config.keyGenerator ?? defaultKeyGenerator;
6736
6800
  let t1;
6737
6801
  $[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];
6738
6802
  let t2;
@@ -6743,22 +6807,28 @@ function useEditor(config) {
6743
6807
  schema: t1
6744
6808
  }
6745
6809
  }, $[3] = config.behaviors, $[4] = t0, $[5] = t1, $[6] = t2) : t2 = $[6];
6746
- const editorActor = useActorRef(editorMachine, t2), readOnly = useSelector(editorActor, _temp);
6747
- let t3, t4;
6748
- $[7] !== editorActor ? (t3 = (event) => {
6749
- editorActor.send(event);
6750
- }, t4 = (event_0, listener) => editorActor.on(event_0, listener), $[7] = editorActor, $[8] = t3, $[9] = t4) : (t3 = $[8], t4 = $[9]);
6751
- let t5;
6752
- $[10] !== editorActor ? (t5 = {
6810
+ const editorActor = useActorRef(editorMachine, t2);
6811
+ let t3;
6812
+ $[7] !== editorActor ? (t3 = createSlateEditor({
6753
6813
  editorActor
6754
- }, $[10] = editorActor, $[11] = t5) : t5 = $[11];
6814
+ }), $[7] = editorActor, $[8] = t3) : t3 = $[8];
6815
+ const slateEditor = t3, readOnly = useSelector(editorActor, _temp);
6816
+ let t4, t5;
6817
+ $[9] !== editorActor ? (t4 = (event) => {
6818
+ editorActor.send(event);
6819
+ }, t5 = (event_0, listener) => editorActor.on(event_0, listener), $[9] = editorActor, $[10] = t4, $[11] = t5) : (t4 = $[10], t5 = $[11]);
6755
6820
  let t6;
6756
- return $[12] !== readOnly || $[13] !== t3 || $[14] !== t4 || $[15] !== t5 ? (t6 = {
6757
- send: t3,
6758
- on: t4,
6821
+ $[12] !== editorActor || $[13] !== slateEditor ? (t6 = {
6822
+ editorActor,
6823
+ slateEditor
6824
+ }, $[12] = editorActor, $[13] = slateEditor, $[14] = t6) : t6 = $[14];
6825
+ let t7;
6826
+ return $[15] !== readOnly || $[16] !== t4 || $[17] !== t5 || $[18] !== t6 ? (t7 = {
6827
+ send: t4,
6828
+ on: t5,
6759
6829
  readOnly,
6760
- _internal: t5
6761
- }, $[12] = readOnly, $[13] = t3, $[14] = t4, $[15] = t5, $[16] = t6) : t6 = $[16], t6;
6830
+ _internal: t6
6831
+ }, $[15] = readOnly, $[16] = t4, $[17] = t5, $[18] = t6, $[19] = t7) : t7 = $[19], t7;
6762
6832
  }
6763
6833
  function _temp(s) {
6764
6834
  return s.context.readOnly;