Skip to content

feat(linked-styles): redefine named paragraph styles ("Update to match")#3758

Open
shri-scale wants to merge 2 commits into
superdoc-dev:mainfrom
shri-scale:feature/redefine-named-paragraph-styles
Open

feat(linked-styles): redefine named paragraph styles ("Update to match")#3758
shri-scale wants to merge 2 commits into
superdoc-dev:mainfrom
shri-scale:feature/redefine-named-paragraph-styles

Conversation

@shri-scale

Copy link
Copy Markdown
Contributor

What

Adds a supported way to redefine a named paragraph style's run-level look (font family, size, bold/italic/underline, color) so it updates live and survives .docx export — the editor equivalent of Google Docs' "Update Heading 1 to match selection".

Previously the linked-styles extension could only apply an existing style (setLinkedStyle, setStyleById); there was no supported way to redefine what a style means.

API

  • Commandeditor.commands.updateLinkedStyle(styleId, formatting) rewrites the style across all three converter representations (linkedStyles[].definition.styles, translatedLinkedStyles.styles[id], word/styles.xml) under a single snapshot/rollback; never throws.
  • Helpers
    • editor.helpers.linkedStyles.getLinkedStyleFormatting(styleId) — read a style's current run formatting.
    • editor.helpers.linkedStyles.getEffectiveFormattingAtSelection() — read the run formatting at the cursor (the source for "update to match").
  • formatting shape: { bold, italic, underline, fontSizePt, fontFamily, colorHex }.

Rendering

A redefinition doesn't change the document, so both render paths are refreshed explicitly on every call:

  • ProseMirror mode — a linked-styles plugin meta signal regenerates decorations from the updated styles.
  • Layout/presentation modePresentationEditor.refreshLinkedStyles() clears the FlowBlockCache (keyed on node identity) and re-lays out, mirroring other non-edit re-render paths (e.g. setShowBookmarks).

UI

The styles dropdown gains a per-row "Update to match" (✎) action. Clicking the style name still just applies the style as before.

Tests

  • Pure mappers (style-formatting.test.js) — formatting ⇄ OOXML conversions.
  • Integration (update-linked-style.test.js) — engine, command, read helpers, repaint-on-every-redefinition (not just the first), and word/styles.xml + translatedLinkedStyles export round-trip.
  • Dropdown emit (LinkedStyle.test.js).

pnpm test (linked-styles suites) green · pnpm check:types clean · eslint clean.

Notes

  • Scope is run-level formatting; paragraph-level layout (spacing/indent) round-trips to export, but live layout-repaint for those is a follow-up.
  • Pure shape conversions are isolated in style-formatting.js (no editor/DOM deps).

Add a supported way to redefine a named paragraph style's run-level look
(font family, size, weight, color) so it updates live and survives .docx
export — the editor equivalent of Google Docs' "Update Heading 1 to match".

- editor.commands.updateLinkedStyle(styleId, formatting) rewrites the style
  across all three converter representations (linkedStyles definition,
  translatedLinkedStyles, word/styles.xml) under one snapshot/rollback; never
  throws.
- Read helpers: getLinkedStyleFormatting(styleId) and
  getEffectiveFormattingAtSelection().
- Repaint on every redefinition in both render modes — a linked-styles plugin
  meta signal (ProseMirror decorations) plus PresentationEditor.refreshLinkedStyles()
  (clears the FlowBlockCache and re-lays out the painted view).
- Styles dropdown gains a per-row "Update to match" (pencil) action.

Pure shape conversions are isolated in style-formatting.js. Covered by unit
tests (pure mappers) and integration tests (engine, command, helpers, repaint,
and export round-trip).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e1fd20066

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread packages/super-editor/src/editors/v1/extensions/linked-styles/style-formatting.js Outdated
…lean-off

Address review feedback on "Update to match":

- readEffectiveRunFormatting now resolves the selection paragraph's named style
  (merged over its basedOn parent) as the base and layers direct marks on top,
  instead of reading marks only. Previously, formatting that came purely from a
  named style (the common .docx case) was captured as empty and wiped the style.
- Cleared booleans (bold/italic/underline) are now stored as explicit off
  ({ value: '0' } in definition styles, w:val="0"/w:u w:val="none" in OOXML)
  rather than deleting the key, so a redefined style overrides an inherited
  basedOn value instead of falling back to it. definitionStylesToFormatting
  reads explicit-off back as false.
@caio-pizzol

caio-pizzol commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Thanks @shri-scale. This is a useful feature and I agree it fills a real gap.

I do not think we should merge it in this shape though. The change adds a new editor.commands.updateLinkedStyle(...) API, but new document changes should go through the Document API (editor.doc.*). editor.commands.* is the older path we are moving away from.

Could you move this into the Document API styles area instead?

A possible shape:

editor.doc.styles.apply({
  target: {
    scope: 'style',
    type: 'paragraph',
    styleId,
    channel: 'run',
  },
  patch: { bold, italic, underline, fontSize, fontFamily, color },
});

The feature, UI, tests, and style-reading logic are worth keeping. The main request is to put the style update behind editor.doc.* so it works through the same public API as the rest of our document changes.

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