@tiptap/core 3.0.0-next.2 → 3.0.0-next.4

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.
Files changed (128) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +5 -1
  3. package/dist/index.cjs +2402 -2540
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.d.cts +1355 -1273
  6. package/dist/index.d.ts +1355 -1273
  7. package/dist/index.js +2408 -2562
  8. package/dist/index.js.map +1 -1
  9. package/package.json +9 -5
  10. package/src/CommandManager.ts +2 -9
  11. package/src/Editor.ts +87 -72
  12. package/src/EventEmitter.ts +7 -10
  13. package/src/Extension.ts +8 -14
  14. package/src/ExtensionManager.ts +26 -125
  15. package/src/InputRule.ts +35 -48
  16. package/src/Mark.ts +9 -9
  17. package/src/Node.ts +9 -9
  18. package/src/NodePos.ts +1 -3
  19. package/src/NodeView.ts +10 -20
  20. package/src/PasteRule.ts +43 -55
  21. package/src/Tracker.ts +7 -9
  22. package/src/commands/blur.ts +14 -12
  23. package/src/commands/clearContent.ts +6 -4
  24. package/src/commands/clearNodes.ts +32 -30
  25. package/src/commands/command.ts +1 -1
  26. package/src/commands/createParagraphNear.ts +5 -3
  27. package/src/commands/cut.ts +12 -10
  28. package/src/commands/deleteCurrentNode.ts +23 -21
  29. package/src/commands/deleteNode.ts +18 -16
  30. package/src/commands/deleteRange.ts +10 -8
  31. package/src/commands/deleteSelection.ts +5 -3
  32. package/src/commands/enter.ts +6 -4
  33. package/src/commands/exitCode.ts +5 -3
  34. package/src/commands/extendMarkRange.ts +14 -12
  35. package/src/commands/first.ts +2 -4
  36. package/src/commands/focus.ts +45 -48
  37. package/src/commands/forEach.ts +2 -2
  38. package/src/commands/insertContent.ts +12 -14
  39. package/src/commands/insertContentAt.ts +101 -98
  40. package/src/commands/join.ts +20 -12
  41. package/src/commands/joinItemBackward.ts +16 -18
  42. package/src/commands/joinItemForward.ts +16 -18
  43. package/src/commands/joinTextblockBackward.ts +5 -3
  44. package/src/commands/joinTextblockForward.ts +5 -3
  45. package/src/commands/keyboardShortcut.ts +29 -34
  46. package/src/commands/lift.ts +10 -8
  47. package/src/commands/liftEmptyBlock.ts +6 -4
  48. package/src/commands/liftListItem.ts +6 -4
  49. package/src/commands/newlineInCode.ts +5 -3
  50. package/src/commands/resetAttributes.ts +36 -41
  51. package/src/commands/scrollIntoView.ts +9 -7
  52. package/src/commands/selectAll.ts +10 -8
  53. package/src/commands/selectNodeBackward.ts +5 -3
  54. package/src/commands/selectNodeForward.ts +5 -3
  55. package/src/commands/selectParentNode.ts +5 -3
  56. package/src/commands/selectTextblockEnd.ts +5 -3
  57. package/src/commands/selectTextblockStart.ts +5 -3
  58. package/src/commands/setContent.ts +25 -25
  59. package/src/commands/setMark.ts +55 -57
  60. package/src/commands/setMeta.ts +7 -5
  61. package/src/commands/setNode.ts +32 -30
  62. package/src/commands/setNodeSelection.ts +11 -9
  63. package/src/commands/setTextSelection.ts +15 -13
  64. package/src/commands/sinkListItem.ts +6 -4
  65. package/src/commands/splitBlock.ts +67 -76
  66. package/src/commands/splitListItem.ts +93 -106
  67. package/src/commands/toggleList.ts +73 -71
  68. package/src/commands/toggleMark.ts +11 -9
  69. package/src/commands/toggleNode.ts +18 -16
  70. package/src/commands/toggleWrap.ts +10 -8
  71. package/src/commands/undoInputRule.ts +31 -29
  72. package/src/commands/unsetAllMarks.ts +16 -14
  73. package/src/commands/unsetMark.ts +27 -25
  74. package/src/commands/updateAttributes.ts +92 -100
  75. package/src/commands/wrapIn.ts +6 -4
  76. package/src/commands/wrapInList.ts +6 -4
  77. package/src/extensions/clipboardTextSerializer.ts +2 -4
  78. package/src/extensions/focusEvents.ts +2 -6
  79. package/src/extensions/keymap.ts +54 -50
  80. package/src/extensions/paste.ts +0 -1
  81. package/src/extensions/tabindex.ts +1 -1
  82. package/src/helpers/combineTransactionSteps.ts +1 -4
  83. package/src/helpers/createChainableState.ts +1 -4
  84. package/src/helpers/createDocument.ts +1 -3
  85. package/src/helpers/createNodeFromContent.ts +4 -10
  86. package/src/helpers/findChildrenInRange.ts +1 -5
  87. package/src/helpers/findParentNode.ts +3 -1
  88. package/src/helpers/flattenExtensions.ts +30 -0
  89. package/src/helpers/getAttributes.ts +1 -4
  90. package/src/helpers/getAttributesFromExtensions.ts +28 -37
  91. package/src/helpers/getChangedRanges.ts +13 -11
  92. package/src/helpers/getExtensionField.ts +1 -4
  93. package/src/helpers/getMarkAttributes.ts +1 -4
  94. package/src/helpers/getMarkRange.ts +5 -15
  95. package/src/helpers/getMarkType.ts +1 -3
  96. package/src/helpers/getNodeAttributes.ts +1 -4
  97. package/src/helpers/getNodeType.ts +1 -3
  98. package/src/helpers/getRenderedAttributes.ts +1 -3
  99. package/src/helpers/getSchema.ts +2 -2
  100. package/src/helpers/getSchemaByResolvedExtensions.ts +45 -77
  101. package/src/helpers/getSplittedAttributes.ts +4 -4
  102. package/src/helpers/getTextContentFromNodes.ts +8 -11
  103. package/src/helpers/index.ts +4 -0
  104. package/src/helpers/injectExtensionAttributesToParseRule.ts +1 -1
  105. package/src/helpers/isActive.ts +1 -5
  106. package/src/helpers/isExtensionRulesEnabled.ts +1 -3
  107. package/src/helpers/isNodeEmpty.ts +2 -2
  108. package/src/helpers/resolveExtensions.ts +25 -0
  109. package/src/helpers/resolveFocusPosition.ts +3 -14
  110. package/src/helpers/rewriteUnknownContent.ts +149 -0
  111. package/src/helpers/sortExtensions.ts +26 -0
  112. package/src/inputRules/markInputRule.ts +1 -5
  113. package/src/inputRules/nodeInputRule.ts +2 -9
  114. package/src/inputRules/textInputRule.ts +1 -4
  115. package/src/inputRules/textblockTypeInputRule.ts +2 -8
  116. package/src/inputRules/wrappingInputRule.ts +13 -19
  117. package/src/pasteRules/markPasteRule.ts +1 -3
  118. package/src/pasteRules/nodePasteRule.ts +2 -8
  119. package/src/pasteRules/textPasteRule.ts +1 -4
  120. package/src/types.ts +212 -172
  121. package/src/utilities/createStyleTag.ts +3 -1
  122. package/src/utilities/deleteProps.ts +7 -11
  123. package/src/utilities/findDuplicates.ts +4 -1
  124. package/src/utilities/isFunction.ts +1 -0
  125. package/src/utilities/isMacOS.ts +1 -3
  126. package/src/utilities/isiOS.ts +5 -10
  127. package/src/utilities/mergeAttributes.ts +16 -6
  128. package/src/utilities/removeDuplicates.ts +1 -3
@@ -31,18 +31,14 @@ function canSetMark(state: EditorState, tr: Transaction, newMarkType: MarkType)
31
31
  const currentMarks = state.storedMarks ?? cursor.marks()
32
32
 
33
33
  // There can be no current marks that exclude the new mark
34
- return (
35
- !!newMarkType.isInSet(currentMarks)
36
- || !currentMarks.some(mark => mark.type.excludes(newMarkType))
37
- )
34
+ return !!newMarkType.isInSet(currentMarks) || !currentMarks.some(mark => mark.type.excludes(newMarkType))
38
35
  }
39
36
 
40
37
  const { ranges } = selection
41
38
 
42
39
  return ranges.some(({ $from, $to }) => {
43
- let someNodeSupportsMark = $from.depth === 0
44
- ? state.doc.inlineContent && state.doc.type.allowsMarkType(newMarkType)
45
- : false
40
+ let someNodeSupportsMark =
41
+ $from.depth === 0 ? state.doc.inlineContent && state.doc.type.allowsMarkType(newMarkType) : false
46
42
 
47
43
  state.doc.nodesBetween($from.pos, $to.pos, (node, _pos, parent) => {
48
44
  // If we already found a mark that we can enable, return false to bypass the remaining search
@@ -52,8 +48,8 @@ function canSetMark(state: EditorState, tr: Transaction, newMarkType: MarkType)
52
48
 
53
49
  if (node.isInline) {
54
50
  const parentAllowsMarkType = !parent || parent.type.allowsMarkType(newMarkType)
55
- const currentMarksAllowMarkType = !!newMarkType.isInSet(node.marks)
56
- || !node.marks.some(otherMark => otherMark.type.excludes(newMarkType))
51
+ const currentMarksAllowMarkType =
52
+ !!newMarkType.isInSet(node.marks) || !node.marks.some(otherMark => otherMark.type.excludes(newMarkType))
57
53
 
58
54
  someNodeSupportsMark = parentAllowsMarkType && currentMarksAllowMarkType
59
55
  }
@@ -63,54 +59,56 @@ function canSetMark(state: EditorState, tr: Transaction, newMarkType: MarkType)
63
59
  return someNodeSupportsMark
64
60
  })
65
61
  }
66
- export const setMark: RawCommands['setMark'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
67
- const { selection } = tr
68
- const { empty, ranges } = selection
69
- const type = getMarkType(typeOrName, state.schema)
70
-
71
- if (dispatch) {
72
- if (empty) {
73
- const oldAttributes = getMarkAttributes(state, type)
74
-
75
- tr.addStoredMark(
76
- type.create({
77
- ...oldAttributes,
78
- ...attributes,
79
- }),
80
- )
81
- } else {
82
- ranges.forEach(range => {
83
- const from = range.$from.pos
84
- const to = range.$to.pos
85
-
86
- state.doc.nodesBetween(from, to, (node, pos) => {
87
- const trimmedFrom = Math.max(pos, from)
88
- const trimmedTo = Math.min(pos + node.nodeSize, to)
89
- const someHasMark = node.marks.find(mark => mark.type === type)
90
-
91
- // if there is already a mark of this type
92
- // we know that we have to merge its attributes
93
- // otherwise we add a fresh new mark
94
- if (someHasMark) {
95
- node.marks.forEach(mark => {
96
- if (type === mark.type) {
97
- tr.addMark(
98
- trimmedFrom,
99
- trimmedTo,
100
- type.create({
101
- ...mark.attrs,
102
- ...attributes,
103
- }),
104
- )
105
- }
106
- })
107
- } else {
108
- tr.addMark(trimmedFrom, trimmedTo, type.create(attributes))
109
- }
62
+ export const setMark: RawCommands['setMark'] =
63
+ (typeOrName, attributes = {}) =>
64
+ ({ tr, state, dispatch }) => {
65
+ const { selection } = tr
66
+ const { empty, ranges } = selection
67
+ const type = getMarkType(typeOrName, state.schema)
68
+
69
+ if (dispatch) {
70
+ if (empty) {
71
+ const oldAttributes = getMarkAttributes(state, type)
72
+
73
+ tr.addStoredMark(
74
+ type.create({
75
+ ...oldAttributes,
76
+ ...attributes,
77
+ }),
78
+ )
79
+ } else {
80
+ ranges.forEach(range => {
81
+ const from = range.$from.pos
82
+ const to = range.$to.pos
83
+
84
+ state.doc.nodesBetween(from, to, (node, pos) => {
85
+ const trimmedFrom = Math.max(pos, from)
86
+ const trimmedTo = Math.min(pos + node.nodeSize, to)
87
+ const someHasMark = node.marks.find(mark => mark.type === type)
88
+
89
+ // if there is already a mark of this type
90
+ // we know that we have to merge its attributes
91
+ // otherwise we add a fresh new mark
92
+ if (someHasMark) {
93
+ node.marks.forEach(mark => {
94
+ if (type === mark.type) {
95
+ tr.addMark(
96
+ trimmedFrom,
97
+ trimmedTo,
98
+ type.create({
99
+ ...mark.attrs,
100
+ ...attributes,
101
+ }),
102
+ )
103
+ }
104
+ })
105
+ } else {
106
+ tr.addMark(trimmedFrom, trimmedTo, type.create(attributes))
107
+ }
108
+ })
110
109
  })
111
- })
110
+ }
112
111
  }
113
- }
114
112
 
115
- return canSetMark(state, tr, type)
116
- }
113
+ return canSetMark(state, tr, type)
114
+ }
@@ -11,13 +11,15 @@ declare module '@tiptap/core' {
11
11
  * @param value The value to store.
12
12
  * @example editor.commands.setMeta('foo', 'bar')
13
13
  */
14
- setMeta: (key: string | Plugin | PluginKey, value: any) => ReturnType,
14
+ setMeta: (key: string | Plugin | PluginKey, value: any) => ReturnType
15
15
  }
16
16
  }
17
17
  }
18
18
 
19
- export const setMeta: RawCommands['setMeta'] = (key, value) => ({ tr }) => {
20
- tr.setMeta(key, value)
19
+ export const setMeta: RawCommands['setMeta'] =
20
+ (key, value) =>
21
+ ({ tr }) => {
22
+ tr.setMeta(key, value)
21
23
 
22
- return true
23
- }
24
+ return true
25
+ }
@@ -18,38 +18,40 @@ declare module '@tiptap/core' {
18
18
  }
19
19
  }
20
20
 
21
- export const setNode: RawCommands['setNode'] = (typeOrName, attributes = {}) => ({ state, dispatch, chain }) => {
22
- const type = getNodeType(typeOrName, state.schema)
21
+ export const setNode: RawCommands['setNode'] =
22
+ (typeOrName, attributes = {}) =>
23
+ ({ state, dispatch, chain }) => {
24
+ const type = getNodeType(typeOrName, state.schema)
23
25
 
24
- let attributesToCopy: Record<string, any> | undefined
26
+ let attributesToCopy: Record<string, any> | undefined
25
27
 
26
- if (state.selection.$anchor.sameParent(state.selection.$head)) {
27
- // only copy attributes if the selection is pointing to a node of the same type
28
- attributesToCopy = state.selection.$anchor.parent.attrs
29
- }
28
+ if (state.selection.$anchor.sameParent(state.selection.$head)) {
29
+ // only copy attributes if the selection is pointing to a node of the same type
30
+ attributesToCopy = state.selection.$anchor.parent.attrs
31
+ }
30
32
 
31
- // TODO: use a fallback like insertContent?
32
- if (!type.isTextblock) {
33
- console.warn('[tiptap warn]: Currently "setNode()" only supports text block nodes.')
33
+ // TODO: use a fallback like insertContent?
34
+ if (!type.isTextblock) {
35
+ console.warn('[tiptap warn]: Currently "setNode()" only supports text block nodes.')
34
36
 
35
- return false
36
- }
37
+ return false
38
+ }
37
39
 
38
- return (
39
- chain()
40
- // try to convert node to default node if needed
41
- .command(({ commands }) => {
42
- const canSetBlock = setBlockType(type, { ...attributesToCopy, ...attributes })(state)
43
-
44
- if (canSetBlock) {
45
- return true
46
- }
47
-
48
- return commands.clearNodes()
49
- })
50
- .command(({ state: updatedState }) => {
51
- return setBlockType(type, { ...attributesToCopy, ...attributes })(updatedState, dispatch)
52
- })
53
- .run()
54
- )
55
- }
40
+ return (
41
+ chain()
42
+ // try to convert node to default node if needed
43
+ .command(({ commands }) => {
44
+ const canSetBlock = setBlockType(type, { ...attributesToCopy, ...attributes })(state)
45
+
46
+ if (canSetBlock) {
47
+ return true
48
+ }
49
+
50
+ return commands.clearNodes()
51
+ })
52
+ .command(({ state: updatedState }) => {
53
+ return setBlockType(type, { ...attributesToCopy, ...attributes })(updatedState, dispatch)
54
+ })
55
+ .run()
56
+ )
57
+ }
@@ -16,14 +16,16 @@ declare module '@tiptap/core' {
16
16
  }
17
17
  }
18
18
 
19
- export const setNodeSelection: RawCommands['setNodeSelection'] = position => ({ tr, dispatch }) => {
20
- if (dispatch) {
21
- const { doc } = tr
22
- const from = minMax(position, 0, doc.content.size)
23
- const selection = NodeSelection.create(doc, from)
19
+ export const setNodeSelection: RawCommands['setNodeSelection'] =
20
+ position =>
21
+ ({ tr, dispatch }) => {
22
+ if (dispatch) {
23
+ const { doc } = tr
24
+ const from = minMax(position, 0, doc.content.size)
25
+ const selection = NodeSelection.create(doc, from)
24
26
 
25
- tr.setSelection(selection)
26
- }
27
+ tr.setSelection(selection)
28
+ }
27
29
 
28
- return true
29
- }
30
+ return true
31
+ }
@@ -16,18 +16,20 @@ declare module '@tiptap/core' {
16
16
  }
17
17
  }
18
18
 
19
- export const setTextSelection: RawCommands['setTextSelection'] = position => ({ tr, dispatch }) => {
20
- if (dispatch) {
21
- const { doc } = tr
22
- const { from, to } = typeof position === 'number' ? { from: position, to: position } : position
23
- const minPos = TextSelection.atStart(doc).from
24
- const maxPos = TextSelection.atEnd(doc).to
25
- const resolvedFrom = minMax(from, minPos, maxPos)
26
- const resolvedEnd = minMax(to, minPos, maxPos)
27
- const selection = TextSelection.create(doc, resolvedFrom, resolvedEnd)
19
+ export const setTextSelection: RawCommands['setTextSelection'] =
20
+ position =>
21
+ ({ tr, dispatch }) => {
22
+ if (dispatch) {
23
+ const { doc } = tr
24
+ const { from, to } = typeof position === 'number' ? { from: position, to: position } : position
25
+ const minPos = TextSelection.atStart(doc).from
26
+ const maxPos = TextSelection.atEnd(doc).to
27
+ const resolvedFrom = minMax(from, minPos, maxPos)
28
+ const resolvedEnd = minMax(to, minPos, maxPos)
29
+ const selection = TextSelection.create(doc, resolvedFrom, resolvedEnd)
28
30
 
29
- tr.setSelection(selection)
30
- }
31
+ tr.setSelection(selection)
32
+ }
31
33
 
32
- return true
33
- }
34
+ return true
35
+ }
@@ -17,8 +17,10 @@ declare module '@tiptap/core' {
17
17
  }
18
18
  }
19
19
 
20
- export const sinkListItem: RawCommands['sinkListItem'] = typeOrName => ({ state, dispatch }) => {
21
- const type = getNodeType(typeOrName, state.schema)
20
+ export const sinkListItem: RawCommands['sinkListItem'] =
21
+ typeOrName =>
22
+ ({ state, dispatch }) => {
23
+ const type = getNodeType(typeOrName, state.schema)
22
24
 
23
- return originalSinkListItem(type)(state, dispatch)
24
- }
25
+ return originalSinkListItem(type)(state, dispatch)
26
+ }
@@ -29,95 +29,86 @@ declare module '@tiptap/core' {
29
29
  }
30
30
  }
31
31
 
32
- export const splitBlock: RawCommands['splitBlock'] = ({ keepMarks = true } = {}) => ({
33
- tr, state, dispatch, editor,
34
- }) => {
35
- const { selection, doc } = tr
36
- const { $from, $to } = selection
37
- const extensionAttributes = editor.extensionManager.attributes
38
- const newAttributes = getSplittedAttributes(
39
- extensionAttributes,
40
- $from.node().type.name,
41
- $from.node().attrs,
42
- )
43
-
44
- if (selection instanceof NodeSelection && selection.node.isBlock) {
45
- if (!$from.parentOffset || !canSplit(doc, $from.pos)) {
46
- return false
47
- }
32
+ export const splitBlock: RawCommands['splitBlock'] =
33
+ ({ keepMarks = true } = {}) =>
34
+ ({ tr, state, dispatch, editor }) => {
35
+ const { selection, doc } = tr
36
+ const { $from, $to } = selection
37
+ const extensionAttributes = editor.extensionManager.attributes
38
+ const newAttributes = getSplittedAttributes(extensionAttributes, $from.node().type.name, $from.node().attrs)
39
+
40
+ if (selection instanceof NodeSelection && selection.node.isBlock) {
41
+ if (!$from.parentOffset || !canSplit(doc, $from.pos)) {
42
+ return false
43
+ }
48
44
 
49
- if (dispatch) {
50
- if (keepMarks) {
51
- ensureMarks(state, editor.extensionManager.splittableMarks)
45
+ if (dispatch) {
46
+ if (keepMarks) {
47
+ ensureMarks(state, editor.extensionManager.splittableMarks)
48
+ }
49
+
50
+ tr.split($from.pos).scrollIntoView()
52
51
  }
53
52
 
54
- tr.split($from.pos).scrollIntoView()
53
+ return true
55
54
  }
56
55
 
57
- return true
58
- }
59
-
60
- if (!$from.parent.isBlock) {
61
- return false
62
- }
56
+ if (!$from.parent.isBlock) {
57
+ return false
58
+ }
63
59
 
64
- const atEnd = $to.parentOffset === $to.parent.content.size
65
-
66
- const deflt = $from.depth === 0
67
- ? undefined
68
- : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)))
69
-
70
- let types = atEnd && deflt
71
- ? [
72
- {
73
- type: deflt,
74
- attrs: newAttributes,
75
- },
76
- ]
77
- : undefined
78
-
79
- let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types)
80
-
81
- if (
82
- !types
83
- && !can
84
- && canSplit(tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : undefined)
85
- ) {
86
- can = true
87
- types = deflt
88
- ? [
89
- {
90
- type: deflt,
91
- attrs: newAttributes,
92
- },
93
- ]
94
- : undefined
95
- }
60
+ const atEnd = $to.parentOffset === $to.parent.content.size
61
+
62
+ const deflt = $from.depth === 0 ? undefined : defaultBlockAt($from.node(-1).contentMatchAt($from.indexAfter(-1)))
63
+
64
+ let types =
65
+ atEnd && deflt
66
+ ? [
67
+ {
68
+ type: deflt,
69
+ attrs: newAttributes,
70
+ },
71
+ ]
72
+ : undefined
73
+
74
+ let can = canSplit(tr.doc, tr.mapping.map($from.pos), 1, types)
75
+
76
+ if (!types && !can && canSplit(tr.doc, tr.mapping.map($from.pos), 1, deflt ? [{ type: deflt }] : undefined)) {
77
+ can = true
78
+ types = deflt
79
+ ? [
80
+ {
81
+ type: deflt,
82
+ attrs: newAttributes,
83
+ },
84
+ ]
85
+ : undefined
86
+ }
96
87
 
97
- if (dispatch) {
98
- if (can) {
99
- if (selection instanceof TextSelection) {
100
- tr.deleteSelection()
101
- }
88
+ if (dispatch) {
89
+ if (can) {
90
+ if (selection instanceof TextSelection) {
91
+ tr.deleteSelection()
92
+ }
102
93
 
103
- tr.split(tr.mapping.map($from.pos), 1, types)
94
+ tr.split(tr.mapping.map($from.pos), 1, types)
104
95
 
105
- if (deflt && !atEnd && !$from.parentOffset && $from.parent.type !== deflt) {
106
- const first = tr.mapping.map($from.before())
107
- const $first = tr.doc.resolve(first)
96
+ if (deflt && !atEnd && !$from.parentOffset && $from.parent.type !== deflt) {
97
+ const first = tr.mapping.map($from.before())
98
+ const $first = tr.doc.resolve(first)
108
99
 
109
- if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) {
110
- tr.setNodeMarkup(tr.mapping.map($from.before()), deflt)
100
+ if ($from.node(-1).canReplaceWith($first.index(), $first.index() + 1, deflt)) {
101
+ tr.setNodeMarkup(tr.mapping.map($from.before()), deflt)
102
+ }
111
103
  }
112
104
  }
113
- }
114
105
 
115
- if (keepMarks) {
116
- ensureMarks(state, editor.extensionManager.splittableMarks)
106
+ if (keepMarks) {
107
+ ensureMarks(state, editor.extensionManager.splittableMarks)
108
+ }
109
+
110
+ tr.scrollIntoView()
117
111
  }
118
112
 
119
- tr.scrollIntoView()
113
+ return can
120
114
  }
121
-
122
- return can
123
- }