feat(x-markdown): support animation inside custom components - #2022
Conversation
Add animateInsideComponents option to StreamingOption interface. When enabled, text nodes inside custom components (contentRender) also get the AnimationText typewriter effect. - Add animateInsideComponents boolean to StreamingOption - Modify shouldReplaceText logic in Renderer.ts - Add 6 unit tests covering on/off/default/nested scenarios - Add manual verification script and demo page Closes ant-design#1950 Co-Authored-By: Claude <noreply@anthropic.com>
|
Note Currently processing new changes in this PR. This may take a few minutes, please wait... ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (5)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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/x-markdown/demo.html`:
- Line 135: Update animationTimer and the animation flow around resetAll to
track every setTimeout return value rather than a single unused timer reference.
Add each timer ID to the collection, clear all stored timers and empty the
collection in resetAll, and ensure replaying or resetting prevents callbacks
from prior animations from appending output.
- Around line 97-104: 更新 renderSegment 及其调用方以接收 charDelay,并在 animate
字符循环中根据字符索引设置递增的 animationDelay,而不是固定为 0s;确保该延迟仅用于字符淡入,同时保留背景闪烁的现有延迟行为,使字符按顺序淡入。
In `@packages/x-markdown/manual-test.ts`:
- Around line 22-29: Update the manual test runner around test so it tracks the
number of failed cases when exceptions are caught, sets a non-zero process exit
status if any failures occurred, and suppresses the “All tests passed!” and
“logic is CORRECT” success summaries whenever failures exist.
In `@packages/x-markdown/src/XMarkdown/__tests__/Renderer.test.ts`:
- Around line 1642-1648: Update the AnimationText lookup expectations in
packages/x-markdown/src/XMarkdown/__tests__/Renderer.test.ts at lines 1642-1648
so the Before and After values include their preserved surrounding spaces:
“Before ” and “ After”. Apply the same expectation change at lines 1707-1713 for
Level1 and End: “Level1 ” and “ End”; leave the Inside expectation unchanged.
In `@packages/x-markdown/src/XMarkdown/core/Renderer.ts`:
- Around line 185-188: Update the text replacement logic in Renderer around
parentTagName and shouldReplaceText to detect whether any ancestor, not only the
direct parent, is a configured custom component. Propagate this context through
processChildren if needed, so nested elements remain non-animated when
animateInsideComponents is disabled while preserving animation when it is
enabled; add coverage for both cases with ordinary nested elements.
🪄 Autofix
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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4affa99b-e601-4b74-b1b9-a8a4c6be7976
📒 Files selected for processing (5)
packages/x-markdown/demo.htmlpackages/x-markdown/manual-test.tspackages/x-markdown/src/XMarkdown/__tests__/Renderer.test.tspackages/x-markdown/src/XMarkdown/core/Renderer.tspackages/x-markdown/src/XMarkdown/interface.ts
| // Simulate AnimationText component: split into individual chars with fade-in | ||
| if (animate) { | ||
| for (let i = 0; i < text.length; i++) { | ||
| const chunk = document.createElement('span'); | ||
| chunk.className = 'text-chunk'; | ||
| chunk.textContent = text[i]; | ||
| chunk.style.animationDelay = '0s'; | ||
| wrapper.appendChild(chunk); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
让字符淡入使用 charDelay。
每个字符都使用 animationDelay = '0s'。因此,同一文本片段中的字符会同时淡入。charDelay 只延迟背景闪烁,不会延迟淡入动画。
将 charDelay 传入 renderSegment,并为每个字符设置递增的 animationDelay。否则演示页面与“逐字淡入”的说明不一致。
Also applies to: 152-154
🤖 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/x-markdown/demo.html` around lines 97 - 104, 更新 renderSegment
及其调用方以接收 charDelay,并在 animate 字符循环中根据字符索引设置递增的 animationDelay,而不是固定为
0s;确保该延迟仅用于字符淡入,同时保留背景闪烁的现有延迟行为,使字符按顺序淡入。
| setTimeout(() => { el.style.background = origBg; }, 500); | ||
| } | ||
|
|
||
| let animationTimer = null; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
取消上一轮播放的所有定时器。
animationTimer 从未保存任何 setTimeout 返回值。用户在动画完成前点击“重置”或再次点击“播放”时,上一轮回调仍会向输出区域追加文本。
保存全部定时器 ID。resetAll 时清除这些定时器并清空集合。
Also applies to: 149-170, 176-180
🤖 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/x-markdown/demo.html` at line 135, Update animationTimer and the
animation flow around resetAll to track every setTimeout return value rather
than a single unused timer reference. Add each timer ID to the collection, clear
all stored timers and empty the collection in resetAll, and ensure replaying or
resetting prevents callbacks from prior animations from appending output.
| function test(name: string, fn: () => void) { | ||
| try { | ||
| fn(); | ||
| console.log(` ✅ ${name}`); | ||
| } catch (e) { | ||
| console.log(` ❌ ${name}: ${(e as Error).message}`); | ||
| } | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
失败时返回失败状态。
test 捕获错误后只输出日志。即使用例失败,脚本仍会输出 “All tests passed!” 和 “logic is CORRECT”,并以成功状态结束。
记录失败数量。存在失败时设置非零退出码,并且不要输出成功摘要。
Also applies to: 79-80
🤖 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/x-markdown/manual-test.ts` around lines 22 - 29, Update the manual
test runner around test so it tracks the number of failed cases when exceptions
are caught, sets a non-zero process exit status if any failures occurred, and
suppresses the “All tests passed!” and “logic is CORRECT” success summaries
whenever failures exist.
| const beforeCall = animationCalls.find((call) => call[1]?.text === 'Before'); | ||
| const afterCall = animationCalls.find((call) => call[1]?.text === 'After'); | ||
| const insideCall = animationCalls.find((call) => call[1]?.text === 'Inside'); | ||
|
|
||
| expect(beforeCall).toBeDefined(); | ||
| expect(afterCall).toBeDefined(); | ||
| expect(insideCall).toBeDefined(); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
修正包含空格的 AnimationText 断言。
Renderer 将未裁剪的 domNode.data 传给 AnimationText。这两个 HTML 字符串中的外围文本包含前导或尾随空格。当前断言会找不到对应调用。
packages/x-markdown/src/XMarkdown/__tests__/Renderer.test.ts#L1642-L1648: 将期望值改为Before和After。packages/x-markdown/src/XMarkdown/__tests__/Renderer.test.ts#L1707-L1713: 将期望值改为Level1和End。
📍 Affects 1 file
packages/x-markdown/src/XMarkdown/__tests__/Renderer.test.ts#L1642-L1648(this comment)packages/x-markdown/src/XMarkdown/__tests__/Renderer.test.ts#L1707-L1713
🤖 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/x-markdown/src/XMarkdown/__tests__/Renderer.test.ts` around lines
1642 - 1648, Update the AnimationText lookup expectations in
packages/x-markdown/src/XMarkdown/__tests__/Renderer.test.ts at lines 1642-1648
so the Before and After values include their preserved surrounding spaces:
“Before ” and “ After”. Apply the same expectation change at lines 1707-1713 for
Level1 and End: “Level1 ” and “ End”; leave the Inside expectation unchanged.
| 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); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
检查自定义组件祖先,而不是只检查直接父节点。
当输入为 <custom-wrapper><strong>World</strong></custom-wrapper> 时,World 的直接父节点是 strong。此条件会将 isParentCustomComponent 设为 false。因此,即使 animateInsideComponents 为 false 或未配置,World 仍会被替换为 AnimationText。
遍历祖先节点,或在 processChildren 中传递“位于自定义组件内部”的上下文。增加包含普通嵌套元素的启用和禁用测试。
🤖 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/x-markdown/src/XMarkdown/core/Renderer.ts` around lines 185 - 188,
Update the text replacement logic in Renderer around parentTagName and
shouldReplaceText to detect whether any ancestor, not only the direct parent, is
a configured custom component. Propagate this context through processChildren if
needed, so nested elements remain non-animated when animateInsideComponents is
disabled while preserving animation when it is enabled; add coverage for both
cases with ordinary nested elements.
Summary
Add
animateInsideComponentsoption toStreamingOptioninterface. When enabled, text nodes inside custom components (contentRender) also get the AnimationText typewriter effect.Changes
interface.ts: AddanimateInsideComponents?: booleantoStreamingOptionRenderer.ts: ModifyshouldReplaceTextlogic to allow animation inside custom components when the flag is setRenderer.test.ts: Add 6 unit tests covering on/off/default/nested/disable scenariosBehavior
animateInsideComponentsfalse(default)trueVerification
packages/x-markdown/demo.htmlshows side-by-side comparisonCloses #1950
🤖 Generated with Claude Code
Summary by CodeRabbit
新功能
测试