Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bubble的footer,header 支持参数传递,满足场景多样 #678

Closed
wants to merge 0 commits into from

Conversation

L-Hknu
Copy link

@L-Hknu L-Hknu commented Mar 31, 2025

中文版模板 / Chinese template

🤔 This is a ...

  • 🆕 New feature
  • 🐞 Bug fix
  • 📝 Site / documentation improvement
  • 📽️ Demo improvement
  • 💄 Component style improvement
  • 🤖 TypeScript definition improvement
  • 📦 Bundle size optimization
  • ⚡️ Performance optimization
  • ⭐️ Feature enhancement
  • 🌐 Internationalization
  • 🛠 Refactoring
  • 🎨 Code style optimization
  • ✅ Test Case
  • 🔀 Branch merge
  • ⏩ Workflow
  • ⌨️ Accessibility improvement
  • ❓ Other (about what?)

🔗 Related Issues

  • Describe the source of related requirements, such as links to relevant issue discussions.
  • For example: close #xxxx, fix #xxxx

💡 Background and Solution

  • The specific problem to be addressed.
  • List the final API implementation and usage if needed.
  • If there are UI/interaction changes, consider providing screenshots or GIFs.

📝 Change Log

Language Changelog
🇺🇸 English
🇨🇳 Chinese

Summary by CodeRabbit

  • 新功能

    • 优化了 Bubble 组件中页眉和页脚的渲染方式,现在支持传入静态内容或动态渲染函数,实现更灵活的内容展示。
  • 文档更新

    • 更新了文档说明,明确描述了页眉和页脚属性的新用法,以帮助用户了解新功能。

Copy link
Contributor

coderabbitai bot commented Mar 31, 2025

📝 Walkthrough

Walkthrough

本次变更在 Bubble 组件中新增了 renderSlot 函数,以支持对 headerfooter 属性的灵活渲染。现在这两个属性不仅可以传入静态的 React 节点,还可以传入函数,从而动态生成内容。同时,相关文档(英文和中文)以及接口定义均更新了对应的类型定义,让其支持新的函数签名。

Changes

文件 更改摘要
components/bubble/Bubble.tsx 添加了 renderSlot 函数,用于判断并渲染 headerfooter 属性。
components/bubble/index.en-US.md
components/bubble/index.zh-CN.md
修改文档中 headerfooter 的类型定义,由 React.ReactNode 扩展为支持函数返回 React 节点。
components/bubble/interface.ts 更新 BubbleProps 接口中 headerfooter 的类型定义,添加了函数签名支持,允许传入可接收信息并返回 React 节点的函数。

Possibly related PRs

Suggested reviewers

  • YumoImer

Poem

我是个跳跃的兔子,
在代码森林中挖掘新奇,
renderSlot点亮了 header 与 footer,
静态或动态皆可随心所欲。
文档与接口完美衔接,
代码春天,万物更新! 🐇✨


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between acd7603 and 95744dd.

📒 Files selected for processing (1)
  • components/bubble/Bubble.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/bubble/Bubble.tsx

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

github-actions bot commented Mar 31, 2025

Prepare preview

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
components/bubble/Bubble.tsx (3)

144-152: renderSolt 函数命名疑似有误

函数名 renderSolt 可能是拼写错误,应该是 renderSlot(slot,不是 solt)。该函数逻辑正确,支持了 header 和 footer 的函数式渲染,但命名应当符合前端常规术语。

-  const renderSolt = (node:React.ReactNode | ((info: { content?: BubbleContentType,props:BubbleProps} ) => React.ReactNode)) => {
+  const renderSlot = (node:React.ReactNode | ((info: { content?: BubbleContentType,props:BubbleProps} ) => React.ReactNode)) => {

另外,建议在函数参数类型定义中添加空格,使代码更易读:

-  const renderSolt = (node:React.ReactNode | ((info: { content?: BubbleContentType,props:BubbleProps} ) => React.ReactNode)) => {
+  const renderSlot = (node: React.ReactNode | ((info: { content?: BubbleContentType, props: BubbleProps }) => React.ReactNode)) => {

168-168: 更新函数调用名称

需要更新函数调用以匹配建议的重命名。

-            {renderSolt(header)}
+            {renderSlot(header)}

184-184: 更新函数调用名称

同样需要更新这里的函数调用。

-            {renderSolt(footer)}
+            {renderSlot(footer)}
components/bubble/interface.ts (1)

39-40: 接口定义更新恰当,但建议调整格式

接口定义更新为支持函数类型的 headerfooter 属性,类型定义完善。但建议添加空格以提高代码可读性。

-  header?: React.ReactNode | ((info: { content?: BubbleContentType,props:BubbleProps}) => React.ReactNode);
-  footer?: React.ReactNode | ((info: { content?: BubbleContentType,props:BubbleProps} ) => React.ReactNode);
+  header?: React.ReactNode | ((info: { content?: BubbleContentType, props: BubbleProps }) => React.ReactNode);
+  footer?: React.ReactNode | ((info: { content?: BubbleContentType, props: BubbleProps }) => React.ReactNode);

另外,注意到文档中的接口定义与这里的实现存在差异:

  • 文档:(info: { content?: string }) => ReactNode
  • 实现:(info: { content?: BubbleContentType, props: BubbleProps }) => React.ReactNode

建议在文档中也包含 props 参数,以保持一致性,或者在代码实现中考虑简化接口。

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2120e71 and 6835419.

📒 Files selected for processing (4)
  • components/bubble/Bubble.tsx (3 hunks)
  • components/bubble/index.en-US.md (1 hunks)
  • components/bubble/index.zh-CN.md (1 hunks)
  • components/bubble/interface.ts (1 hunks)
🔇 Additional comments (2)
components/bubble/index.zh-CN.md (1)

47-48: 文档类型定义更新符合功能拓展

文档中的 footerheader 属性类型更新为支持函数类型,这与组件实现保持一致,增强了气泡组件的灵活性。但建议在文档中添加一个示例,展示如何使用这种函数式传参的新特性。

components/bubble/index.en-US.md (1)

46-47: 英文文档类型定义更新一致

英文文档中 footerheader 属性的类型定义更新与中文文档保持一致,这很好。同样建议添加一个使用示例,以便开发者更容易理解和使用这个新特性。

Copy link
Author

@L-Hknu L-Hknu left a comment

Choose a reason for hiding this comment

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

剔除过于开放的参数

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
components/bubble/Bubble.tsx (4)

144-151: 函数命名有拼写错误: "renderSolt" 应为 "renderSlot"

函数名 renderSolt 存在拼写错误,应该是 renderSlot。"Slot" 是组件库中表示插槽的常用术语。此外,类型注解的冒号后应有空格,以符合 TypeScript 代码规范。

请应用以下修改:

-  const renderSolt = (node:React.ReactNode | ((info: { content?: BubbleContentType} ) => React.ReactNode)) => {
+  const renderSlot = (node: React.ReactNode | ((info: { content?: BubbleContentType }) => React.ReactNode)) => {

144-151: 考虑为传递的 content 类型做更安全的处理

当调用函数形式的 node 时,直接传递了原始 content。根据 BubbleContentType 的定义,content 可能是 React 节点或任意对象。如果 content 本身也是一个函数,可能会导致意外行为。

建议添加一个检查,确保传递给函数的参数符合预期:

  if (typeof node === 'function') {
    return node({
-      content: content
+      content: typeof content === 'function' ? null : content
    })
  }

167-167: 更新函数调用名称

此处需要更新函数名以匹配修正后的 renderSlot 函数名。

请应用以下修改:

-            {renderSolt(header)}
+            {renderSlot(header)}

183-183: 更新函数调用名称

此处需要更新函数名以匹配修正后的 renderSlot 函数名。

请应用以下修改:

-            {renderSolt(footer)}
+            {renderSlot(footer)}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6835419 and c4c1444.

📒 Files selected for processing (2)
  • components/bubble/Bubble.tsx (3 hunks)
  • components/bubble/interface.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • components/bubble/interface.ts
🧰 Additional context used
🧬 Code Definitions (1)
components/bubble/Bubble.tsx (1)
components/bubble/interface.ts (1)
  • BubbleContentType (21-21)
🔇 Additional comments (1)
components/bubble/Bubble.tsx (1)

144-151: 功能设计良好,支持更灵活的组件扩展

这个新增功能允许 headerfooter 属性接受函数形式的参数,增强了组件的灵活性和扩展性。这种模式使得 Bubble 组件可以在不同场景下更加灵活地适应不同的需求,符合组件设计的最佳实践。

const renderSlot = (node:React.ReactNode | ((info: { content?: BubbleContentType} ) => React.ReactNode)) => {
if (typeof node === 'function') {
return node({
content: content
Copy link
Member

Choose a reason for hiding this comment

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

这边也是 typedContent,和 messageRender 保持一致。另外需要写对应的 test case

@@ -36,6 +36,6 @@ export interface BubbleProps<ContentType extends BubbleContentType = string>
variant?: 'filled' | 'borderless' | 'outlined' | 'shadow';
shape?: 'round' | 'corner';
onTypingComplete?: VoidFunction;
header?: React.ReactNode;
footer?: React.ReactNode;
header?: React.ReactNode | ((info: { content?: BubbleContentType}) => React.ReactNode);
Copy link
Member

Choose a reason for hiding this comment

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

feature branch

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
components/bubble/Bubble.tsx (1)

144-151: 增加了灵活的渲染插槽函数

renderSlot 函数使 header 和 footer 属性能够接受函数类型,从而可以根据当前内容动态生成渲染内容。这提升了组件的灵活性,使其能够满足更多场景需求。

不过有几点建议:

  1. 考虑添加 JSDoc 注释来说明此函数的用途和参数
  2. 可以重命名为 renderTypedSlotmessageRender 保持一致的命名风格
-  const renderSlot = (node:React.ReactNode | ((info: { content?: BubbleContentType} ) => React.ReactNode)) => {
+  /**
+   * 根据传入的节点类型进行渲染,如果是函数则传入 typedContent
+   * @param node 要渲染的节点或生成节点的函数
+   * @returns 渲染后的 React 节点
+   */
+  const renderTypedSlot = (node:React.ReactNode | ((info: { content?: BubbleContentType} ) => React.ReactNode)) => {
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aaa4451 and acd7603.

📒 Files selected for processing (1)
  • components/bubble/Bubble.tsx (3 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
components/bubble/Bubble.tsx (1)
components/bubble/interface.ts (1)
  • BubbleContentType (21-21)
🔇 Additional comments (2)
components/bubble/Bubble.tsx (2)

183-183: 实现了 footer 属性的灵活渲染

通过调用 renderSlot 函数,footer 现在可以作为函数接收当前内容信息,增强了自定义能力。

与之前的评论一致,需要为此功能编写测试用例。


167-167:

✅ Verification successful

实现了 header 属性的灵活渲染

通过调用 renderSlot 函数,header 现在可以作为函数接收当前内容信息,增强了自定义能力。

建议更新对应的测试用例,确保新功能的正确性。


🌐 Web query:

如何编写 React 组件的函数式 props 测试

💡 Result:

在测试React函数式组件的props时,需要重点关注属性值的正确传递、条件渲染逻辑和事件触发机制。以下是核心测试方法和实践:

一、基本属性测试

  1. 直接属性断言
// 测试文本输入组件的标签和默认值
it('验证TextInput属性传递', () => {
  const props = { label: '用户名', defaultValue: '初始值' };
  const wrapper = mount(<TextInput {...props} />);
  
  expect(wrapper.find('label').text()).toBe('用户名');
  expect(wrapper.find('input').prop('value')).toBe('初始值');
})[2];
  1. 完整props对象比对
// 比对密码输入框的所有props属性
it('验证密码字段props完整性', () => {
  const container = shallow(<Login password="secret" />);
  expect(container.find('input[type="password"]').props()).toEqual({
    className: 'my-2',
    onChange: expect.any(Function),
    type: 'password',
    value: 'secret'
  });
})[1];

二、条件渲染测试

测试场景 测试方法 示例
prop存在时渲染 检查目标元素是否存在 expect(label).toExist()
prop为空时隐藏 验证元素是否被正确条件渲染 expect(icon).toBeNull()
动态内容显示 对比渲染内容与prop值的匹配度 expect(title.text()).toEqual(props.title)
// 测试标签的条件渲染
it('当label为空时不显示标签', () => {
  const wrapper = mount(<TextInput />);
  expect(wrapper.find('label')).toHaveLength(0);
});

it('当label有值时显示标签', () => {
  const wrapper = mount(<TextInput label="邮箱地址" />);
  expect(wrapper.find('label').text()).toBe('邮箱地址');
})[2];

三、事件处理测试

  1. 模拟事件触发
it('点击按钮触发onSubmit回调', () => {
  const mockSubmit = jest.fn();
  const { getByRole } = render(<SubmitButton onSubmit={mockSubmit} />);
  
  fireEvent.click(getByRole('button'));
  expect(mockSubmit).toHaveBeenCalledTimes(1);
})[5][7];
  1. 参数传递验证
it('输入框变更传递正确参数', () => {
  const handleChange = jest.fn();
  const { getByPlaceholderText } = render(<SearchInput onChange={handleChange} />);
  
  fireEvent.change(getByPlaceholderText('搜索...'), { 
    target: { value: 'React测试' } 
  });
  
  expect(handleChange).toHaveBeenCalledWith('React测试');
})[7][15];

四、最佳实践

  1. 使用data-testid属性定位元素
<input 
  data-testid="email-input"
  value={email}
  onChange={handleChange}
/>

// 测试中通过testId定位
const input = screen.getByTestId('email-input')[8];
  1. 异步操作处理
it('异步加载后显示数据', async () => {
  const { findByText } = render(<UserProfile userId="123" />);
  
  await waitFor(() => {
    expect(findByText('用户姓名')).toBeInTheDocument();
  });
})[7][16];
  1. Props类型校验
// 在组件文件中定义propTypes
MyComponent.propTypes = {
  count: PropTypes.number.isRequired,
  onUpdate: PropTypes.func,
};

// 测试时验证类型错误
it('当count非数字时告警', () => {
  console.error = jest.fn();
  render(<MyComponent count="invalid" />);
  expect(console.error).toHaveBeenCalled();
})[11][20];

通过以上方法可以有效验证函数式组件的props处理逻辑,确保组件在不同场景下的正确表现。测试时应结合浅渲染(shallow)和全渲染(mount)策略,重点测试组件接口的输入输出行为,避免过度测试实现细节。

Citations:


更新建议:完善测试用例以覆盖函数式 props 的场景

代码实现已正确支持通过调用 renderSlot 函数来灵活渲染 header 属性,提高了组件的自定义能力。但建议补充相应的测试用例,确保传入函数形式的 header 能在各个场景下正常工作。可参考以下测试重点:

  • 验证直接属性传递和断言,确保传入的函数能被调用并返回预期内容;
  • 增加条件渲染测试,检查当 header 为函数时组件的渲染结果;
  • 如有事件处理逻辑,确保对返回内容的事件触发也做相应的测试。

示例修改建议:

it('应正确调用 header 函数并渲染返回内容', () => {
  const headerFn = jest.fn().mockReturnValue(<div data-testid="header-content">测试头部</div>);
  const wrapper = mount(<Bubble header={headerFn} />);
  
  // 确保 header 函数被调用
  expect(headerFn).toHaveBeenCalled();
  // 验证返回的内容是否被正确渲染
  expect(wrapper.find('[data-testid="header-content"]').exists()).toBe(true);
});

请根据项目中已有的测试实践(例如直接属性断言、条件渲染和事件模拟)进行相应调整,以全面验证新实现的功能。

Copy link
Member

@afc163 afc163 left a comment

Choose a reason for hiding this comment

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

已经有一个了 #638

@L-Hknu
Copy link
Author

L-Hknu commented Mar 31, 2025

已经有一个了 #638

比他多了个头部支持 o_o|||

Copy link

codecov bot commented Apr 1, 2025

Bundle Report

Bundle size has no change ✅

Copy link

codecov bot commented Apr 1, 2025

Codecov Report

Attention: Patch coverage is 75.00000% with 1 line in your changes missing coverage. Please review.

Project coverage is 91.97%. Comparing base (2120e71) to head (95744dd).

Files with missing lines Patch % Lines
components/bubble/Bubble.tsx 75.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #678      +/-   ##
==========================================
- Coverage   92.01%   91.97%   -0.05%     
==========================================
  Files          67       67              
  Lines        1491     1495       +4     
  Branches      387      404      +17     
==========================================
+ Hits         1372     1375       +3     
- Misses        119      120       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@@ -141,7 +141,14 @@ const Bubble: React.ForwardRefRenderFunction<BubbleRef, BubbleProps> = (props, r
{contentNode}
</div>
);

const renderSlot = (node:React.ReactNode | ((info: { content?: BubbleContentType} ) => React.ReactNode)) => {
Copy link
Member

Choose a reason for hiding this comment

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

test case~

@afc163
Copy link
Member

afc163 commented Apr 1, 2025

#638 我已经合并了,建议在这个的基础上继续修改。

@afc163
Copy link
Member

afc163 commented Apr 1, 2025

新特性放在 feature 分支

@L-Hknu
Copy link
Author

L-Hknu commented Apr 1, 2025

#683 用此提交

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.

3 participants