Skip to content

fix(plugin-formula): 修复公式绝对值分隔符长度异常#882

Merged
cycleccc merged 1 commit into
masterfrom
fix/plugin-formula-issue-881
May 25, 2026
Merged

fix(plugin-formula): 修复公式绝对值分隔符长度异常#882
cycleccc merged 1 commit into
masterfrom
fix/plugin-formula-issue-881

Conversation

@cycleccc

@cycleccc cycleccc commented May 25, 2026

Copy link
Copy Markdown
Collaborator

关联 issue

变更说明

  • plugin-formula 自定义元素渲染从 output: 'mathml' 调整为 output: 'htmlAndMathml',避免绝对值分隔符在编辑态回显过短
  • 移除公式卡片的 Shadow DOM 容器,改为 light DOM 挂载,确保 KaTeX HTML 渲染样式可正确生效
  • 新增回归测试,覆盖 \left|...\right| 场景并校验存在可拉伸分隔符节点
  • README(中/英)补充 KaTeX 样式引入说明
  • 添加 changeset(patch)

验证

  • pnpm test packages/plugin-formula/__tests__/module.test.ts packages/plugin-formula/__tests__/register-custom-elem.test.ts
  • pnpm --filter @wangeditor-next/plugin-formula build
  • pnpm typecheck

说明

  • 本地用于验收的 apps/demo-reactpnpm-lock.yaml 临时改动未包含在本 PR 内。

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed incorrect rendering of absolute value delimiters in mathematical formulas.
  • Documentation

    • Updated installation guide to include KaTeX CSS import (katex.min.css) before plugin registration.
    • Added clarification that the KaTeX stylesheet must be loaded on the page for formulas to render properly; missing styles result in unformatted text display.

Review Change Stack

@changeset-bot

changeset-bot Bot commented May 25, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 038f733

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

This PR includes changesets to release 1 package
Name Type
@wangeditor-next/plugin-formula 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

@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR fixes inconsistent LaTeX formula rendering by refactoring the formula card custom element to lazily initialize its span and switch KaTeX output to htmlAndMathml. Documentation is updated to require CSS imports, and a test validates the rendering behavior.

Changes

KaTeX Formula Rendering Fix

Layer / File(s) Summary
Formula card custom element refactoring
packages/plugin-formula/src/register-custom-elem/index.ts
The span field is now nullable and created lazily via ensureSpan() instead of in the constructor. KaTeX rendering switches from output: 'mathml' to output: 'htmlAndMathml' to correctly size stretchy absolute value delimiters.
Formula rendering validation test
packages/plugin-formula/__tests__/register-custom-elem.test.ts
New test creates w-e-formula-card, sets LaTeX content, and asserts that KaTeX renders HTML with proper stretchy delimiter styling (.delimsizing.mult), no shadow root, and correct cleanup.
Documentation and release notes
.changeset/four-owls-type.md, packages/plugin-formula/README.md, packages/plugin-formula/README-en.md
README setup snippets and changeset document the patch fix, explicitly showing import 'katex/dist/katex.min.css' before module registration and warning that formulas render unformatted without the stylesheet.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • wangeditor-next/wangEditor-next#393: Adds MathML output via output: 'mathml' to register-custom-elem/index.ts; this PR switches to output: 'htmlAndMathml' for improved delimiter rendering.
  • wangeditor-next/wangEditor-next#365: Updates KaTeX CSS loading in register-custom-elem/index.ts via injected <link>; this PR requires explicit CSS import in user code and refactors span initialization.

Poem

🐰 A formula fix with stretchy grace,
Delimiters now find their proper place,
htmlAndMathml sets the stage just right,
Lazy loading, CSS insight,
Math renders tall and bold and bright!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title in Chinese summarizes the fix: formula absolute value delimiter length abnormality in plugin-formula. It directly relates to the main change in the changeset.
Description check ✅ Passed The PR description in Chinese covers all key sections: related issue, changes overview, verification steps, and explanatory notes. However, it does not strictly follow the template provided (which appears to be in English and includes specific sections like Implementation Approach, Testing Done, Verification Steps, Checklist, and Related Issues). The description is meaningful and complete in its own right.
Linked Issues check ✅ Passed The PR fully addresses issue #881 by fixing the LaTeX formula absolute value delimiter rendering. Changes include switching output from 'mathml' to 'htmlAndMathml', removing Shadow DOM, adding regression tests for \left|...\right|, and updating documentation with KaTeX stylesheet requirements.
Out of Scope Changes check ✅ Passed All changes are directly related to fixing the formula rendering issue and its documentation. The changeset, test file, source code modifications, and README updates are all within the scope of resolving issue #881.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/plugin-formula-issue-881

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

packages/plugin-formula/__tests__/register-custom-elem.test.ts

ESLint skipped: missing config or dependency (missing-dependency). The ESLint configuration references a package that is not available in the sandbox.

packages/plugin-formula/src/register-custom-elem/index.ts

ESLint skipped: the ESLint configuration for this file references a package that is not available in the sandbox.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@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: 038f733d06

ℹ️ About Codex in GitHub

Your team has set up Codex to 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 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

const span = document.createElement('span')

span.style.display = 'inline-block'
this.appendChild(span)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve clipboard text by isolating rendered KaTeX DOM

Appending the KaTeX render container into the custom element’s light DOM makes setFragmentData/getPlainText in core traverse KaTeX’s internal HTML+MathML nodes when users copy content, so copying a formula now yields duplicated/garbled plain text (hidden MathML annotation plus visual HTML text) in external paste targets. This regression appears when selecting formula nodes and using copy/cut; the previous Shadow DOM implementation avoided leaking these internal nodes into clipboard extraction.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/plugin-formula/__tests__/register-custom-elem.test.ts`:
- Around line 3-18: Add round-trip serialization tests for the plugin-formula
style change: extend the existing test for the custom element 'w-e-formula-card'
to exercise render -> toHtml -> parseHtml and setHtml(getHtml()) /
toHtml(parseHtml(html)) paths across both inline and class style modes and for
default and custom configuration values; specifically, invoke the module's
render (or equivalent render helper), call toHtml() on the editor state,
parseHtml(...) to rehydrate DOM, and assert that parsed output/rendered DOM
still contains '.katex', '.katex-html' and '.delimsizing.mult' for each
combination (inline/class × default/custom) and for both round-trip flows.
Ensure you reuse the existing element creation (elem =
document.createElement('w-e-formula-card')) and attribute handling
(setAttribute('data-value', ...)) while adding assertions after
setHtml(getHtml()) and toHtml(parseHtml(html)) to fully cover the required
matrix.
- Around line 11-17: The test currently calls elem.remove() after assertions
which will be skipped if an assertion throws; wrap the assertions (the block
that checks elem.shadowRoot and the various elem.querySelector(...)
expectations) in a try/finally and move elem.remove() into the finally so
cleanup always runs; locate the test that creates the element (variable elem) in
packages/plugin-formula/__tests__/register-custom-elem.test.ts and ensure
elem.remove() is executed in the finally block surrounding those expectations.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e15596ba-8936-4a1a-a585-1530e8eea88b

📥 Commits

Reviewing files that changed from the base of the PR and between 35ca828 and 038f733.

📒 Files selected for processing (5)
  • .changeset/four-owls-type.md
  • packages/plugin-formula/README-en.md
  • packages/plugin-formula/README.md
  • packages/plugin-formula/__tests__/register-custom-elem.test.ts
  • packages/plugin-formula/src/register-custom-elem/index.ts

Comment on lines +3 to +18
describe('plugin-formula custom element', () => {
it('renders htmlAndMathml output and keeps stretchy absolute delimiters', () => {
const elem = document.createElement('w-e-formula-card')
const formula = String.raw`\left|-2\frac{4}{7}\right|`

elem.setAttribute('data-value', formula)
document.body.appendChild(elem)

expect(elem.shadowRoot).toBeNull()
expect(elem.querySelector('.katex')).not.toBeNull()
expect(elem.querySelector('.katex-html')).not.toBeNull()
expect(elem.querySelector('.katex-html .delimsizing.mult')).not.toBeNull()

elem.remove()
})
})

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.

🛠️ Refactor suggestion | 🟠 Major | 🏗️ Heavy lift

Add the required round-trip serialization coverage for this style-related change.

This adds a useful DOM regression test, but it still misses the required round-trip matrix (render/toHtml/parseHtml, inline/class style modes, default/custom config, and setHtml(getHtml()) / toHtml(parseHtml(html))) for serialization/style changes.

As per coding guidelines, "**/*.test.{ts,tsx}: Test round-trip export/import for inline and class style modes, default and custom configuration values, across render/toHtml/parseHtml paths, and with setHtml(getHtml())/toHtml(parseHtml(html)) when modifying serialization or styles".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/plugin-formula/__tests__/register-custom-elem.test.ts` around lines
3 - 18, Add round-trip serialization tests for the plugin-formula style change:
extend the existing test for the custom element 'w-e-formula-card' to exercise
render -> toHtml -> parseHtml and setHtml(getHtml()) / toHtml(parseHtml(html))
paths across both inline and class style modes and for default and custom
configuration values; specifically, invoke the module's render (or equivalent
render helper), call toHtml() on the editor state, parseHtml(...) to rehydrate
DOM, and assert that parsed output/rendered DOM still contains '.katex',
'.katex-html' and '.delimsizing.mult' for each combination (inline/class ×
default/custom) and for both round-trip flows. Ensure you reuse the existing
element creation (elem = document.createElement('w-e-formula-card')) and
attribute handling (setAttribute('data-value', ...)) while adding assertions
after setHtml(getHtml()) and toHtml(parseHtml(html)) to fully cover the required
matrix.

Comment on lines +11 to +17
expect(elem.shadowRoot).toBeNull()
expect(elem.querySelector('.katex')).not.toBeNull()
expect(elem.querySelector('.katex-html')).not.toBeNull()
expect(elem.querySelector('.katex-html .delimsizing.mult')).not.toBeNull()

elem.remove()
})

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.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Ensure cleanup runs even when an assertion fails.

elem.remove() should be in finally to avoid leaking DOM state on failed assertions.

Suggested change
 it('renders htmlAndMathml output and keeps stretchy absolute delimiters', () => {
   const elem = document.createElement('w-e-formula-card')
   const formula = String.raw`\left|-2\frac{4}{7}\right|`
 
-  elem.setAttribute('data-value', formula)
-  document.body.appendChild(elem)
-
-  expect(elem.shadowRoot).toBeNull()
-  expect(elem.querySelector('.katex')).not.toBeNull()
-  expect(elem.querySelector('.katex-html')).not.toBeNull()
-  expect(elem.querySelector('.katex-html .delimsizing.mult')).not.toBeNull()
-
-  elem.remove()
+  try {
+    elem.setAttribute('data-value', formula)
+    document.body.appendChild(elem)
+
+    expect(elem.shadowRoot).toBeNull()
+    expect(elem.querySelector('.katex')).not.toBeNull()
+    expect(elem.querySelector('.katex-html')).not.toBeNull()
+    expect(elem.querySelector('.katex-html .delimsizing.mult')).not.toBeNull()
+  } finally {
+    elem.remove()
+  }
 })
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/plugin-formula/__tests__/register-custom-elem.test.ts` around lines
11 - 17, The test currently calls elem.remove() after assertions which will be
skipped if an assertion throws; wrap the assertions (the block that checks
elem.shadowRoot and the various elem.querySelector(...) expectations) in a
try/finally and move elem.remove() into the finally so cleanup always runs;
locate the test that creates the element (variable elem) in
packages/plugin-formula/__tests__/register-custom-elem.test.ts and ensure
elem.remove() is executed in the finally block surrounding those expectations.

@cycleccc cycleccc merged commit dc64615 into master May 25, 2026
10 checks passed
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.

latex公式在富文本中回显的和页面上回显的不一致

1 participant