fix(git-sync): round-trip paragraph/heading text alignment (review #10)

Aligned paragraphs were exported as <div align="…"> which had NO matching
import parse rule — the div was unwrapped and the alignment lost on every
round trip. Emit a styled <p style="text-align:…"> instead, and give the
textAlign global attribute (docmost-schema) an explicit parseHTML that reads
element.style.textAlign (and legacy align=) plus a renderHTML that writes the
style. Now heading/paragraph alignment survives Docmost->git->Docmost.

Verified on stand: a textAlign=center paragraph exports as
<p style="text-align:center">, and after a git-side edit + re-import the
paragraph still has textAlign=center in the DB (was null before).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
claude-stand
2026-07-02 18:36:53 +03:00
parent f9cd3e6318
commit bb5bb52244
2 changed files with 19 additions and 2 deletions
+13 -1
View File
@@ -238,7 +238,19 @@ const DocmostAttributes = Extension.create({
attributes: {
id: { default: null },
indent: { default: null },
textAlign: { default: null },
// textAlign must round-trip the exported `<p style="text-align:…">`
// (and the legacy `<... align="…">`) form (review #10). Without an
// explicit parseHTML the default reads a bare `textAlign` attribute
// (never present), so alignment was silently dropped on every import.
textAlign: {
default: null,
parseHTML: (el: HTMLElement) =>
el.style?.textAlign || el.getAttribute("align") || null,
renderHTML: (attrs: Record<string, any>) =>
attrs.textAlign
? { style: `text-align: ${attrs.textAlign}` }
: {},
},
},
},
{
@@ -97,7 +97,12 @@ export function convertProseMirrorToMarkdown(content: any): string {
const text = nodeContent.map(processNode).join("");
const align = node.attrs?.textAlign;
if (align && align !== "left") {
return `<div align="${escapeAttr(align)}">${text}</div>`;
// Emit alignment as a styled `<p>` (review #10). The old
// `<div align="…">` had NO matching import parse rule — the div was
// unwrapped and alignment lost on every round trip. A styled `<p>`
// round-trips: the paragraph parse rule (tag:"p") matches and the
// textAlign global-attribute parseHTML (docmost-schema) reads the style.
return `<p style="text-align:${escapeAttr(align)}">${text}</p>`;
}
return text || "";