import { Decoration, EditorView, WidgetType } from '@codemirror/view'; import makeInlineReplaceExtension from './utils/makeInlineReplaceExtension'; const dividerClassName = 'cm-md-divider'; const dividerLineClassName = 'cm-md-divider-line'; class DividerWidget extends WidgetType { public constructor() { super(); } public eq(_other: DividerWidget) { return true; } public toDOM() { const container = document.createElement('hr'); container.classList.add(dividerClassName); return container; } public ignoreEvent() { return true; } } const dividerLineMark = Decoration.line({ class: dividerLineClassName }); // Node names that should be rendered as dividers const dividerNodeNames = ['HorizontalRule', 'FrontMatterMarker']; const replaceDividers = [ EditorView.theme({ [`& .cm-line.${dividerLineClassName}`]: { // Use flex layout to allow the divider to fill the remainder of the line. // This applies, for example, to the case where the divider is in a blockquote or // a sub list item. display: 'flex', flexWrap: 'wrap', }, [`& .${dividerClassName}`]: { // Fill remaining width flexGrow: 1, flexShrink: 1, border: 'none', borderBottom: '2px solid var(--joplin-divider-color)', position: 'relative', }, }), makeInlineReplaceExtension({ createDecoration: (node) => { if (dividerNodeNames.includes(node.name)) { return new DividerWidget(); } return null; }, }), makeInlineReplaceExtension({ createDecoration: (node) => { if (dividerNodeNames.includes(node.name)) { return dividerLineMark; } return null; }, getDecorationRange: (node, state) => { const line = state.doc.lineAt(node.from); return [line.from]; }, }), ]; export default replaceDividers;