Add enhanced horizontal rule extension with markdown indentation support

- Create EnhancedHorizontalRule extension that preserves leading spaces (0-3) in markdown serialization
- Store indentation as data attribute and restore it during markdown rendering
- Fix YAML front matter parsing to not match indented horizontal rules as front matter
This commit is contained in:
suyao 2025-10-29 08:04:21 +08:00
parent cfb9ee7df3
commit 9b8e4d1d70
No known key found for this signature in database
2 changed files with 75 additions and 1 deletions

View File

@ -0,0 +1,74 @@
import { mergeAttributes } from '@tiptap/core'
import { HorizontalRule } from '@tiptap/extension-horizontal-rule'
/**
* Enhanced HorizontalRule extension that preserves leading spaces in markdown
*
* Standard Markdown allows 0-3 spaces before a horizontal rule (---, ***, ___)
* This extension preserves that indentation when serializing back to markdown
*/
export const EnhancedHorizontalRule = HorizontalRule.extend({
addAttributes() {
return {
...this.parent?.(),
// Store the number of leading spaces (0-3)
indentation: {
default: 0,
parseHTML: (element) => {
const indent = element.getAttribute('data-indentation')
return indent ? parseInt(indent, 10) : 0
},
renderHTML: (attributes) => {
if (!attributes.indentation) return {}
return {
'data-indentation': attributes.indentation
}
}
}
}
},
parseHTML() {
return [
{
tag: 'hr',
getAttrs: (element) => {
if (typeof element === 'string') return {}
const htmlElement = element as HTMLElement
const indentAttr = htmlElement.getAttribute('data-indentation')
return {
indentation: indentAttr ? parseInt(indentAttr, 10) : 0
}
}
}
]
},
renderHTML({ HTMLAttributes }) {
return ['hr', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes)]
},
// Custom markdown parsing to capture leading spaces
parseMarkdown(token) {
// The token.raw contains the original markdown including leading spaces
// Match 0-3 leading spaces before ---, ***, or ___
const match = /^( {0,3})(?:---|___|\*\*\*)/.exec(token.raw || '')
const indentation = match ? match[1].length : 0
return {
type: this.name,
attrs: {
indentation
}
}
},
// Custom markdown serialization to restore leading spaces
renderMarkdown(node) {
const indentation = node.attrs?.indentation || 0
const spaces = ' '.repeat(Math.min(indentation, 3)) // Max 3 spaces per spec
return spaces + '---\n\n'
}
})

View File

@ -23,7 +23,7 @@ export const YamlFrontMatter = Node.create({
level: 'block',
start(src: string) {
const result = src.match(/^\s*---\n/) ? 0 : -1
const result = src.match(/^---\n/) ? 0 : -1
return result
},
// Parse YAML front matter