@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 CHANGED
@@ -124,6 +124,13 @@ export declare type Behavior<
124
124
  */
125
125
  export declare type BehaviorActionIntend =
126
126
  | BehaviorEvent
127
+ | {
128
+ type: 'insert block object'
129
+ name: string
130
+ value?: {
131
+ [prop: string]: unknown
132
+ }
133
+ }
127
134
  | {
128
135
  type: 'insert text block'
129
136
  decorators: Array<string>
@@ -524,14 +531,6 @@ export declare const coreBehaviors: Behavior<
524
531
  true
525
532
  >[]
526
533
 
527
- /**
528
- * @internal
529
- */
530
- export declare type createEditorOptions = {
531
- editorActor: EditorActor
532
- subscriptions: Array<() => () => void>
533
- }
534
-
535
534
  /**
536
535
  * @alpha
537
536
  */
@@ -5787,18 +5786,28 @@ export declare type LoadingChange = {
5787
5786
  * @alpha
5788
5787
  */
5789
5788
  export declare type MarkdownBehaviorsConfig = {
5790
- mapDefaultStyle: (schema: PortableTextMemberSchemaTypes) => string | undefined
5791
- mapHeadingStyle: (
5789
+ mapBreakObject?: (schema: PortableTextMemberSchemaTypes) =>
5790
+ | {
5791
+ name: string
5792
+ value?: {
5793
+ [prop: string]: unknown
5794
+ }
5795
+ }
5796
+ | undefined
5797
+ mapDefaultStyle?: (
5798
+ schema: PortableTextMemberSchemaTypes,
5799
+ ) => string | undefined
5800
+ mapHeadingStyle?: (
5792
5801
  schema: PortableTextMemberSchemaTypes,
5793
5802
  level: number,
5794
5803
  ) => string | undefined
5795
- mapBlockquoteStyle: (
5804
+ mapBlockquoteStyle?: (
5796
5805
  schema: PortableTextMemberSchemaTypes,
5797
5806
  ) => string | undefined
5798
- mapUnorderedListStyle: (
5807
+ mapUnorderedListStyle?: (
5799
5808
  schema: PortableTextMemberSchemaTypes,
5800
5809
  ) => string | undefined
5801
- mapOrderedListStyle: (
5810
+ mapOrderedListStyle?: (
5802
5811
  schema: PortableTextMemberSchemaTypes,
5803
5812
  ) => string | undefined
5804
5813
  }
@@ -6000,9 +6009,9 @@ export declare class PortableTextEditor extends Component<
6000
6009
  | []
6001
6010
  | [
6002
6011
  (
6003
- | PortableTextSpan
6012
+ | PortableTextTextBlock<PortableTextObject | PortableTextSpan>
6004
6013
  | PortableTextObject
6005
- | PortableTextTextBlock<PortableTextSpan | PortableTextObject>
6014
+ | PortableTextSpan
6006
6015
  | undefined
6007
6016
  ),
6008
6017
  Path | undefined,
package/lib/index.d.ts CHANGED
@@ -124,6 +124,13 @@ export declare type Behavior<
124
124
  */
125
125
  export declare type BehaviorActionIntend =
126
126
  | BehaviorEvent
127
+ | {
128
+ type: 'insert block object'
129
+ name: string
130
+ value?: {
131
+ [prop: string]: unknown
132
+ }
133
+ }
127
134
  | {
128
135
  type: 'insert text block'
129
136
  decorators: Array<string>
@@ -524,14 +531,6 @@ export declare const coreBehaviors: Behavior<
524
531
  true
525
532
  >[]
526
533
 
527
- /**
528
- * @internal
529
- */
530
- export declare type createEditorOptions = {
531
- editorActor: EditorActor
532
- subscriptions: Array<() => () => void>
533
- }
534
-
535
534
  /**
536
535
  * @alpha
537
536
  */
@@ -5787,18 +5786,28 @@ export declare type LoadingChange = {
5787
5786
  * @alpha
5788
5787
  */
5789
5788
  export declare type MarkdownBehaviorsConfig = {
5790
- mapDefaultStyle: (schema: PortableTextMemberSchemaTypes) => string | undefined
5791
- mapHeadingStyle: (
5789
+ mapBreakObject?: (schema: PortableTextMemberSchemaTypes) =>
5790
+ | {
5791
+ name: string
5792
+ value?: {
5793
+ [prop: string]: unknown
5794
+ }
5795
+ }
5796
+ | undefined
5797
+ mapDefaultStyle?: (
5798
+ schema: PortableTextMemberSchemaTypes,
5799
+ ) => string | undefined
5800
+ mapHeadingStyle?: (
5792
5801
  schema: PortableTextMemberSchemaTypes,
5793
5802
  level: number,
5794
5803
  ) => string | undefined
5795
- mapBlockquoteStyle: (
5804
+ mapBlockquoteStyle?: (
5796
5805
  schema: PortableTextMemberSchemaTypes,
5797
5806
  ) => string | undefined
5798
- mapUnorderedListStyle: (
5807
+ mapUnorderedListStyle?: (
5799
5808
  schema: PortableTextMemberSchemaTypes,
5800
5809
  ) => string | undefined
5801
- mapOrderedListStyle: (
5810
+ mapOrderedListStyle?: (
5802
5811
  schema: PortableTextMemberSchemaTypes,
5803
5812
  ) => string | undefined
5804
5813
  }
@@ -6000,9 +6009,9 @@ export declare class PortableTextEditor extends Component<
6000
6009
  | []
6001
6010
  | [
6002
6011
  (
6003
- | PortableTextSpan
6012
+ | PortableTextTextBlock<PortableTextObject | PortableTextSpan>
6004
6013
  | PortableTextObject
6005
- | PortableTextTextBlock<PortableTextSpan | PortableTextObject>
6014
+ | PortableTextSpan
6006
6015
  | undefined
6007
6016
  ),
6008
6017
  Path | undefined,
package/lib/index.esm.js 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,
@@ -4752,32 +4794,18 @@ function createEditableAPI(editor, editorActor) {
4752
4794
  at: editor.selection
4753
4795
  }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path || [];
4754
4796
  },
4755
- insertBlock: (type, value) => {
4756
- const block = toSlateValue([{
4757
- _key: editorActor.getSnapshot().context.keyGenerator(),
4758
- _type: type.name,
4759
- ...value || {}
4760
- }], {
4761
- schemaTypes: editorActor.getSnapshot().context.schema
4762
- })[0];
4763
- if (!editor.selection) {
4764
- const lastBlock = Array.from(Editor.nodes(editor, {
4765
- match: (n) => !Editor.isEditor(n),
4766
- at: [],
4767
- reverse: !0
4768
- }))[0];
4769
- return Editor.insertNode(editor, block), lastBlock && isEqualToEmptyEditor([lastBlock[0]], types) && Transforms.removeNodes(editor, {
4770
- at: lastBlock[1]
4771
- }), 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
4772
4807
  }
4773
- const focusBlock = Array.from(Editor.nodes(editor, {
4774
- at: editor.selection.focus.path.slice(0, 1),
4775
- match: (n) => n._type === types.block.name
4776
- }))[0];
4777
- return Editor.insertNode(editor, block), focusBlock && isEqualToEmptyEditor([focusBlock[0]], types) && Transforms.removeNodes(editor, {
4778
- at: focusBlock[1]
4779
- }), editor.onChange(), toPortableTextRange(fromSlateValue(editor.children, types.block.name, KEY_TO_VALUE_ELEMENT.get(editor)), editor.selection, types)?.focus.path || [];
4780
- },
4808
+ }),
4781
4809
  hasBlockStyle: (style) => {
4782
4810
  try {
4783
4811
  return editor.pteHasBlockStyle(style);
@@ -4947,6 +4975,35 @@ function createEditableAPI(editor, editorActor) {
4947
4975
  }
4948
4976
  };
4949
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
+ };
4950
5007
  function isAnnotationActive({
4951
5008
  editor,
4952
5009
  annotation
@@ -5327,6 +5384,7 @@ const addAnnotationActionImplementation = ({
5327
5384
  at: location
5328
5385
  });
5329
5386
  },
5387
+ "insert block object": insertBlockObjectActionImplementation,
5330
5388
  "insert break": insertBreakActionImplementation,
5331
5389
  "insert soft break": insertSoftBreakActionImplementation,
5332
5390
  "insert text": ({
@@ -5384,6 +5442,13 @@ function performAction({
5384
5442
  });
5385
5443
  break;
5386
5444
  }
5445
+ case "insert block object": {
5446
+ behaviorActionImplementations["insert block object"]({
5447
+ context,
5448
+ action
5449
+ });
5450
+ break;
5451
+ }
5387
5452
  case "insert text block": {
5388
5453
  behaviorActionImplementations["insert text block"]({
5389
5454
  context,