Skip to content

fix(x-markdown): support animation inside custom components - #1974

Open
wryyyds7 wants to merge 2 commits into
ant-design:mainfrom
wryyyds7:fix/x-markdown-animate-inside-components
Open

fix(x-markdown): support animation inside custom components#1974
wryyyds7 wants to merge 2 commits into
ant-design:mainfrom
wryyyds7:fix/x-markdown-animate-inside-components

Conversation

@wryyyds7

@wryyyds7 wryyyds7 commented Jul 15, 2026

Copy link
Copy Markdown

Close #1950

问题

XMarkdown 的 streaming.enableAnimation 开启后,当文字节点的父节点是自定义组件(通过 components 属性传入)时,动画会被跳过,文字不出现淡入效果。

修改内容
interface.ts:在 StreamingOption 中新增 animateInsideComponents?: boolean 开关,默认 false(向后兼容)
Renderer.ts:修改 shouldReplaceText 判断条件为 (!isParentCustomComponent || animateInsideComponents)
Renderer.test.ts:新增 5 个单测
使用方式

<XMarkdown
content={content}
streaming={{
enableAnimation: true,
animateInsideComponents: true,
animationConfig: { fadeDuration: 600, easing: 'ease-in-out' },
}}
components={{
p: ({ children, ...rest }) => <p {...rest}>{children}

,
}}
/>
根因在 Renderer.ts 中:

const shouldReplaceText = enableAnimation && isValidTextNode && !isParentCustomComponent;


<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

* **新功能**
  * 新增流式渲染配置 `animateInsideComponents`,可控制自定义组件内部文本是否启用淡入动画。
  * 当开启 `enableAnimation` 时,自定义组件内外文本可按配置分别触发动画。
* **Bug Fixes**
  * 修正自定义组件内部文本的动画触发逻辑:未启用 `animateInsideComponents` 时不动画。
* **测试**
  * 增加对组件内外与嵌套场景下动画触发与调用次数的覆盖用例。
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

- Add  option to StreamingOption interface
- Modify Renderer.ts shouldReplaceText condition to allow AnimationText
  inside custom components when animateInsideComponents is enabled
- Add 5 unit tests in Renderer.test.ts

Close ant-design#1950
@dosubot dosubot Bot added the javascript Pull requests that update Javascript code label Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 69760aca-44eb-4c84-97eb-a6163ff6e368

📥 Commits

Reviewing files that changed from the base of the PR and between 28baa87 and c4397f5.

📒 Files selected for processing (1)
  • packages/x-markdown/src/XMarkdown/core/Renderer.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/x-markdown/src/XMarkdown/core/Renderer.ts

📝 Walkthrough

Walkthrough

新增 animateInsideComponents 流式配置,使自定义组件内部文本可按配置启用 AnimationText,并补充外部文本、嵌套组件及禁用动画场景的测试。

Changes

组件内文字动画

Layer / File(s) Summary
流式动画配置契约
packages/x-markdown/src/XMarkdown/interface.ts
StreamingOption 新增可选的 animateInsideComponents 配置项及文档注释。
组件文本动画渲染行为
packages/x-markdown/src/XMarkdown/core/Renderer.ts, packages/x-markdown/src/XMarkdown/__tests__/Renderer.test.ts
Renderer 根据配置决定是否为自定义组件内部文本创建 AnimationText,并覆盖相关组合与嵌套组件测试。

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested reviewers: div627

Poem

小兔挥爪改开关,
组件文字跳跃亮。
内外文本齐起舞,
嵌套也能数得清。
动画关闭便安静。

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 核心开关和单测已补齐,但未见 contentRender 打字机示例,未完全满足 issue 验收。 补充 contentRender + 打字机效果的示例或文档,并确认示例可直接演示该开关生效。
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了在自定义组件内支持动画的主要改动。
Out of Scope Changes check ✅ Passed 改动主要围绕动画开关、渲染逻辑和测试,未见明显无关的越界修改。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces a new animateInsideComponents configuration option to allow text fade-in animations inside custom components. It updates the Renderer logic to respect this option and adds comprehensive unit tests to verify its behavior. The review feedback suggests optimizing the text replacement check in Renderer.ts by lazily evaluating the parent tag check only when animations are enabled, and using Object.prototype.hasOwnProperty.call to prevent potential prototype pollution issues.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +183 to +185
const parentTagName = (domNode.parent as Element)?.name;
const isParentCustomComponent = parentTagName && this.options.components?.[parentTagName];
const shouldReplaceText = enableAnimation && isValidTextNode && !isParentCustomComponent;
const shouldReplaceText = enableAnimation && isValidTextNode && (!isParentCustomComponent || animateInsideComponents);

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.

medium

性能与安全性优化

问题分析:

  1. 性能开销: 目前的实现中,对于每个解析的 DOM 节点,无论 enableAnimation 是否开启,或者当前节点是否为有效的文本节点 (isValidTextNode),都会执行 parentTagName 的获取以及在 this.options.components 中的查找操作。由于大部分用户默认不开启动画,这会带来不必要的性能开销。
  2. 原型链污染/安全隐患: 直接使用 this.options.components?.[parentTagName] 进行查找时,如果 parentTagName 刚好是 Object.prototype 上的属性(例如 toStringvalueOfhasOwnProperty 等),会导致非预期的匹配。

改进建议:
建议将这部分逻辑放入 if (enableAnimation && isValidTextNode) 条件分支中进行惰性求值(Short-circuiting),并使用 Object.prototype.hasOwnProperty.call 安全地检查自定义组件,从而同时提升性能和安全性。

Suggested change
const parentTagName = (domNode.parent as Element)?.name;
const isParentCustomComponent = parentTagName && this.options.components?.[parentTagName];
const shouldReplaceText = enableAnimation && isValidTextNode && !isParentCustomComponent;
const shouldReplaceText = enableAnimation && isValidTextNode && (!isParentCustomComponent || animateInsideComponents);
let shouldReplaceText = false;
if (enableAnimation && isValidTextNode) {
const parentTagName = (domNode.parent as Element)?.name;
const isParentCustomComponent =
parentTagName &&
Object.prototype.hasOwnProperty.call(this.options.components || {}, parentTagName);
shouldReplaceText = !isParentCustomComponent || !!animateInsideComponents;
}

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.

@wryyyds7

Copy link
Copy Markdown
Author

#1950

Address gemini-code-assist review feedback:
- Move parentTagName/isParentCustomComponent into if block for lazy evaluation
- Use Object.prototype.hasOwnProperty.call for safe property lookup
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

javascript Pull requests that update Javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Good First Issue] XMarkdown contentRender 自定义渲染支持打字机效果

2 participants