Skip to content

[ZAMB-257] Add MathJax rich-text support - #559

Open
ocorona92 wants to merge 1 commit into
v0from
codex/zamb-257-mathjax-rich-text
Open

ocorona92 wants to merge 1 commit into
v0from
codex/zamb-257-mathjax-rich-text

Conversation

@ocorona92

Copy link
Copy Markdown
Collaborator

Summary

  • add an official MathJax plugin for the rich-text editor
  • preserve inline and display delimiters across Markdown and Rich Text modes
  • support live typing, Markdown paste, escaped dollars, and code spans
  • delegate typesetting and cleanup to host-provided callbacks

Context

Enterprise editors do not have access to the optional Markdown preview mode, so MathJax needs to render directly in Rich Text. The StackOverflow integration will be submitted separately after this editor API is reviewed.

Validation

  • npm run test:unit -- --runInBand --testPathIgnorePatterns=/node_modules/ \\.e2e\\.test /dist/ — 51 suites passed, 1,130 tests passed
  • npm run lint — passed with two unrelated existing test warnings
  • npm run prepublishOnly — Webpack and TypeScript passed
  • manually verified typing, multiline paste, escaped dollars, code spans, mode round-tripping, and persistence on stackenterprise.local with MathJax 3.2.2

@changeset-bot

changeset-bot Bot commented Oct 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 08d5d64

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

This PR includes changesets to release 1 package
Name Type
@stackoverflow/stacks-editor Minor

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

@netlify

netlify Bot commented Oct 18, 2026

Copy link
Copy Markdown

✅ Deploy Preview for stacks-editor ready!

Name Link
🔨 Latest commit 08d5d64
🔍 Latest deploy log https://app.netlify.com/projects/stacks-editor/deploys/6ad54b2efdc53a3f9756b37c
😎 Deploy Preview https://deploy-preview-559--stacks-editor.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@ocorona92
ocorona92 marked this pull request as ready for review October 20, 2026 15:14
@ocorona92
ocorona92 requested a review from a team as a code owner October 20, 2026 15:14

@dancormier dancormier left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey @ocorona92, thanks for the PR. I hit a few data-loss and editing issues while testing locally that need fixing before this merges. Details and GIFs are inline.

Comment on lines +163 to +170
const blockStart = paragraph.before();
const blockEnd = paragraph.after();
const mathNode = nodeType.create({
source,
openDelimiter: open,
closeDelimiter: close,
});
const tr = state.tr.replaceWith(blockStart, blockEnd, mathNode);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Completing display math in the middle of a paragraph deletes everything after the cursor. Can we preserve that text, or only convert when the formula fills the whole paragraph?

Image

To reproduce

  1. In an empty Rich Text editor, type $$x$ KEEP THIS character by character
  2. Place the cursor immediately before the space preceding KEEP THIS
  3. Type one more $ to complete $$x$$
  4. Note that the formula renders, but KEEP THIS is deleted

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copying a paragraph with math into a plain-text editor drops the formula entirely. These nodes need clipboard text, such as leafText, so copying preserves the delimited source. Escaped-dollar nodes need this too.

Image

To reproduce

  1. In an empty Rich Text editor, type Before $x^2$ after
  2. Confirm that the formula renders
  3. Select and copy the entire paragraph
  4. Paste it into a plain-text editor
  5. Note that the pasted text is Before after, with the formula missing

...mathJaxMarkdownParser,
}
);
const parsed = parser.parse(text);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pasting ~~text~~ or a Markdown table throws an unsupported-token error, even without any math. Can we use the editor’s configured parser and let unsupported content fall through to normal paste handling?

Image Image

To reproduce

  1. Open the browser console on the editor demo page
  2. Run this:
document.body.insertAdjacentHTML(
    "afterbegin",
    '<p id="paste-fixture"><strong>Bold phrase</strong> and <a href="https://example.com/">linked phrase</a> with $x$.</p>'
);
  1. Select and copy the entire line added above the editor, including $x$
  2. Paste it into an empty Rich Text editor using normal paste, not “paste as plain text”
  3. Note that the formula renders, but the bold formatting and hyperlink are lost

Comment on lines +219 to +234
appendTransaction: (transactions, _, state) => {
if (
!transactions.some((transaction) => transaction.docChanged) ||
transactions.some((transaction) =>
state.plugins.some(
(plugin) =>
(
plugin.spec as {
isInputRules?: boolean;
}
).isInputRules && transaction.getMeta(plugin)
)
)
) {
return null;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Backspace immediately after typing $x$ doesn’t undo the conversion. This hook turns the restored text straight back into math. Can we exclude input-rule undo transactions here?

Image

To reproduce

  1. In an empty Rich Text editor, type $x$ character by character
  2. Once the formula renders, immediately press Backspace without moving the cursor
  3. Note that the formula remains rendered instead of reverting to literal $x$

Comment on lines +46 to +51
view.dispatch(
view.state.tr.replaceSelection(
Slice.maxOpen(parsed.content)
)
);
return true;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pasting rich text containing $x$ strips bold formatting and links; images are lost too. Can we preserve the supplied rich-text slice instead of rebuilding the entire paste from plain text?

Image

To reproduce

  1. Open the console
  2. Paste this:
document.body.insertAdjacentHTML(
    "afterbegin",
    '<p id="paste-fixture"><strong>Bold phrase</strong> and <a href="https://example.com/">linked phrase</a> with $x$.</p>'
);
  1. Copy the entire line added above the editor
  2. Paste it into the editor
  3. Note that bolding and link are missing


/** Build a non-empty, single-line capture that stops at the closing delimiter. */
function sourceCapture(close: string): string {
return `((?:(?!${escapeRegExp(close)})[^\\n])+?)`;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Typing $x+\$y$ never converts, but entering the same source in Markdown mode renders correctly. This regex stops at escaped dollars too—can we use escape-aware delimiter matching here?

Image

To reproduce

  1. In an empty Rich Text editor, type $x+\$y$ character by character
  2. Note that it stays as literal text instead of rendering
  3. Switch to Markdown mode
  4. Replace the contents with the exact same source: $x+\$y$
  5. Switch back to Rich Text mode
  6. Note that the formula now renders—the typing and Markdown parsing paths handle the same source differently

This branch has not been deployed

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants