Affected Packages
core, extension-mention
Version(s)
3.23.4(latest)
Bug Description
First of all, thank you for maintaining Tiptap and for all the work that goes into this project.
I am not completely sure whether this is the intended behavior or an actual bug, but I encountered a few cases where inputRules seem to behave unexpectedly when used together with the Mention extension.
I tried to investigate the issue and found that it may be related to how inputRules calculate ranges when inline atom nodes are involved. I would appreciate it if you could confirm whether this is a bug, an expected limitation, or if there is a recommended way to handle this case.
InputRules appear to calculate ranges from rendered text content instead of safely mapping back to actual ProseMirror document positions. This causes incorrect replacements when inline atom nodes such as Mention are included in or near the matched text.
Since Mention's nodeSize differs from the length of its renderText output, the matched text range and the actual document range can diverge. As a result, inputRules may apply transformations to the wrong range or unexpectedly remove mention content.
Examples:
-
'` [@developer]`'
When an inputRule converts this into inline code, the wrong range is converted.
-
'[@developer<]-'
The <- inputRule can be triggered around the mention boundary, and the mention text is unexpectedly removed.
-
'[@\d `eveloper] text `'
Similar to the first case, the calculated range is incorrect when a mention and inline code-like text are involved.
I suspect the issue may be related to a few areas in the codebase:
core/src/InputRule.ts
When InputRule calculates the range, inline atom/block-like nodes may need to be handled differently from plain text nodes.
In particular, I suspect that the logic that sets the const range may be incorrect in this case. It seems to calculate the range based on the length of the matched/rendered text, but inline atom nodes such as Mention can have a nodeSize that differs from the length of their rendered text representation.
Because of this mismatch, the calculated range.from and range.to may not correspond to the actual ProseMirror document positions. As a result, when the inputRule applies a transaction, it can transform or replace the wrong part of the document.
Currently, the matched text range and the actual ProseMirror document range can diverge when inline nodes such as Mention are included in the match.
extension-mention
One possible workaround or improvement might be to safely mark the boundaries of the mention node by inserting zero-width spaces on both sides in the text representation.
For example:
return `\u200B${suggestion?.char ?? '@'}${node.attrs.label ?? node.attrs.id}\u200B`
This may help prevent inputRules from matching across mention node boundaries unintentionally.
core/src/helpers/getTextContentFromNodes.ts
It may also be necessary to review how node.type.spec.toText and the node's renderText output are handled together.
Since getTextContentFromNodes uses the rendered text representation of nodes, inputRules may detect matches that do not safely map back to actual document positions.
In particular, it may be necessary to check whether inputRules should be ignored when a match occurs inside or across the boundary of an inline atom node.
Browser Used
Chrome
Code Example URL
No response
Expected Behavior
InputRules should either correctly map matched rendered text back to document positions, or avoid running when the match crosses inline atom node boundaries in a way that cannot be safely mapped.
Additional Context (Optional)
No response
Dependency Updates
Affected Packages
core, extension-mention
Version(s)
3.23.4(latest)
Bug Description
First of all, thank you for maintaining Tiptap and for all the work that goes into this project.
I am not completely sure whether this is the intended behavior or an actual bug, but I encountered a few cases where inputRules seem to behave unexpectedly when used together with the Mention extension.
I tried to investigate the issue and found that it may be related to how inputRules calculate ranges when inline atom nodes are involved. I would appreciate it if you could confirm whether this is a bug, an expected limitation, or if there is a recommended way to handle this case.
InputRules appear to calculate ranges from rendered text content instead of safely mapping back to actual ProseMirror document positions. This causes incorrect replacements when inline atom nodes such as Mention are included in or near the matched text.
Since Mention's nodeSize differs from the length of its renderText output, the matched text range and the actual document range can diverge. As a result, inputRules may apply transformations to the wrong range or unexpectedly remove mention content.
Examples:
'` [@developer]`'
When an inputRule converts this into inline code, the wrong range is converted.
'[@developer<]-'
The
<-inputRule can be triggered around the mention boundary, and the mention text is unexpectedly removed.'[@\d `eveloper] text `'
Similar to the first case, the calculated range is incorrect when a mention and inline code-like text are involved.
I suspect the issue may be related to a few areas in the codebase:
core/src/InputRule.tsWhen
InputRulecalculates the range, inline atom/block-like nodes may need to be handled differently from plain text nodes.In particular, I suspect that the logic that sets the
const rangemay be incorrect in this case. It seems to calculate the range based on the length of the matched/rendered text, but inline atom nodes such as Mention can have anodeSizethat differs from the length of their rendered text representation.Because of this mismatch, the calculated
range.fromandrange.tomay not correspond to the actual ProseMirror document positions. As a result, when the inputRule applies a transaction, it can transform or replace the wrong part of the document.Currently, the matched text range and the actual ProseMirror document range can diverge when inline nodes such as Mention are included in the match.
extension-mentionOne possible workaround or improvement might be to safely mark the boundaries of the mention node by inserting zero-width spaces on both sides in the text representation.
For example:
This may help prevent inputRules from matching across mention node boundaries unintentionally.
core/src/helpers/getTextContentFromNodes.tsIt may also be necessary to review how node.type.spec.toText and the node's renderText output are handled together.
Since getTextContentFromNodes uses the rendered text representation of nodes, inputRules may detect matches that do not safely map back to actual document positions.
In particular, it may be necessary to check whether inputRules should be ignored when a match occurs inside or across the boundary of an inline atom node.
Browser Used
Chrome
Code Example URL
No response
Expected Behavior
InputRules should either correctly map matched rendered text back to document positions, or avoid running when the match crosses inline atom node boundaries in a way that cannot be safely mapped.
Additional Context (Optional)
No response
Dependency Updates