Skip to content

fix(text-editor): keep texteditor typography separate from text forma… - #8175

Draft
ibutakova wants to merge 1 commit into
masterfrom
FE-7767-separate-typography-from-formatting-in-texteditor
Draft

ibutakova wants to merge 1 commit into
masterfrom
FE-7767-separate-typography-from-formatting-in-texteditor

Conversation

@ibutakova

@ibutakova ibutakova commented Sep 14, 2026

Copy link
Copy Markdown
Contributor

Proposed behaviour

Separates typography from user formatting in Text Editor HTML exports, making save/import round trips reliable.
StyledSpanNode now exports user formatting with semantic wrappers:
<strong><span data-carbon-base-weight="500" style="font-size: 21px; line-height: 26.25px">Bold subtitle</span></strong>

StyledSpanNode.exportDOM() no longer writes effective bold, italic, or underline styles directly to the <span>. User-applied formatting is represented by surrounding strong, em, and u wrappers. The span keeps its base size and line height; for bold content, its base weight is stored in data-carbon-base-weight so <strong> can
control the rendered weight.

StyledSpanNode.importDOM()'s legacy fallback handles older Carbon and foreign HTML that encoded bold as a literal font-weight on the span. When the weight does not match a 700 typography preset, it recovers the matching preset weight from the size and line height instead of always defaulting to 400. This preserves legacy bold headings and subtitles more accurately after import.

Solution does:

  • Preserves bold paragraph, subtitle, heading, and title typography through export/import.
  • Preserves custom 700 / 17px / 23px typography without incorrectly converting it to bold paragraph formatting.
  • Recovers the correct base weight from legacy literal-700 HTML using its size and line height.
  • Exports italic and underline with semantic em / u wrappers.
  • Keeps htmlStringWithInlineStyles portable by adding equivalent inline styles for semantic formatting tags.

For HTML stored and later re-imported, data-carbon-base-weight is retained as part of the exported content.

Current behaviour

StyledSpanNode currently writes bold formatting in two places:

  • font-weight: 700 on the span
  • a surrounding strong element
    This makes HTML import difficult because font-weight: 700 could mean either a naturally bold typography style, such as a title, or bold formatting applied by the user.

Checklist

  • Commits follow our style guide
  • Related issues linked in commit messages if required
  • Screenshots are included in the PR if useful
  • All themes are supported if required
  • Unit tests added or updated if required
  • Playwright automation tests added or updated if required
  • Storybook added or updated if required
  • Translations added or updated (including creating or amending translation keys table in storybook) if required
  • Typescript d.ts file added or updated if required
  • Related docs have been updated if required

QA

  • Tested in provided StackBlitz sandbox/Storybook
  • Add new Playwright test coverage if required
  • Carbon implementation matches Design System/designs
  • UI Tests GitHub check reviewed if required

Additional context

Testing instructions

  1. Bold on a paragraph
  • Type plain paragraph text, select it, apply Bold.
  • Export/copy HTML → span should show normal (non-bold) weight, wrapped in strong.
  • Re-import that HTML → text is still bold.
  1. Bold on a Title
  • Apply “Title” typography (no bold toggle).
  • Export HTML → span shows font-weight: 700, no strong wrapper.
  • Re-import → still styled as Title, not marked as user-bold.
  1. Explicitly bold Title
  • Apply “Title” typography and toggle Bold.
  • Export → wrapped in strong, span still 700.
  • Re-import → Title typography and bold both preserved.
  1. Italic / Underline alone
  • Apply only Italic → export wraps in em only.
  • Apply only Underline → export wraps in u only.
  • Re-import each → formatting preserved.
  1. Combined bold + italic + underline
  • Apply all three → export nests u``em``strong``span.
  • Re-import → all three formats still active.
  1. Backward compatibility (critical)
    Paste/import HTML exported by an older Carbon version (or any HTML with font-weight:700 directly on a span, no strong) → text should still import as bold correctly.

Copilot AI 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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Copilot AI 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.

🟡 Changes recommended

Blocking import/export compatibility issues and regression-test gaps remain.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

src/components/text-editor/internal/nodes/styled-span.node.ts:211

  • issue (blocking): This updated fallback also handles legacy fontWeight === "bold" markup, but every added legacy test uses the numeric "700" form. Add a focused keyword-form import test so the changed size/line-height recovery is covered for both accepted inputs.
              // No preset matches 700 at this size/line-height, so 700 was
              // likely applied formatting, not the base weight. Recover the
              // true base weight from size + line-height, falling back to
              // paragraph weight if nothing matches.
              const matchedBySizeOnly = Object.values(typographyMap).find(
                (t) => t.size === fontSize && t.lineHeight === lineHeight,
              );
              fontWeight = matchedBySizeOnly ? matchedBySizeOnly.weight : "400";

src/components/text-editor/internal/nodes/styled-span.node.ts:212

  • issue (blocking): font-weight: bold enters this fallback even when the size/line-height is the title preset, because the preset check only matches the literal "700". As a result, equivalent legacy/foreign markup such as <span style="font-weight: bold; font-size: 24px; line-height: 30px"> is reconstructed as a title with bold format enabled, unlike the same markup using 700. Normalize bold to 700 before the preset check (and add a regression case) so a natural title is not marked as user-applied bold.
              const matchedBySizeOnly = Object.values(typographyMap).find(
                (t) => t.size === fontSize && t.lineHeight === lineHeight,
              );
              fontWeight = matchedBySizeOnly ? matchedBySizeOnly.weight : "400";
              shouldApplyBoldFormat = !domNode.closest("strong, b");
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/components/text-editor/__internal__/__nodes__/styled-span.node.ts Outdated
@DipperTheDan
DipperTheDan self-requested a review September 16, 2026 15:30
@ibutakova
ibutakova force-pushed the FE-7767-separate-typography-from-formatting-in-texteditor branch from 8869468 to ac53dea Compare September 17, 2026 10:34
@ibutakova
ibutakova requested a lite review from Copilot September 17, 2026 10:35

Copilot AI 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.

🟡 Changes recommended

Two moderate blocking findings remain in typography import and serialization compatibility.

Get a fresh assessment by requesting another Copilot review.

Review details

Suppressed comments (2)

src/components/text-editor/internal/nodes/styled-span.node.ts:167

  • issue: (blocking): Adding this marker to every exported span changes the existing HTML serialization contract. The current exact Playwright assertion at src/components/text-editor/text-editor.pw.tsx:477-479 and the inline-style assertion at src/components/text-editor/text-editor.test.tsx:787-789 will fail because data-carbon-styled-span is inserted into the <span>. Either update those affected contract tests and document the new attribute, or restrict the marker to the ambiguous custom-700 cases so ordinary exports remain unchanged.
    // marks element as a current carbon export.
    element.setAttribute(CARBON_STYLED_SPAN_ATTRIBUTE, "true");

src/components/text-editor/internal/nodes/styled-span.node.ts:166

  • nitpick: (non-blocking): This new comment should use a sentence-style comment and capitalize the Carbon name.
    // marks element as a current carbon export.
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

@ibutakova
ibutakova force-pushed the FE-7767-separate-typography-from-formatting-in-texteditor branch from ac53dea to 69c079b Compare September 17, 2026 10:53
@ibutakova
ibutakova requested a lite review from Copilot September 17, 2026 10:54

Copilot AI 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.

🟡 Changes recommended

Exported bold formatting is incorrect when the span retains a base weight below 700.

Get a fresh assessment by requesting another Copilot review.

Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/components/text-editor/__internal__/__nodes__/styled-span.node.ts Outdated
@ibutakova
ibutakova force-pushed the FE-7767-separate-typography-from-formatting-in-texteditor branch from 69c079b to 983d1b6 Compare September 17, 2026 13:15
@ibutakova
ibutakova requested a lite review from Copilot September 17, 2026 13:18

Copilot AI 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.

🟡 Changes recommended

Blocking issues remain in explicit bold-title export and legacy font-weight: bold import handling.

Get a fresh assessment by requesting another Copilot review.

Warning

  • Copilot's review of this pull request may be incomplete because some of the changed files are excluded by your Copilot content exclusion settings. See Excluding content from Copilot for details.
Review details

Files excluded by content exclusion policy (1)

  • skills/carbon-react/components/text-editor.md

Suppressed comments (3)

src/components/text-editor/internal/nodes/styled-span.node.ts:220

  • issue: (blocking): When legacy or foreign HTML uses the CSS keyword font-weight: bold with title dimensions (24px/30px), matchesTypography is true, so this branch leaves fontWeight as "bold". getTypographyKey() only recognizes "700", so the imported node falls back to paragraph typography and loses the title style. Normalize the keyword before the match and add a regression test.
          if (
            !isCurrentCarbonExport &&
            (fontWeight === "700" || fontWeight === "bold")
          ) {

src/components/text-editor/internal/nodes/styled-span.node.ts:163

  • issue: (blocking): The PR's explicit-bold-title requirement says the exported span retains its base font-weight: 700, but this condition suppresses fontWeight for every bold node. The new test consequently asserts the opposite of that requirement. Keep the 700 base weight on the span while still omitting non-700 base weights so the strong wrapper can render those cases.
    if (!isBold) {
      element.style.fontWeight = this.__fontWeight;
    }

src/components/text-editor/internal/utils/helpers.ts:24

  • issue: (non-blocking): The new B and I tag mappings are not covered by the parameterized test, which only exercises strong, em, and u. Regressions in the aliases could therefore pass CI; add b and i cases to the same test.
  STRONG: "font-weight: bold;",
  B: "font-weight: bold;",
  EM: "font-style: italic;",
  I: "font-style: italic;",
  U: "text-decoration: underline;",
  • Files reviewed: 6/6 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/components/text-editor/__internal__/__nodes__/styled-span.node.ts Outdated
@ibutakova
ibutakova force-pushed the FE-7767-separate-typography-from-formatting-in-texteditor branch from 08f7a47 to 9f7ae71 Compare September 17, 2026 13:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Development

Successfully merging this pull request may close these issues.

2 participants