@portabletext/editor 1.8.0 → 1.10.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.esm.js CHANGED
@@ -344,7 +344,9 @@ function createMarkdownBehaviors(config) {
344
344
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
345
345
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
346
346
  return !1;
347
- 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.blockquoteStyle?.({
348
+ schema: context.schema
349
+ });
348
350
  return caretAtTheEndOfQuote && looksLikeMarkdownQuote && blockquoteStyle !== void 0 ? {
349
351
  focusTextBlock,
350
352
  focusSpan,
@@ -385,20 +387,26 @@ function createMarkdownBehaviors(config) {
385
387
  context,
386
388
  event
387
389
  }) => {
388
- if (event.text !== "-")
390
+ const hrCharacter = event.text === "-" ? "-" : event.text === "*" ? "*" : event.text === "_" ? "_" : void 0;
391
+ if (hrCharacter === void 0)
389
392
  return !1;
390
- const breakObject = config.mapBreakObject?.(context.schema), focusBlock = getFocusTextBlock(context), selectionCollapsed = selectionIsCollapsed(context);
393
+ const breakObject = config.horizontalRuleObject?.({
394
+ schema: context.schema
395
+ }), focusBlock = getFocusTextBlock(context), selectionCollapsed = selectionIsCollapsed(context);
391
396
  if (!breakObject || !focusBlock || !selectionCollapsed)
392
397
  return !1;
393
398
  const onlyText = focusBlock.node.children.every(isPortableTextSpan), blockText = focusBlock.node.children.map((child) => child.text ?? "").join("");
394
- return onlyText && blockText === "--" ? {
399
+ return onlyText && blockText === `${hrCharacter}${hrCharacter}` ? {
395
400
  breakObject,
396
- focusBlock
401
+ focusBlock,
402
+ hrCharacter
397
403
  } : !1;
398
404
  },
399
- actions: [() => [{
405
+ actions: [(_, {
406
+ hrCharacter
407
+ }) => [{
400
408
  type: "insert text",
401
- text: "-"
409
+ text: hrCharacter
402
410
  }], (_, {
403
411
  breakObject,
404
412
  focusBlock
@@ -432,15 +440,18 @@ function createMarkdownBehaviors(config) {
432
440
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
433
441
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
434
442
  return !1;
435
- const markdownHeadingSearch = /^#+/.exec(focusSpan.node.text), headingLevel = markdownHeadingSearch ? markdownHeadingSearch[0].length : void 0;
436
- if (context.selection.focus.offset !== headingLevel)
443
+ const markdownHeadingSearch = /^#+/.exec(focusSpan.node.text), level = markdownHeadingSearch ? markdownHeadingSearch[0].length : void 0;
444
+ if (context.selection.focus.offset !== level)
437
445
  return !1;
438
- const headingStyle = headingLevel !== void 0 ? config.mapHeadingStyle?.(context.schema, headingLevel) : void 0;
439
- return headingLevel !== void 0 && headingStyle !== void 0 ? {
446
+ const style = level !== void 0 ? config.headingStyle?.({
447
+ schema: context.schema,
448
+ level
449
+ }) : void 0;
450
+ return level !== void 0 && style !== void 0 ? {
440
451
  focusTextBlock,
441
452
  focusSpan,
442
- style: headingStyle,
443
- level: headingLevel
453
+ style,
454
+ level
444
455
  } : !1;
445
456
  },
446
457
  actions: [() => [{
@@ -480,7 +491,9 @@ function createMarkdownBehaviors(config) {
480
491
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
481
492
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
482
493
  return !1;
483
- const atTheBeginningOfBLock = focusTextBlock.node.children[0]._key === focusSpan.node._key && context.selection.focus.offset === 0, defaultStyle = config.mapDefaultStyle?.(context.schema);
494
+ const atTheBeginningOfBLock = focusTextBlock.node.children[0]._key === focusSpan.node._key && context.selection.focus.offset === 0, defaultStyle = config.defaultStyle?.({
495
+ schema: context.schema
496
+ });
484
497
  return atTheBeginningOfBLock && defaultStyle && focusTextBlock.node.style !== defaultStyle ? {
485
498
  defaultStyle,
486
499
  focusTextBlock
@@ -505,7 +518,11 @@ function createMarkdownBehaviors(config) {
505
518
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
506
519
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
507
520
  return !1;
508
- const defaultStyle = config.mapDefaultStyle?.(context.schema), looksLikeUnorderedList = /^(-|\*)/.test(focusSpan.node.text), unorderedListStyle = config.mapUnorderedListStyle?.(context.schema), caretAtTheEndOfUnorderedList = context.selection.focus.offset === 1;
521
+ const defaultStyle = config.defaultStyle?.({
522
+ schema: context.schema
523
+ }), looksLikeUnorderedList = /^(-|\*)/.test(focusSpan.node.text), unorderedListStyle = config.unorderedListStyle?.({
524
+ schema: context.schema
525
+ }), caretAtTheEndOfUnorderedList = context.selection.focus.offset === 1;
509
526
  if (defaultStyle && caretAtTheEndOfUnorderedList && looksLikeUnorderedList && unorderedListStyle !== void 0)
510
527
  return {
511
528
  focusTextBlock,
@@ -514,7 +531,9 @@ function createMarkdownBehaviors(config) {
514
531
  listItemLength: 1,
515
532
  style: defaultStyle
516
533
  };
517
- const looksLikeOrderedList = /^1./.test(focusSpan.node.text), orderedListStyle = config.mapOrderedListStyle?.(context.schema), caretAtTheEndOfOrderedList = context.selection.focus.offset === 2;
534
+ const looksLikeOrderedList = /^1./.test(focusSpan.node.text), orderedListStyle = config.orderedListStyle?.({
535
+ schema: context.schema
536
+ }), caretAtTheEndOfOrderedList = context.selection.focus.offset === 2;
518
537
  return defaultStyle && caretAtTheEndOfOrderedList && looksLikeOrderedList && orderedListStyle !== void 0 ? {
519
538
  focusTextBlock,
520
539
  focusSpan,
@@ -554,6 +573,65 @@ function createMarkdownBehaviors(config) {
554
573
  };
555
574
  return [automaticBlockquoteOnSpace, automaticBreak, automaticHeadingOnSpace, clearStyleOnBackspace, automaticListOnSpace];
556
575
  }
576
+ function createLinkBehaviors(config) {
577
+ const pasteLinkOnSelection = {
578
+ on: "paste",
579
+ guard: ({
580
+ context,
581
+ event
582
+ }) => {
583
+ const selectionCollapsed = selectionIsCollapsed(context), text = event.clipboardData.getData("text/plain"), url = looksLikeUrl(text) ? text : void 0, annotation = url !== void 0 ? config.linkAnnotation?.({
584
+ url,
585
+ schema: context.schema
586
+ }) : void 0;
587
+ return annotation && !selectionCollapsed ? {
588
+ annotation
589
+ } : !1;
590
+ },
591
+ actions: [(_, {
592
+ annotation
593
+ }) => [{
594
+ type: "annotation.add",
595
+ annotation
596
+ }]]
597
+ }, pasteLinkAtCaret = {
598
+ on: "paste",
599
+ guard: ({
600
+ context,
601
+ event
602
+ }) => {
603
+ const focusSpan = getFocusSpan(context), selectionCollapsed = selectionIsCollapsed(context);
604
+ if (!focusSpan || !selectionCollapsed)
605
+ return !1;
606
+ const text = event.clipboardData.getData("text/plain"), url = looksLikeUrl(text) ? text : void 0, annotation = url !== void 0 ? config.linkAnnotation?.({
607
+ url,
608
+ schema: context.schema
609
+ }) : void 0;
610
+ return url && annotation && selectionCollapsed ? {
611
+ focusSpan,
612
+ annotation,
613
+ url
614
+ } : !1;
615
+ },
616
+ actions: [(_, {
617
+ annotation,
618
+ url
619
+ }) => [{
620
+ type: "insert span",
621
+ text: url,
622
+ annotations: [annotation]
623
+ }]]
624
+ };
625
+ return [pasteLinkOnSelection, pasteLinkAtCaret];
626
+ }
627
+ function looksLikeUrl(text) {
628
+ let looksLikeUrl2 = !1;
629
+ try {
630
+ new URL(text), looksLikeUrl2 = !0;
631
+ } catch {
632
+ }
633
+ return looksLikeUrl2;
634
+ }
557
635
  function getPortableTextMemberSchemaTypes(portableTextType) {
558
636
  if (!portableTextType)
559
637
  throw new Error("Parameter 'portabletextType' missing (required)");
@@ -4468,11 +4546,11 @@ function isDecoratorActive({
4468
4546
  }) {
4469
4547
  if (!editor.selection)
4470
4548
  return !1;
4471
- const selectedNodes = Array.from(Editor.nodes(editor, {
4549
+ const selectedTextNodes = Array.from(Editor.nodes(editor, {
4472
4550
  match: Text.isText,
4473
4551
  at: editor.selection
4474
4552
  }));
4475
- return Range.isExpanded(editor.selection) ? selectedNodes.every((n) => {
4553
+ return selectedTextNodes.length === 0 ? !1 : Range.isExpanded(editor.selection) ? selectedTextNodes.every((n) => {
4476
4554
  const [node] = n;
4477
4555
  return node.marks?.includes(decorator);
4478
4556
  }) : ({
@@ -5300,6 +5378,35 @@ const addAnnotationActionImplementation = ({
5300
5378
  type: "insert break"
5301
5379
  }
5302
5380
  });
5381
+ }, insertSpanActionImplementation = ({
5382
+ context,
5383
+ action
5384
+ }) => {
5385
+ if (!action.editor.selection) {
5386
+ console.error("Unable to perform action without selection", action);
5387
+ return;
5388
+ }
5389
+ const [focusBlock, focusBlockPath] = Array.from(Editor.nodes(action.editor, {
5390
+ at: action.editor.selection.focus.path,
5391
+ match: (node) => action.editor.isTextBlock(node)
5392
+ }))[0] ?? [void 0, void 0];
5393
+ if (!focusBlock || !focusBlockPath) {
5394
+ console.error("Unable to perform action without focus block", action);
5395
+ return;
5396
+ }
5397
+ const markDefs = focusBlock.markDefs ?? [], annotations = action.annotations ? action.annotations.map((annotation) => ({
5398
+ _type: annotation.name,
5399
+ _key: context.keyGenerator(),
5400
+ ...annotation.value
5401
+ })) : void 0;
5402
+ annotations && annotations.length > 0 && Transforms.setNodes(action.editor, {
5403
+ markDefs: [...markDefs, ...annotations]
5404
+ }), Transforms.insertNodes(action.editor, {
5405
+ _type: "span",
5406
+ _key: context.keyGenerator(),
5407
+ text: action.text,
5408
+ marks: [...annotations?.map((annotation) => annotation._key) ?? [], ...action.decorators ?? []]
5409
+ });
5303
5410
  }, behaviorActionImplementations = {
5304
5411
  "annotation.add": addAnnotationActionImplementation,
5305
5412
  "annotation.remove": removeAnnotationActionImplementation,
@@ -5387,6 +5494,7 @@ const addAnnotationActionImplementation = ({
5387
5494
  "insert block object": insertBlockObjectActionImplementation,
5388
5495
  "insert break": insertBreakActionImplementation,
5389
5496
  "insert soft break": insertSoftBreakActionImplementation,
5497
+ "insert span": insertSpanActionImplementation,
5390
5498
  "insert text": ({
5391
5499
  action
5392
5500
  }) => {
@@ -5413,6 +5521,11 @@ const addAnnotationActionImplementation = ({
5413
5521
  }) => {
5414
5522
  action.effect();
5415
5523
  },
5524
+ paste: ({
5525
+ action
5526
+ }) => {
5527
+ action.editor.insertData(action.clipboardData);
5528
+ },
5416
5529
  select: ({
5417
5530
  action
5418
5531
  }) => {
@@ -5449,6 +5562,13 @@ function performAction({
5449
5562
  });
5450
5563
  break;
5451
5564
  }
5565
+ case "insert span": {
5566
+ behaviorActionImplementations["insert span"]({
5567
+ context,
5568
+ action
5569
+ });
5570
+ break;
5571
+ }
5452
5572
  case "insert text block": {
5453
5573
  behaviorActionImplementations["insert text block"]({
5454
5574
  context,
@@ -5580,11 +5700,18 @@ function performDefaultAction({
5580
5700
  });
5581
5701
  break;
5582
5702
  }
5583
- default:
5703
+ case "insert text": {
5584
5704
  behaviorActionImplementations["insert text"]({
5585
5705
  context,
5586
5706
  action
5587
5707
  });
5708
+ break;
5709
+ }
5710
+ default:
5711
+ behaviorActionImplementations.paste({
5712
+ context,
5713
+ action
5714
+ });
5588
5715
  }
5589
5716
  }
5590
5717
  const networkLogic = fromCallback(({
@@ -6650,19 +6777,13 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6650
6777
  const handleCopy = useCallback((event) => {
6651
6778
  onCopy && onCopy(event) !== void 0 && event.preventDefault();
6652
6779
  }, [onCopy]), handlePaste = useCallback((event_0) => {
6653
- if (event_0.preventDefault(), !slateEditor.selection)
6654
- return;
6655
- if (!onPaste) {
6656
- debug("Pasting normally"), slateEditor.insertData(event_0.clipboardData);
6657
- return;
6658
- }
6659
- const value_0 = PortableTextEditor.getValue(portableTextEditor), path = toPortableTextRange(value_0, slateEditor.selection, schemaTypes)?.focus.path || [], onPasteResult = onPaste({
6780
+ const value_0 = PortableTextEditor.getValue(portableTextEditor), path = toPortableTextRange(value_0, slateEditor.selection, schemaTypes)?.focus.path || [], onPasteResult = onPaste?.({
6660
6781
  event: event_0,
6661
6782
  value: value_0,
6662
6783
  path,
6663
6784
  schemaTypes
6664
6785
  });
6665
- onPasteResult === void 0 ? (debug("No result from custom paste handler, pasting normally"), slateEditor.insertData(event_0.clipboardData)) : (editorActor.send({
6786
+ onPasteResult || !slateEditor.selection ? (event_0.preventDefault(), editorActor.send({
6666
6787
  type: "loading"
6667
6788
  }), Promise.resolve(onPasteResult).then((result_0) => {
6668
6789
  debug("Custom paste function from client resolved", result_0), !result_0 || !result_0.insert ? (debug("No result from custom paste handler, pasting normally"), slateEditor.insertData(event_0.clipboardData)) : result_0.insert ? slateEditor.insertFragment(toSlateValue(result_0.insert, {
@@ -6672,7 +6793,14 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6672
6793
  editorActor.send({
6673
6794
  type: "done loading"
6674
6795
  });
6675
- }));
6796
+ })) : event_0.nativeEvent.clipboardData && (event_0.preventDefault(), editorActor.send({
6797
+ type: "behavior event",
6798
+ behaviorEvent: {
6799
+ type: "paste",
6800
+ clipboardData: event_0.nativeEvent.clipboardData
6801
+ },
6802
+ editor: slateEditor
6803
+ })), debug("No result from custom paste handler, pasting normally");
6676
6804
  }, [editorActor, onPaste, portableTextEditor, schemaTypes, slateEditor]), handleOnFocus = useCallback((event_1) => {
6677
6805
  if (onFocus && onFocus(event_1), !event_1.isDefaultPrevented()) {
6678
6806
  const selection = PortableTextEditor.getSelection(portableTextEditor);
@@ -6687,15 +6815,11 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6687
6815
  });
6688
6816
  }
6689
6817
  }, [editorActor, onFocus, portableTextEditor, slateEditor]), handleClick = useCallback((event_2) => {
6690
- if (onClick && onClick(event_2), slateEditor.selection && event_2.target === event_2.currentTarget) {
6691
- const [lastBlock, path_0] = Node.last(slateEditor, []), focusPath = slateEditor.selection.focus.path.slice(0, 1), lastPath = path_0.slice(0, 1);
6692
- if (Path.equals(focusPath, lastPath)) {
6693
- const node = Node.descendant(slateEditor, path_0.slice(0, 1));
6694
- lastBlock && Editor.isVoid(slateEditor, node) && (Transforms.insertNodes(slateEditor, slateEditor.pteCreateTextBlock({
6695
- decorators: []
6696
- })), slateEditor.onChange());
6697
- }
6698
- }
6818
+ onClick && onClick(event_2);
6819
+ const focusBlockPath = slateEditor.selection ? slateEditor.selection.focus.path.slice(0, 1) : void 0, focusBlock = focusBlockPath ? Node.descendant(slateEditor, focusBlockPath) : void 0, [_, lastNodePath] = Node.last(slateEditor, []), lastBlockPath = lastNodePath.slice(0, 1), lastNodeFocused = focusBlockPath ? Path.equals(lastBlockPath, focusBlockPath) : !1, lastBlockIsVoid = focusBlock ? !slateEditor.isTextBlock(focusBlock) : !1;
6820
+ slateEditor.selection && Range.isCollapsed(slateEditor.selection) && lastNodeFocused && lastBlockIsVoid && (Transforms.insertNodes(slateEditor, slateEditor.pteCreateTextBlock({
6821
+ decorators: []
6822
+ })), slateEditor.onChange());
6699
6823
  }, [onClick, slateEditor]), handleOnBlur = useCallback((event_3) => {
6700
6824
  onBlur && onBlur(event_3), event_3.isPropagationStopped() || editorActor.send({
6701
6825
  type: "blur",
@@ -6743,7 +6867,7 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6743
6867
  return scrollSelectionIntoView === null ? noop : (_editor, domRange) => {
6744
6868
  scrollSelectionIntoView(portableTextEditor, domRange);
6745
6869
  };
6746
- }, [portableTextEditor, scrollSelectionIntoView]), decorate = useCallback(([, path_1]) => {
6870
+ }, [portableTextEditor, scrollSelectionIntoView]), decorate = useCallback(([, path_0]) => {
6747
6871
  if (isEqualToEmptyEditor(slateEditor.children, schemaTypes))
6748
6872
  return [{
6749
6873
  anchor: {
@@ -6756,18 +6880,18 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6756
6880
  },
6757
6881
  placeholder: !0
6758
6882
  }];
6759
- if (path_1.length === 0)
6883
+ if (path_0.length === 0)
6760
6884
  return [];
6761
- const result_1 = rangeDecorationState.filter((item) => Range.isCollapsed(item) ? path_1.length !== 2 ? !1 : Path.equals(item.focus.path, path_1) && Path.equals(item.anchor.path, path_1) : Range.intersection(item, {
6885
+ const result_1 = rangeDecorationState.filter((item) => Range.isCollapsed(item) ? path_0.length !== 2 ? !1 : Path.equals(item.focus.path, path_0) && Path.equals(item.anchor.path, path_0) : Range.intersection(item, {
6762
6886
  anchor: {
6763
- path: path_1,
6887
+ path: path_0,
6764
6888
  offset: 0
6765
6889
  },
6766
6890
  focus: {
6767
- path: path_1,
6891
+ path: path_0,
6768
6892
  offset: 0
6769
6893
  }
6770
- }) || Range.includes(item, path_1));
6894
+ }) || Range.includes(item, path_0));
6771
6895
  return result_1.length > 0 ? result_1 : [];
6772
6896
  }, [slateEditor, schemaTypes, rangeDecorationState]);
6773
6897
  return useEffect(() => {
@@ -6838,6 +6962,7 @@ export {
6838
6962
  PortableTextEditor,
6839
6963
  coreBehavior,
6840
6964
  coreBehaviors,
6965
+ createLinkBehaviors,
6841
6966
  createMarkdownBehaviors,
6842
6967
  defineBehavior,
6843
6968
  defineSchema,