Fix horizontal rule can() check always returning true (#6492)
Some checks failed
build / lint (20) (push) Has been cancelled
build / test (20, map[name:Demos/Examples spec:./demos/src/Examples/**/*.spec.{js,ts}]) (push) Has been cancelled
build / test (20, map[name:Demos/Experiments spec:./demos/src/Experiments/**/*.spec.{js,ts}]) (push) Has been cancelled
build / test (20, map[name:Demos/Extensions spec:./demos/src/Extensions/**/*.spec.{js,ts}]) (push) Has been cancelled
build / test (20, map[name:Demos/GuideContent spec:./demos/src/GuideContent/**/*.spec.{js,ts}]) (push) Has been cancelled
build / test (20, map[name:Demos/GuideGettingStarted spec:./demos/src/GuideGettingStarted/**/*.spec.{js,ts}]) (push) Has been cancelled
build / test (20, map[name:Demos/Marks spec:./demos/src/Marks/**/*.spec.{js,ts}]) (push) Has been cancelled
build / test (20, map[name:Demos/Nodes spec:./demos/src/Nodes/**/*.spec.{js,ts}]) (push) Has been cancelled
build / test (20, map[name:Integration spec:./tests/cypress/integration/**/*.spec.{js,ts}]) (push) Has been cancelled
Publish / Release (20) (push) Has been cancelled
build / build (20) (push) Has been cancelled

* fixed the horizontal rule command always returning true, even if it's not insertable

* added changeset

* move canInsertNode util to core

* added changeset

* simplify matchType call

* fix import

* adjust import and export paths
This commit is contained in:
bdbch 2025-06-22 00:21:18 +02:00 committed by Dominik Biedebach
parent 120e9dd03a
commit 080c51ff4f
5 changed files with 48 additions and 1 deletions

View File

@ -0,0 +1,5 @@
---
'@tiptap/extension-horizontal-rule': patch
---
Fixed a bug that caused the horizontal rule's `setHorizontalRule` command to always return true when checked via `can()`

View File

@ -0,0 +1,5 @@
---
'@tiptap/core': patch
---
Added new `canInsertNode` utility that checks if a node can be inserted into a specific position

View File

@ -0,0 +1,31 @@
import type { NodeType } from '@tiptap/pm/model'
import { type EditorState, NodeSelection } from '@tiptap/pm/state'
export function canInsertNode(state: EditorState, nodeType: NodeType): boolean {
const { selection } = state
const { $from } = selection
// Special handling for NodeSelection
if (selection instanceof NodeSelection) {
const index = $from.index()
const parent = $from.parent
// Can we replace the selected node with the horizontal rule?
return parent.canReplaceWith(index, index + 1, nodeType)
}
// Default: check if we can insert at the current position
let depth = $from.depth
while (depth >= 0) {
const index = $from.index(depth)
const parent = $from.node(depth)
const match = parent.contentMatchAt(index)
if (match.matchType(nodeType)) {
return true
}
depth -= 1
}
return false
}

View File

@ -1,4 +1,5 @@
export * from './callOrReturn.js' export * from './callOrReturn.js'
export * from './canInsertNode.js'
export * from './createStyleTag.js' export * from './createStyleTag.js'
export * from './deleteProps.js' export * from './deleteProps.js'
export * from './elementFromString.js' export * from './elementFromString.js'

View File

@ -1,5 +1,5 @@
import { import {
isNodeSelection, mergeAttributes, Node, nodeInputRule, canInsertNode, isNodeSelection, mergeAttributes, Node, nodeInputRule,
} from '@tiptap/core' } from '@tiptap/core'
import { NodeSelection, TextSelection } from '@tiptap/pm/state' import { NodeSelection, TextSelection } from '@tiptap/pm/state'
@ -51,6 +51,11 @@ export const HorizontalRule = Node.create<HorizontalRuleOptions>({
return { return {
setHorizontalRule: setHorizontalRule:
() => ({ chain, state }) => { () => ({ chain, state }) => {
// Check if we can insert the node at the current selection
if (!canInsertNode(state, state.schema.nodes[this.name])) {
return false
}
const { selection } = state const { selection } = state
const { $from: $originFrom, $to: $originTo } = selection const { $from: $originFrom, $to: $originTo } = selection