Skip to content

fix(editor): persist and render text alignment on blocks#761

Open
drudge wants to merge 4 commits intoemdash-cms:mainfrom
drudge:drudge/editor-align-fix
Open

fix(editor): persist and render text alignment on blocks#761
drudge wants to merge 4 commits intoemdash-cms:mainfrom
drudge:drudge/editor-align-fix

Conversation

@drudge
Copy link
Copy Markdown
Contributor

@drudge drudge commented Apr 24, 2026

What does this PR do?

Fixes a bug where text alignment applied in the admin editor (center, right, justify) did not show up on the rendered site — and, on a closer review, also did not survive a reload in the editor itself. Reported case: select an h1, click "Center" in the editor toolbar, save — the heading still renders left-aligned on the public page.

The bug spanned two separate converter pairs plus the renderer:

Core (packages/core)

  1. Save converterprosemirrorToPortableText dropped node.attrs.textAlign for paragraphs and headings, so alignment never reached the database.
  2. SchemaPortableTextTextBlock had no textAlign field.
  3. Load converterportableTextToProsemirror never restored textAlign onto the rehydrated node.
  4. RendereremdashComponents had no block style renderer, so astro-portabletext's default emitted plain <p> / <h1> with no alignment applied.

Admin (packages/admin/src/components/PortableTextEditor.tsx)

The admin editor inlines its own copy of the PM↔PT converter pair and a local PortableTextTextBlock type. Patching core alone was not enough — the admin still wrote blocks without textAlign, which is why alignment applied in the toolbar also vanished on reload. Mirrored the same fix in the admin's duplicates.

Modeled as a top-level block property (consistent with how style, listItem, level, and image dimensions are modeled; inline marks would be semantically wrong since alignment is block-level). The default "left" is normalized away on save so existing payloads stay byte-identical.

Follow-up

The admin's inlined converter pair (~500 LOC) duplicates packages/core/src/content/converters/* and caused the split-brain that motivated the second commit in this PR. A follow-up should delete the admin copies and import from core. That's a refactor, so it needs a prior Discussion per CONTRIBUTING.md and is out of scope for this bug fix.

Closes #

Type of change

  • Bug fix
  • Feature (requires maintainer-approved Discussion)
  • Refactor (no behavior change)
  • Translation
  • Documentation
  • Performance improvement
  • Tests
  • Chore (dependencies, CI, tooling)

Checklist

  • I have read CONTRIBUTING.md
  • pnpm typecheck passes
  • pnpm lint passes
  • pnpm test passes (or targeted tests for my change)
  • pnpm format has been run
  • I have added/updated tests for my changes (if applicable)
  • User-visible strings in the admin UI are wrapped for translation and pnpm locale:extract has been run (if applicable)
  • I have added a changeset (if this PR changes a published package)
  • New features link to an approved Discussion: https://github.com/emdash-cms/emdash/discussions/...

Translation checkbox N/A — no new admin UI strings. New-feature checkbox N/A — bug fix.

AI-generated code disclosure

  • This PR includes AI-generated code

Changesets

Two patch changesets since the fix spans two published packages:

  • .changeset/editor-text-alignment-render.mdemdash (core converter + renderer)
  • .changeset/admin-text-alignment-persist.md@emdash-cms/admin (inlined-converter fix)

Screenshots / test output

Rendered HTML from end-to-end verification (POST via API with textAlign on an h1 + p, then GET the public post page):

<div class="article-content">
  <h1 style="text-align: center;">Centered Heading</h1>
  <p style="text-align: right;">Right-aligned paragraph.</p>
  <p>Normal paragraph (no alignment).</p>
</div>

The h1 is centered, the p is right-aligned, and the un-aligned p has no inline style — confirming the default is normalized away on save.

Tests:

  • packages/core/tests/unit/converters/text-alignment.test.ts — 4 round-trip tests against the core converters.
  • packages/admin/tests/editor/text-alignment.test.ts — 4 matching tests against the admin's exported _prosemirrorToPortableText / _portableTextToProsemirror.

Core suite: 2,591/2,591 pass. Admin suite: 790/790 pass.

Text alignment applied in the admin editor (center, right, justify) was
silently dropped because the ProseMirror → Portable Text converter ignored
node.attrs.textAlign, the type had no field for it, and the PortableText
renderer emitted plain tags with no style. Alignment now round-trips through
the converters and renders as inline text-align on paragraph, heading, and
blockquote blocks.
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented Apr 24, 2026

🦋 Changeset detected

Latest commit: 26b3b61

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 13 packages
Name Type
@emdash-cms/admin Patch
emdash Patch
@emdash-cms/cloudflare Patch
@emdash-cms/fixture-perf-site Patch
@emdash-cms/perf-demo-site Patch
@emdash-cms/cache-demo-site Patch
@emdash-cms/auth Patch
@emdash-cms/blocks Patch
@emdash-cms/gutenberg-to-portable-text Patch
@emdash-cms/x402 Patch
create-emdash Patch
@emdash-cms/auth-atproto Patch
@emdash-cms/plugin-embeds Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 24, 2026

Open in StackBlitz

@emdash-cms/admin

npm i https://pkg.pr.new/@emdash-cms/admin@761

@emdash-cms/auth

npm i https://pkg.pr.new/@emdash-cms/auth@761

@emdash-cms/blocks

npm i https://pkg.pr.new/@emdash-cms/blocks@761

@emdash-cms/cloudflare

npm i https://pkg.pr.new/@emdash-cms/cloudflare@761

emdash

npm i https://pkg.pr.new/emdash@761

create-emdash

npm i https://pkg.pr.new/create-emdash@761

@emdash-cms/gutenberg-to-portable-text

npm i https://pkg.pr.new/@emdash-cms/gutenberg-to-portable-text@761

@emdash-cms/x402

npm i https://pkg.pr.new/@emdash-cms/x402@761

@emdash-cms/plugin-ai-moderation

npm i https://pkg.pr.new/@emdash-cms/plugin-ai-moderation@761

@emdash-cms/plugin-atproto

npm i https://pkg.pr.new/@emdash-cms/plugin-atproto@761

@emdash-cms/plugin-audit-log

npm i https://pkg.pr.new/@emdash-cms/plugin-audit-log@761

@emdash-cms/plugin-color

npm i https://pkg.pr.new/@emdash-cms/plugin-color@761

@emdash-cms/plugin-embeds

npm i https://pkg.pr.new/@emdash-cms/plugin-embeds@761

@emdash-cms/plugin-forms

npm i https://pkg.pr.new/@emdash-cms/plugin-forms@761

@emdash-cms/plugin-webhook-notifier

npm i https://pkg.pr.new/@emdash-cms/plugin-webhook-notifier@761

commit: 48982d5

drudge added a commit to drudge/emdash that referenced this pull request Apr 24, 2026
The admin editor inlines its own copy of the ProseMirror ↔ Portable Text
converter pair (PortableTextEditor.tsx), separate from the shared core
converters. The prior commit patched core but missed the admin duplicate,
so the editor was still dropping textAlign on save — alignment applied in
the toolbar vanished on reload. Mirror the fix into the admin converters.

A follow-up should delete the admin's inlined converters and import from
core to eliminate this drift class.
drudge added a commit to drudge/emdash that referenced this pull request Apr 24, 2026
@drudge drudge marked this pull request as ready for review April 24, 2026 16:12
@github-actions
Copy link
Copy Markdown
Contributor

Overlapping PRs

This PR modifies files that are also changed by other open PRs:

This may cause merge conflicts or duplicated work. A maintainer will coordinate.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants