@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.js CHANGED
@@ -323,7 +323,9 @@ function createMarkdownBehaviors(config) {
323
323
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
324
324
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
325
325
  return !1;
326
- 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.blockquoteStyle?.({
327
+ schema: context.schema
328
+ });
327
329
  return caretAtTheEndOfQuote && looksLikeMarkdownQuote && blockquoteStyle !== void 0 ? {
328
330
  focusTextBlock,
329
331
  focusSpan,
@@ -364,20 +366,26 @@ function createMarkdownBehaviors(config) {
364
366
  context,
365
367
  event
366
368
  }) => {
367
- if (event.text !== "-")
369
+ const hrCharacter = event.text === "-" ? "-" : event.text === "*" ? "*" : event.text === "_" ? "_" : void 0;
370
+ if (hrCharacter === void 0)
368
371
  return !1;
369
- const breakObject = config.mapBreakObject?.(context.schema), focusBlock = getFocusTextBlock(context), selectionCollapsed = selectionIsCollapsed(context);
372
+ const breakObject = config.horizontalRuleObject?.({
373
+ schema: context.schema
374
+ }), focusBlock = getFocusTextBlock(context), selectionCollapsed = selectionIsCollapsed(context);
370
375
  if (!breakObject || !focusBlock || !selectionCollapsed)
371
376
  return !1;
372
377
  const onlyText = focusBlock.node.children.every(isPortableTextSpan), blockText = focusBlock.node.children.map((child) => child.text ?? "").join("");
373
- return onlyText && blockText === "--" ? {
378
+ return onlyText && blockText === `${hrCharacter}${hrCharacter}` ? {
374
379
  breakObject,
375
- focusBlock
380
+ focusBlock,
381
+ hrCharacter
376
382
  } : !1;
377
383
  },
378
- actions: [() => [{
384
+ actions: [(_, {
385
+ hrCharacter
386
+ }) => [{
379
387
  type: "insert text",
380
- text: "-"
388
+ text: hrCharacter
381
389
  }], (_, {
382
390
  breakObject,
383
391
  focusBlock
@@ -411,15 +419,18 @@ function createMarkdownBehaviors(config) {
411
419
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
412
420
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
413
421
  return !1;
414
- const markdownHeadingSearch = /^#+/.exec(focusSpan.node.text), headingLevel = markdownHeadingSearch ? markdownHeadingSearch[0].length : void 0;
415
- if (context.selection.focus.offset !== headingLevel)
422
+ const markdownHeadingSearch = /^#+/.exec(focusSpan.node.text), level = markdownHeadingSearch ? markdownHeadingSearch[0].length : void 0;
423
+ if (context.selection.focus.offset !== level)
416
424
  return !1;
417
- const headingStyle = headingLevel !== void 0 ? config.mapHeadingStyle?.(context.schema, headingLevel) : void 0;
418
- return headingLevel !== void 0 && headingStyle !== void 0 ? {
425
+ const style = level !== void 0 ? config.headingStyle?.({
426
+ schema: context.schema,
427
+ level
428
+ }) : void 0;
429
+ return level !== void 0 && style !== void 0 ? {
419
430
  focusTextBlock,
420
431
  focusSpan,
421
- style: headingStyle,
422
- level: headingLevel
432
+ style,
433
+ level
423
434
  } : !1;
424
435
  },
425
436
  actions: [() => [{
@@ -459,7 +470,9 @@ function createMarkdownBehaviors(config) {
459
470
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
460
471
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
461
472
  return !1;
462
- const atTheBeginningOfBLock = focusTextBlock.node.children[0]._key === focusSpan.node._key && context.selection.focus.offset === 0, defaultStyle = config.mapDefaultStyle?.(context.schema);
473
+ const atTheBeginningOfBLock = focusTextBlock.node.children[0]._key === focusSpan.node._key && context.selection.focus.offset === 0, defaultStyle = config.defaultStyle?.({
474
+ schema: context.schema
475
+ });
463
476
  return atTheBeginningOfBLock && defaultStyle && focusTextBlock.node.style !== defaultStyle ? {
464
477
  defaultStyle,
465
478
  focusTextBlock
@@ -484,7 +497,11 @@ function createMarkdownBehaviors(config) {
484
497
  const selectionCollapsed = selectionIsCollapsed(context), focusTextBlock = getFocusTextBlock(context), focusSpan = getFocusSpan(context);
485
498
  if (!selectionCollapsed || !focusTextBlock || !focusSpan)
486
499
  return !1;
487
- const defaultStyle = config.mapDefaultStyle?.(context.schema), looksLikeUnorderedList = /^(-|\*)/.test(focusSpan.node.text), unorderedListStyle = config.mapUnorderedListStyle?.(context.schema), caretAtTheEndOfUnorderedList = context.selection.focus.offset === 1;
500
+ const defaultStyle = config.defaultStyle?.({
501
+ schema: context.schema
502
+ }), looksLikeUnorderedList = /^(-|\*)/.test(focusSpan.node.text), unorderedListStyle = config.unorderedListStyle?.({
503
+ schema: context.schema
504
+ }), caretAtTheEndOfUnorderedList = context.selection.focus.offset === 1;
488
505
  if (defaultStyle && caretAtTheEndOfUnorderedList && looksLikeUnorderedList && unorderedListStyle !== void 0)
489
506
  return {
490
507
  focusTextBlock,
@@ -493,7 +510,9 @@ function createMarkdownBehaviors(config) {
493
510
  listItemLength: 1,
494
511
  style: defaultStyle
495
512
  };
496
- const looksLikeOrderedList = /^1./.test(focusSpan.node.text), orderedListStyle = config.mapOrderedListStyle?.(context.schema), caretAtTheEndOfOrderedList = context.selection.focus.offset === 2;
513
+ const looksLikeOrderedList = /^1./.test(focusSpan.node.text), orderedListStyle = config.orderedListStyle?.({
514
+ schema: context.schema
515
+ }), caretAtTheEndOfOrderedList = context.selection.focus.offset === 2;
497
516
  return defaultStyle && caretAtTheEndOfOrderedList && looksLikeOrderedList && orderedListStyle !== void 0 ? {
498
517
  focusTextBlock,
499
518
  focusSpan,
@@ -533,6 +552,65 @@ function createMarkdownBehaviors(config) {
533
552
  };
534
553
  return [automaticBlockquoteOnSpace, automaticBreak, automaticHeadingOnSpace, clearStyleOnBackspace, automaticListOnSpace];
535
554
  }
555
+ function createLinkBehaviors(config) {
556
+ const pasteLinkOnSelection = {
557
+ on: "paste",
558
+ guard: ({
559
+ context,
560
+ event
561
+ }) => {
562
+ const selectionCollapsed = selectionIsCollapsed(context), text = event.clipboardData.getData("text/plain"), url = looksLikeUrl(text) ? text : void 0, annotation = url !== void 0 ? config.linkAnnotation?.({
563
+ url,
564
+ schema: context.schema
565
+ }) : void 0;
566
+ return annotation && !selectionCollapsed ? {
567
+ annotation
568
+ } : !1;
569
+ },
570
+ actions: [(_, {
571
+ annotation
572
+ }) => [{
573
+ type: "annotation.add",
574
+ annotation
575
+ }]]
576
+ }, pasteLinkAtCaret = {
577
+ on: "paste",
578
+ guard: ({
579
+ context,
580
+ event
581
+ }) => {
582
+ const focusSpan = getFocusSpan(context), selectionCollapsed = selectionIsCollapsed(context);
583
+ if (!focusSpan || !selectionCollapsed)
584
+ return !1;
585
+ const text = event.clipboardData.getData("text/plain"), url = looksLikeUrl(text) ? text : void 0, annotation = url !== void 0 ? config.linkAnnotation?.({
586
+ url,
587
+ schema: context.schema
588
+ }) : void 0;
589
+ return url && annotation && selectionCollapsed ? {
590
+ focusSpan,
591
+ annotation,
592
+ url
593
+ } : !1;
594
+ },
595
+ actions: [(_, {
596
+ annotation,
597
+ url
598
+ }) => [{
599
+ type: "insert span",
600
+ text: url,
601
+ annotations: [annotation]
602
+ }]]
603
+ };
604
+ return [pasteLinkOnSelection, pasteLinkAtCaret];
605
+ }
606
+ function looksLikeUrl(text) {
607
+ let looksLikeUrl2 = !1;
608
+ try {
609
+ new URL(text), looksLikeUrl2 = !0;
610
+ } catch {
611
+ }
612
+ return looksLikeUrl2;
613
+ }
536
614
  function getPortableTextMemberSchemaTypes(portableTextType) {
537
615
  if (!portableTextType)
538
616
  throw new Error("Parameter 'portabletextType' missing (required)");
@@ -4447,11 +4525,11 @@ function isDecoratorActive({
4447
4525
  }) {
4448
4526
  if (!editor.selection)
4449
4527
  return !1;
4450
- const selectedNodes = Array.from(slate.Editor.nodes(editor, {
4528
+ const selectedTextNodes = Array.from(slate.Editor.nodes(editor, {
4451
4529
  match: slate.Text.isText,
4452
4530
  at: editor.selection
4453
4531
  }));
4454
- return slate.Range.isExpanded(editor.selection) ? selectedNodes.every((n) => {
4532
+ return selectedTextNodes.length === 0 ? !1 : slate.Range.isExpanded(editor.selection) ? selectedTextNodes.every((n) => {
4455
4533
  const [node] = n;
4456
4534
  return node.marks?.includes(decorator);
4457
4535
  }) : ({
@@ -5279,6 +5357,35 @@ const addAnnotationActionImplementation = ({
5279
5357
  type: "insert break"
5280
5358
  }
5281
5359
  });
5360
+ }, insertSpanActionImplementation = ({
5361
+ context,
5362
+ action
5363
+ }) => {
5364
+ if (!action.editor.selection) {
5365
+ console.error("Unable to perform action without selection", action);
5366
+ return;
5367
+ }
5368
+ const [focusBlock, focusBlockPath] = Array.from(slate.Editor.nodes(action.editor, {
5369
+ at: action.editor.selection.focus.path,
5370
+ match: (node) => action.editor.isTextBlock(node)
5371
+ }))[0] ?? [void 0, void 0];
5372
+ if (!focusBlock || !focusBlockPath) {
5373
+ console.error("Unable to perform action without focus block", action);
5374
+ return;
5375
+ }
5376
+ const markDefs = focusBlock.markDefs ?? [], annotations = action.annotations ? action.annotations.map((annotation) => ({
5377
+ _type: annotation.name,
5378
+ _key: context.keyGenerator(),
5379
+ ...annotation.value
5380
+ })) : void 0;
5381
+ annotations && annotations.length > 0 && slate.Transforms.setNodes(action.editor, {
5382
+ markDefs: [...markDefs, ...annotations]
5383
+ }), slate.Transforms.insertNodes(action.editor, {
5384
+ _type: "span",
5385
+ _key: context.keyGenerator(),
5386
+ text: action.text,
5387
+ marks: [...annotations?.map((annotation) => annotation._key) ?? [], ...action.decorators ?? []]
5388
+ });
5282
5389
  }, behaviorActionImplementations = {
5283
5390
  "annotation.add": addAnnotationActionImplementation,
5284
5391
  "annotation.remove": removeAnnotationActionImplementation,
@@ -5366,6 +5473,7 @@ const addAnnotationActionImplementation = ({
5366
5473
  "insert block object": insertBlockObjectActionImplementation,
5367
5474
  "insert break": insertBreakActionImplementation,
5368
5475
  "insert soft break": insertSoftBreakActionImplementation,
5476
+ "insert span": insertSpanActionImplementation,
5369
5477
  "insert text": ({
5370
5478
  action
5371
5479
  }) => {
@@ -5392,6 +5500,11 @@ const addAnnotationActionImplementation = ({
5392
5500
  }) => {
5393
5501
  action.effect();
5394
5502
  },
5503
+ paste: ({
5504
+ action
5505
+ }) => {
5506
+ action.editor.insertData(action.clipboardData);
5507
+ },
5395
5508
  select: ({
5396
5509
  action
5397
5510
  }) => {
@@ -5428,6 +5541,13 @@ function performAction({
5428
5541
  });
5429
5542
  break;
5430
5543
  }
5544
+ case "insert span": {
5545
+ behaviorActionImplementations["insert span"]({
5546
+ context,
5547
+ action
5548
+ });
5549
+ break;
5550
+ }
5431
5551
  case "insert text block": {
5432
5552
  behaviorActionImplementations["insert text block"]({
5433
5553
  context,
@@ -5559,11 +5679,18 @@ function performDefaultAction({
5559
5679
  });
5560
5680
  break;
5561
5681
  }
5562
- default:
5682
+ case "insert text": {
5563
5683
  behaviorActionImplementations["insert text"]({
5564
5684
  context,
5565
5685
  action
5566
5686
  });
5687
+ break;
5688
+ }
5689
+ default:
5690
+ behaviorActionImplementations.paste({
5691
+ context,
5692
+ action
5693
+ });
5567
5694
  }
5568
5695
  }
5569
5696
  const networkLogic = xstate.fromCallback(({
@@ -6629,19 +6756,13 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6629
6756
  const handleCopy = react.useCallback((event) => {
6630
6757
  onCopy && onCopy(event) !== void 0 && event.preventDefault();
6631
6758
  }, [onCopy]), handlePaste = react.useCallback((event_0) => {
6632
- if (event_0.preventDefault(), !slateEditor.selection)
6633
- return;
6634
- if (!onPaste) {
6635
- debug("Pasting normally"), slateEditor.insertData(event_0.clipboardData);
6636
- return;
6637
- }
6638
- const value_0 = PortableTextEditor.getValue(portableTextEditor), path = toPortableTextRange(value_0, slateEditor.selection, schemaTypes)?.focus.path || [], onPasteResult = onPaste({
6759
+ const value_0 = PortableTextEditor.getValue(portableTextEditor), path = toPortableTextRange(value_0, slateEditor.selection, schemaTypes)?.focus.path || [], onPasteResult = onPaste?.({
6639
6760
  event: event_0,
6640
6761
  value: value_0,
6641
6762
  path,
6642
6763
  schemaTypes
6643
6764
  });
6644
- onPasteResult === void 0 ? (debug("No result from custom paste handler, pasting normally"), slateEditor.insertData(event_0.clipboardData)) : (editorActor.send({
6765
+ onPasteResult || !slateEditor.selection ? (event_0.preventDefault(), editorActor.send({
6645
6766
  type: "loading"
6646
6767
  }), Promise.resolve(onPasteResult).then((result_0) => {
6647
6768
  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, {
@@ -6651,7 +6772,14 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6651
6772
  editorActor.send({
6652
6773
  type: "done loading"
6653
6774
  });
6654
- }));
6775
+ })) : event_0.nativeEvent.clipboardData && (event_0.preventDefault(), editorActor.send({
6776
+ type: "behavior event",
6777
+ behaviorEvent: {
6778
+ type: "paste",
6779
+ clipboardData: event_0.nativeEvent.clipboardData
6780
+ },
6781
+ editor: slateEditor
6782
+ })), debug("No result from custom paste handler, pasting normally");
6655
6783
  }, [editorActor, onPaste, portableTextEditor, schemaTypes, slateEditor]), handleOnFocus = react.useCallback((event_1) => {
6656
6784
  if (onFocus && onFocus(event_1), !event_1.isDefaultPrevented()) {
6657
6785
  const selection = PortableTextEditor.getSelection(portableTextEditor);
@@ -6666,15 +6794,11 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6666
6794
  });
6667
6795
  }
6668
6796
  }, [editorActor, onFocus, portableTextEditor, slateEditor]), handleClick = react.useCallback((event_2) => {
6669
- if (onClick && onClick(event_2), slateEditor.selection && event_2.target === event_2.currentTarget) {
6670
- const [lastBlock, path_0] = slate.Node.last(slateEditor, []), focusPath = slateEditor.selection.focus.path.slice(0, 1), lastPath = path_0.slice(0, 1);
6671
- if (slate.Path.equals(focusPath, lastPath)) {
6672
- const node = slate.Node.descendant(slateEditor, path_0.slice(0, 1));
6673
- lastBlock && slate.Editor.isVoid(slateEditor, node) && (slate.Transforms.insertNodes(slateEditor, slateEditor.pteCreateTextBlock({
6674
- decorators: []
6675
- })), slateEditor.onChange());
6676
- }
6677
- }
6797
+ onClick && onClick(event_2);
6798
+ const focusBlockPath = slateEditor.selection ? slateEditor.selection.focus.path.slice(0, 1) : void 0, focusBlock = focusBlockPath ? slate.Node.descendant(slateEditor, focusBlockPath) : void 0, [_, lastNodePath] = slate.Node.last(slateEditor, []), lastBlockPath = lastNodePath.slice(0, 1), lastNodeFocused = focusBlockPath ? slate.Path.equals(lastBlockPath, focusBlockPath) : !1, lastBlockIsVoid = focusBlock ? !slateEditor.isTextBlock(focusBlock) : !1;
6799
+ slateEditor.selection && slate.Range.isCollapsed(slateEditor.selection) && lastNodeFocused && lastBlockIsVoid && (slate.Transforms.insertNodes(slateEditor, slateEditor.pteCreateTextBlock({
6800
+ decorators: []
6801
+ })), slateEditor.onChange());
6678
6802
  }, [onClick, slateEditor]), handleOnBlur = react.useCallback((event_3) => {
6679
6803
  onBlur && onBlur(event_3), event_3.isPropagationStopped() || editorActor.send({
6680
6804
  type: "blur",
@@ -6722,7 +6846,7 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6722
6846
  return scrollSelectionIntoView === null ? noop__default.default : (_editor, domRange) => {
6723
6847
  scrollSelectionIntoView(portableTextEditor, domRange);
6724
6848
  };
6725
- }, [portableTextEditor, scrollSelectionIntoView]), decorate = react.useCallback(([, path_1]) => {
6849
+ }, [portableTextEditor, scrollSelectionIntoView]), decorate = react.useCallback(([, path_0]) => {
6726
6850
  if (isEqualToEmptyEditor(slateEditor.children, schemaTypes))
6727
6851
  return [{
6728
6852
  anchor: {
@@ -6735,18 +6859,18 @@ const debug = debugWithName("component:Editable"), PLACEHOLDER_STYLE = {
6735
6859
  },
6736
6860
  placeholder: !0
6737
6861
  }];
6738
- if (path_1.length === 0)
6862
+ if (path_0.length === 0)
6739
6863
  return [];
6740
- const result_1 = rangeDecorationState.filter((item) => slate.Range.isCollapsed(item) ? path_1.length !== 2 ? !1 : slate.Path.equals(item.focus.path, path_1) && slate.Path.equals(item.anchor.path, path_1) : slate.Range.intersection(item, {
6864
+ const result_1 = rangeDecorationState.filter((item) => slate.Range.isCollapsed(item) ? path_0.length !== 2 ? !1 : slate.Path.equals(item.focus.path, path_0) && slate.Path.equals(item.anchor.path, path_0) : slate.Range.intersection(item, {
6741
6865
  anchor: {
6742
- path: path_1,
6866
+ path: path_0,
6743
6867
  offset: 0
6744
6868
  },
6745
6869
  focus: {
6746
- path: path_1,
6870
+ path: path_0,
6747
6871
  offset: 0
6748
6872
  }
6749
- }) || slate.Range.includes(item, path_1));
6873
+ }) || slate.Range.includes(item, path_0));
6750
6874
  return result_1.length > 0 ? result_1 : [];
6751
6875
  }, [slateEditor, schemaTypes, rangeDecorationState]);
6752
6876
  return react.useEffect(() => {
@@ -6816,6 +6940,7 @@ exports.PortableTextEditable = PortableTextEditable;
6816
6940
  exports.PortableTextEditor = PortableTextEditor;
6817
6941
  exports.coreBehavior = coreBehavior;
6818
6942
  exports.coreBehaviors = coreBehaviors;
6943
+ exports.createLinkBehaviors = createLinkBehaviors;
6819
6944
  exports.createMarkdownBehaviors = createMarkdownBehaviors;
6820
6945
  exports.defineBehavior = defineBehavior;
6821
6946
  exports.defineSchema = defineSchema;