Skip to content

Conversation

@keiseiTi
Copy link

@keiseiTi keiseiTi commented Nov 26, 2025

If the panel is set to styles or classNames, use it's properties, otherwise use collpase's styles or classNames.

Summary by CodeRabbit

  • 新功能

    • 支持为单个面板项提供样式与类名覆盖,可对每项的头部/主体样式与类名进行细粒度自定义。
  • 改进

    • 合并全局与每项的样式/类名以保证一致渲染,未提供覆盖时保留原有默认行为与兼容性。
  • 测试

    • 新增测试验证每项层级的样式与类名覆盖及其与全局配置的组合生效。
  • 注意

    • 对外公开接口未发生变更。

✏️ Tip: You can customize this high-level summary in your review settings.

@vercel
Copy link

vercel bot commented Nov 26, 2025

@keiseiTi is attempting to deploy a commit to the React Component Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 26, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

useItems 中的渲染逻辑扩展为支持每个 item 的 classNamesstyles 覆盖;父级 props 在钩子内以 collapseClassNames / collapseStyles 命名,渲染 CollapsePanel 时合并全局与每项的 classNames/styles。新增测试验证按面板级别的类名与样式覆盖行为。

Changes

Cohort / File(s) 变更摘要
按项样式和类名合并逻辑
src/hooks/useItems.tsx
将父级 props 重命名为 collapseClassNames / collapseStyles,从每个 item 提取 classNamesstyles,使用 clsx 与对象合并将全局与每项的 header/body/title/icon classNames/styles 合并后传给 CollapsePanel;引入 SemanticName 类型以增强类型标注。
测试:面板级样式/类名覆盖
tests/index.spec.tsx
新增用例验证 items[].stylesitems[].classNames 能覆盖或补充全局 collapseStyles / collapseClassNames,断言 header/body 等子部分的样式与类名按项生效。

Sequence Diagram(s)

sequenceDiagram
  participant Hook as useItems / convertItemsToNodes
  participant Item as items[i]
  participant Merge as MergeProps
  participant Panel as CollapsePanel

  Note over Hook,Item: 遍历每个 item,准备渲染 props
  Hook->>Item: 读取 item.props(含可选 classNames/styles)
  Hook->>Merge: 提供 collapseClassNames/collapseStyles(全局)
  Item->>Merge: 提供 item.classNames/item.styles(按项)
  Merge-->>Hook: 返回 mergeClassNames / mergeStyles
  Hook->>Panel: 渲染 CollapsePanel(使用合并后的 classNames/styles)
  Panel-->>Hook: 渲染节点返回
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 分钟

  • 重点关注:
    • 合并逻辑对空值/undefined 的回退行为和优先级;
    • clsx 与对象 spread 的组合是否在所有子名(header/body/title/icon)上正确应用;
    • 类型使用(SemanticName)与现有导出签名的兼容性;
    • 新增测试是否覆盖边界情况(部分缺失子字段等)。

Possibly related PRs

Suggested reviewers

  • zombieJ

🐰 折叠枝头风微暖,
每页披衣各自欢。
父影合并子自裁,
小项有声亦有态,
代码跳跃带胡萝卜🥕

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题清晰准确地总结了主要变更:修复面板级别的styles和classNames属性不起作用的问题,与PR描述和代码变更完全一致。
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

@gemini-code-assist
Copy link

Summary of Changes

Hello @keiseiTi, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses an issue where custom styles and classNames applied to individual panels within a collapse component were not being correctly rendered. The changes introduce a robust mechanism to ensure that panel-specific styling takes precedence, falling back to the collapse component's general styling only when no specific styles or classes are provided for a panel. This enhances the flexibility and customization options for users of the component.

Highlights

  • Style and ClassName Prioritization: Implemented logic to prioritize styles and classNames defined directly on individual panel items over the general styles and classNames provided to the collapse component.
  • Prop Renaming: Renamed the styles prop from the main collapse component to collapseStyles to avoid naming conflicts when extracting panel-specific styles.
  • Panel-Specific Style Extraction: Modified the useItems hook to extract classNames and styles directly from each item object, enabling individual panels to have unique styling.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

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 aims to fix an issue where styles and classNames on individual panels were not being applied. The changes correctly address this for panels provided via the items prop by prioritizing panel-specific properties over the ones from the parent Collapse component. However, as noted in my comment, the fix is incomplete because it doesn't cover panels passed as children. I've recommended extending the fix to the getNewChild function to ensure consistent behavior across the component.

expandIcon,
classNames: collapseClassNames,
styles,
styles: collapseStyles,

Choose a reason for hiding this comment

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

high

Renaming styles to collapseStyles is a good step to avoid naming collisions. However, this fix for panel-specific styles and classNames appears to be incomplete because it only applies to panels defined via the items prop.

The getNewChild function (which handles Panel components passed as children, starting on line 88) has not been updated. It still passes the Collapse component's styles and classNames to each CollapsePanel, ignoring the props on the Panel itself.

To ensure consistent behavior, I recommend applying a similar fix to the getNewChild function. This would involve:

  1. Destructuring classNames and styles from child.props.
  2. Passing childClassNames || collapseClassNames and childStyles || collapseStyles to the cloned element.

This will make the fix comprehensive, even though getNewChild is deprecated.

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)
src/hooks/useItems.tsx (1)

36-37: item 级 classNames/styles 覆盖逻辑正确,可考虑后续扩展为“部分合并”

现在从 item 解构出 classNamesstyles,并在渲染时使用:

  • 当 item 提供 classNames / styles 时,优先使用面板自己的配置;
  • 当未提供时,回退到 collapseClassNames / collapseStyles

这正好修复了“面板级 classNames/styles 不生效”的问题,也与 PR 描述“有面板级就用面板级,否则用 collapse 级”一致。当前实现是“全量替换”,即一旦 item 传入对象,就完全覆盖 collapse 级默认值。

如果未来有需求在 item 上只覆盖部分 key(例如只改 header 的样式,但保留 collapse 默认的其他部位样式),可以考虑改为在这里做一次对象合并(例如先用 collapse 默认,再叠加 item 的配置),以支持更细粒度的定制。

Also applies to: 65-66

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c1a28dc and a9aba53.

📒 Files selected for processing (1)
  • src/hooks/useItems.tsx (3 hunks)
🔇 Additional comments (1)
src/hooks/useItems.tsx (1)

24-26: 为 Collapse 级别样式使用别名是合理且必要的调整

这里将 props 中的 classNames / styles 解构为 collapseClassNames / collapseStyles,避免后续与 item 自身的 classNames / styles 命名冲突,同时也让“容器默认值 vs 面板局部配置”的职责更加清晰,逻辑上没有问题。

@codecov
Copy link

codecov bot commented Nov 26, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.16%. Comparing base (c1a28dc) to head (ecd38af).

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #409   +/-   ##
=======================================
  Coverage   99.16%   99.16%           
=======================================
  Files           5        5           
  Lines         120      120           
  Branches       45       44    -1     
=======================================
  Hits          119      119           
  Misses          1        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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

{...restProps}
classNames={collapseClassNames}
styles={styles}
classNames={classNames || collapseClassNames}
Copy link
Member

Choose a reason for hiding this comment

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

不应该是替代关系,而是合并关系

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

Copy link
Author

@keiseiTi keiseiTi Nov 26, 2025

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: 1

♻️ Duplicate comments (1)
src/hooks/useItems.tsx (1)

156-162: getNewChild 函数未应用相同的合并逻辑。

虽然此函数已标记为 deprecated,但在通过 children 方式传入 Panel 时仍会被使用。当前实现直接传递 collapseClassNamesstyles,未与 child.props 中的 classNamesstyles 合并。

🧹 Nitpick comments (1)
tests/index.spec.tsx (1)

902-954: 测试用例验证了合并行为,建议补充 titleicon 的测试。

测试正确验证了:

  1. collapse 级别和 panel 级别的 classNames 同时生效(第 944-947 行)
  2. panel 级别的 styles 可以覆盖 collapse 级别的值(第 950-953 行)

useItems.tsx 中补全 titleicon 的合并逻辑后,建议扩展此测试以覆盖这两个字段。

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ecd38af and a5d71b7.

📒 Files selected for processing (2)
  • src/hooks/useItems.tsx (4 hunks)
  • tests/index.spec.tsx (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
tests/index.spec.tsx (1)
src/index.tsx (1)
  • Collapse (10-10)
src/hooks/useItems.tsx (1)
src/interface.ts (1)
  • SemanticName (44-44)
🔇 Additional comments (1)
src/hooks/useItems.tsx (1)

84-85: 合并后的 classNames 和 styles 正确传递给 CollapsePanel。

实现思路正确,通过 clsx 合并 className 字符串,通过对象展开合并 styles,使得 panel 级别的配置可以覆盖或扩展 collapse 级别的配置。

Comment on lines +63 to +79
const mergeClassNames: Partial<Record<SemanticName, string>> = {
...collapseClassNames,
header: clsx(collapseClassNames?.header, classNames?.header),
body: clsx(collapseClassNames?.body, classNames?.body),
};

const mergeStyles: Partial<Record<SemanticName, React.CSSProperties>> = {
...collapseStyles,
header: {
...collapseStyles?.header,
...styles?.header,
},
body: {
...collapseStyles?.body,
...styles?.body,
},
};
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

合并逻辑缺少 titleicon 的处理。

SemanticName 类型包含 'header' | 'title' | 'body' | 'icon' 四个值,但当前合并逻辑仅显式处理了 headerbody。如果 panel 级别设置了 classNames.titleclassNames.iconstyles.titlestyles.icon,这些值不会与 collapse 级别的值合并。

建议补全 titleicon 的合并逻辑:

 const mergeClassNames: Partial<Record<SemanticName, string>> = {
   ...collapseClassNames,
   header: clsx(collapseClassNames?.header, classNames?.header),
   body: clsx(collapseClassNames?.body, classNames?.body),
+  title: clsx(collapseClassNames?.title, classNames?.title),
+  icon: clsx(collapseClassNames?.icon, classNames?.icon),
 };

 const mergeStyles: Partial<Record<SemanticName, React.CSSProperties>> = {
   ...collapseStyles,
   header: {
     ...collapseStyles?.header,
     ...styles?.header,
   },
   body: {
     ...collapseStyles?.body,
     ...styles?.body,
   },
+  title: {
+    ...collapseStyles?.title,
+    ...styles?.title,
+  },
+  icon: {
+    ...collapseStyles?.icon,
+    ...styles?.icon,
+  },
 };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const mergeClassNames: Partial<Record<SemanticName, string>> = {
...collapseClassNames,
header: clsx(collapseClassNames?.header, classNames?.header),
body: clsx(collapseClassNames?.body, classNames?.body),
};
const mergeStyles: Partial<Record<SemanticName, React.CSSProperties>> = {
...collapseStyles,
header: {
...collapseStyles?.header,
...styles?.header,
},
body: {
...collapseStyles?.body,
...styles?.body,
},
};
const mergeClassNames: Partial<Record<SemanticName, string>> = {
...collapseClassNames,
header: clsx(collapseClassNames?.header, classNames?.header),
body: clsx(collapseClassNames?.body, classNames?.body),
title: clsx(collapseClassNames?.title, classNames?.title),
icon: clsx(collapseClassNames?.icon, classNames?.icon),
};
const mergeStyles: Partial<Record<SemanticName, React.CSSProperties>> = {
...collapseStyles,
header: {
...collapseStyles?.header,
...styles?.header,
},
body: {
...collapseStyles?.body,
...styles?.body,
},
title: {
...collapseStyles?.title,
...styles?.title,
},
icon: {
...collapseStyles?.icon,
...styles?.icon,
},
};
🤖 Prompt for AI Agents
In src/hooks/useItems.tsx around lines 63 to 79, the merge logic only handles
'header' and 'body' but misses 'title' and 'icon', so panel-level
classNames.title/icon and styles.title/icon are not merged with collapse-level
values; update mergeClassNames to include title: clsx(collapseClassNames?.title,
classNames?.title) and icon: clsx(collapseClassNames?.icon, classNames?.icon),
and update mergeStyles to include title: { ...collapseStyles?.title,
...styles?.title } and icon: { ...collapseStyles?.icon, ...styles?.icon } so all
four SemanticName entries are consistently merged.

isActive = activeKey.indexOf(key) > -1;
}

const mergeClassNames: Partial<Record<SemanticName, string>> = {
Copy link
Member

Choose a reason for hiding this comment

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

我建议是在 Collapse 顶层做一个 SemanticContext,然后传入 classNames 和 styles,然后在 panel 里读取 className 和 style 以及 contextClassName 和 contextStyle,在消费的时候做聚合。
现在合并在 useItems 这层,如果未来额外加 semantic structure 很容易忘记。

expect(bodyElement.classList).toContain('custom-body-panel');

// check styles
expect(headerElement.style.color).toBe('blue');
Copy link
Member

@zombieJ zombieJ Nov 26, 2025

Choose a reason for hiding this comment

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

可以直接 expect(xx).toHaveStyle({ xxx: xxx })

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