Skip to content

refactor: 重构collapse为details实现 #362

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

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

IVLIU
Copy link

@IVLIU IVLIU commented Mar 17, 2025

关联antd ant-design/ant-design#48974

Summary by CodeRabbit

  • 新功能
    • 折叠面板组件现采用原生 HTML <details><summary> 结构,提升可访问性与语义化。
    • 针对支持的浏览器,折叠内容区域新增原生动画效果,展开与收起更流畅。
  • 样式
    • 折叠面板内容区域新增动画和过渡效果,视觉体验优化。
  • 优化
    • 提升了折叠面板的渲染一致性和性能,部分浏览器下动画表现更佳。

Copy link

vercel bot commented Mar 17, 2025

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
collapse ✅ Ready (Inspect) Visit Preview 💬 Add feedback May 20, 2025 0:07am

Copy link

coderabbitai bot commented Mar 17, 2025

Walkthrough

本次变更将折叠面板组件从基于 <div> 的实现迁移到更具语义的原生 <details>/<summary> 元素。相关类型定义、事件处理和样式均做了适配。内容动画根据浏览器支持情况选择原生或 JS 动画。部分状态逻辑也做了简化和优化。

Changes

文件/路径 变更摘要
src/Collapse.tsx React.startTransition 包裹 setActiveKey,以优化状态与 <details> 的同步,添加相关注释。
src/Panel.tsx 根节点由 <div> 改为 <details>,header 用 <summary>,ref 类型与事件类型相应调整,支持原生动画。
src/interface.ts 类型定义从 HTMLDivElement 改为 HTMLDetailsElementstyle 类型更精确,props 继承关系调整。
assets/index.less 针对 .rc-collapse-item 增加原生 <details> 动画相关样式,支持 ::details-content 动画。
src/PanelContent.tsx 移除 rendered 的 state,改为直接用表达式推导,简化渲染逻辑。

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Collapse
    participant Panel (details)
    participant PanelContent

    User->>Collapse: 点击某面板
    Collapse->>Collapse: startTransition(setActiveKey)
    Collapse->>Panel: 传递 isActive, open
    Panel->>Panel: 渲染 <details open={isActive}>
    Panel->>PanelContent: 传递 isActive, forceRender
    PanelContent->>PanelContent: 判断 isActive || forceRender
    PanelContent-->>Panel: 渲染内容(动画或直接显示)
Loading

Poem

🐰
换 div 为 details,语义更美妙,
动画新姿态,CSS 也来跳。
类型精细化,代码更可靠,
折叠展开间,体验步步高!

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.

src/Collapse.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the config "prettier" to extend from. Please check that the name of the config is correct.

The config "prettier" was referenced from the config file in "/.eslintrc.js".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

src/Panel.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the config "prettier" to extend from. Please check that the name of the config is correct.

The config "prettier" was referenced from the config file in "/.eslintrc.js".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

src/PanelContent.tsx

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the config "prettier" to extend from. Please check that the name of the config is correct.

The config "prettier" was referenced from the config file in "/.eslintrc.js".

If you still have problems, please stop by https://eslint.org/chat/help to chat with the team.

  • 1 others

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.


📜 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 20ea000 and f8ac9ab.

📒 Files selected for processing (4)
  • src/Collapse.tsx (1 hunks)
  • src/Panel.tsx (5 hunks)
  • src/PanelContent.tsx (1 hunks)
  • src/interface.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/Collapse.tsx
  • src/PanelContent.tsx
  • src/interface.ts
  • src/Panel.tsx
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Commit Unit Tests in branch refactor/native-details-element
  • Post Copyable Unit Tests in 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
🪧 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.
    • Explain this complex logic.
    • 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 explain this code block.
    • @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 explain its main purpose.
    • @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.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

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 generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @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.

@IVLIU IVLIU changed the title feat: 重构collapse为details实现 refactor: 重构collapse为details实现 Mar 17, 2025
@afc163
Copy link
Member

afc163 commented Mar 19, 2025

ci 挂了

Copy link

codecov bot commented Mar 19, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 99.13%. Comparing base (74a99fe) to head (ce3ba4c).

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #362      +/-   ##
==========================================
+ Coverage   99.12%   99.13%   +0.01%     
==========================================
  Files           5        5              
  Lines         114      116       +2     
  Branches       43       43              
==========================================
+ Hits          113      115       +2     
  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.

@IVLIU
Copy link
Author

IVLIU commented Mar 19, 2025

ci 挂了

fixed 少个包

@afc163
Copy link
Member

afc163 commented Mar 19, 2025

收起动画丢了。

Copy link

@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

🧹 Nitpick comments (1)
src/Panel.tsx (1)

45-48: 考虑重新评估 ARIA 角色的必要性

使用 detailssummary 元素后,这些元素已经具有原生的语义和辅助功能。可以考虑是否仍然需要设置 role="tab"role="button" 和其他 ARIA 属性,因为这些可能与元素的原生语义冲突。

HTML5 的 detailssummary 元素原生支持可访问性,无需额外的 ARIA 角色。

Is it necessary to add ARIA roles to details and summary elements?
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between df7f09e and ce3ba4c.

📒 Files selected for processing (1)
  • src/Panel.tsx (5 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
src/Panel.tsx (2)
src/interface.ts (1) (1)
  • CollapsePanelProps (45-67)
src/index.tsx (1) (1)
  • CollapsePanelProps (3-3)
🔇 Additional comments (3)
src/Panel.tsx (3)

8-8: 使用更符合语义的 HTML 元素

forwardRef 类型从 HTMLDivElement 更改为 HTMLDetailsElement 是一个很好的改进,这符合 HTML 语义化的最佳实践,details 元素本身就是为折叠内容设计的。


83-83: 类型定义更新合理

headerProps 的类型从 HTMLDivElement 更改为更通用的 HTMLElement 是合理的,因为现在头部使用的是 summary 元素。


36-39:

❓ Verification inconclusive

请确认事件传播行为是否符合预期

添加 e.stopPropagation() 阻止了事件冒泡,这在某些情况下是必要的,但请确认这不会破坏依赖事件冒泡的父组件功能。


🏁 Script executed:

#!/bin/bash
# 查找可能依赖事件冒泡的代码
rg -A 5 "onItemClick" --type ts --type tsx

Length of output: 70


事件冒泡行为验证建议

文件:src/Panel.tsx (行 36-39)
代码示例:

  onClick: (e: React.MouseEvent) => {
    onItemClick?.(panelKey);
    e.stopPropagation();
  },

说明:

  • 此处调用 e.stopPropagation() 用于阻止事件冒泡,请确认这一行为不会对依赖事件冒泡机制的父组件造成影响。
  • 建议检查项目中其他对 onItemClick 的引用,以确保没有依赖事件继续冒泡的逻辑。

请运行上面的脚本,并手动确认是否有其他地方依赖事件冒泡逻辑,以便确保代码行为符合预期。


🏁 Script executed:

#!/bin/bash
# 重新搜索所有文件中 onItemClick 的使用情况,不限制文件类型
rg -A 5 "onItemClick" || echo "未发现 onItemClick 使用记录"

Length of output: 8169


请确认是否有依赖事件冒泡的父组件逻辑

通过搜索代码可知,代码在 src/Panel.tsx 第 36-39 行设置了如下点击处理逻辑:

onClick: (e: React.MouseEvent) => {
  onItemClick?.(panelKey);
  e.stopPropagation();
},
  • 脚本搜索显示,onItemClick 在多个文件(如 src/interface.ts, src/hooks/useItems.tsxsrc/Panel.tsx)中作为回调使用。测试用例也验证了在点击时 onItemClick 正确触发,并且在禁用或特定场景下,行为符合预期。
  • 从现有代码和测试来看,没有明显依赖点击事件冒泡的父组件逻辑。但由于 e.stopPropagation() 的作用会完全阻断事件冒泡,请您确认在业务场景下父组件或其他外部逻辑是否需要捕获同一事件进行额外处理。

请根据具体业务逻辑,确认后续是否需要调整,以免破坏依赖事件冒泡的父组件的功能。

@IVLIU
Copy link
Author

IVLIU commented Mar 19, 2025

收起动画丢了。

我在想有没有必要开个discussion讨论下这个问题
改造前开闭实现其实是利用content的height值变化来实现的,本质上是没有open状态的
改造后基于details的实现其实是有open状态的,即content的可见性是有open决定的,而不是content的height

因此改造后的渲染流程如下

open = true时,content展现,然后高度过渡
open = false时,content隐藏,此时动画不可见

所以我觉得需要讨论下这部分的实现,我先说下我的想法

  1. 渐进式增强,对于高版本浏览器,移除CSSMotion,使用::details-content实现展开关闭动画,对于不支持的,使用CSSMotion实现展开动画
  2. 内部再维护一个动画状态,拦截details的点击事件,优先改变动画状态,待动画执行完毕再改变open状态

个人上是更倾向方式1,这样的话,在高版本浏览器中,组件将变得足够简单,性能也将更上一层楼,仅做状态同步即可

@afc163
Copy link
Member

afc163 commented Mar 19, 2025

1 可以的,我也倾向渐进式。

Copy link

@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/Panel.tsx (1)

164-177: 更新了组件的HTML结构

将原来的div结构改为使用语义化的detailssummary元素:

  1. 使用details作为根容器,通过open属性控制展开状态
  2. 使用summary作为标题容器
  3. 根据条件渲染内容部分

这种修改充分利用了HTML的语义化结构,不仅提高了可访问性,还能利用浏览器原生行为。同时通过open={isActive}保持了对组件状态的受控特性。

可能会影响动画效果,需要确认:

  1. 动画效果是否已恢复
  2. details元素的原生展开/折叠行为是否与CSSMotion兼容
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between ce3ba4c and ff26366.

📒 Files selected for processing (3)
  • assets/index.less (1 hunks)
  • src/Collapse.tsx (1 hunks)
  • src/Panel.tsx (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/Collapse.tsx
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/Panel.tsx (1)
src/interface.ts (1)
  • CollapsePanelProps (45-67)
🔇 Additional comments (6)
src/Panel.tsx (6)

8-8: 更新了组件的根元素类型

将组件的根元素从div改为details,同时更新了转发引用类型从HTMLDivElement变为HTMLDetailsElement

这种修改更符合HTML语义化标准,利用了浏览器原生的可折叠组件功能。


35-42: 添加了浏览器特性检测

使用CSS.supportsAPI检测浏览器是否支持::details-content伪元素选择器,这决定了是使用CSS原生动画还是回退到CSSMotion

这是实现渐进增强策略的关键部分,能够在支持现代CSS特性的浏览器中提供更好的性能,同时保持向后兼容性。

哪些浏览器支持details::details-content伪元素选择器?

44-48: 更新了事件处理逻辑

修改了点击事件处理函数的参数类型,并添加了e.stopPropagation()防止事件冒泡。

添加stopPropagation()是必要的,可以防止事件冒泡导致details元素的原生点击事件与自定义处理逻辑冲突。


80-81: 条件性应用动画类名

仅在浏览器支持::details-content选择器时才将motionName应用到details元素上。

这与渐进增强的方法一致,确保动画效果只在支持的浏览器中应用。


94-94: 泛化了header属性的类型定义

headerProps的类型从HTMLDivElement更改为更通用的HTMLElement

这是一个合理的修改,因为现在header是summary元素而不是div


102-162: 重构内容渲染逻辑

引入了createPanelContent函数和基于浏览器特性的条件渲染逻辑:

  1. 抽象出内容创建逻辑到单独的函数
  2. 根据浏览器支持情况决定使用CSSMotion还是原生CSS控制内容显示
  3. 模拟CSSMotion的生命周期管理逻辑

这种设计能够在现代浏览器中利用原生功能实现更好的性能,同时为不支持的浏览器提供良好的回退方案。代码结构清晰,条件逻辑易于理解。

Comment on lines +38 to +50
list-style-position: outside;
interpolate-size: allow-keywords;
overflow: hidden;

&::details-content {
block-size: 0;
transition: block-size 0.6s, content-visibility 0.6s;
transition-behavior: allow-discrete;
}

&[open]::details-content {
block-size: auto;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

使用现代CSS特性实现动画过渡

代码引入了一些新的CSS特性来实现基于<details>元素的动画效果:

  • interpolate-size: allow-keywords; 允许在尺寸关键词(如auto)和具体值之间进行插值动画
  • ::details-content 伪元素选择器用于直接控制details内容区域的样式和动画
  • 使用transition-behavior: allow-discrete;支持离散过渡效果

这些CSS特性是比较新的,需要注意浏览器兼容性问题。与Panel.tsx中的特性检测(CSS.supports('selector(details::details-content)'))相配合,可以实现渐进增强的用户体验。

建议添加一些注释说明这些属性的浏览器兼容性要求,或考虑为不支持这些特性的浏览器提供兼容性样式。

🤖 Prompt for AI Agents (early access)
In assets/index.less around lines 38 to 50, the CSS uses modern features like
interpolate-size, ::details-content, and transition-behavior which have limited
browser support. Add comments explaining the browser compatibility requirements
for these properties and consider adding fallback styles or alternative
approaches for browsers that do not support these features to ensure graceful
degradation.

@IVLIU
Copy link
Author

IVLIU commented May 10, 2025

1 可以的,我也倾向渐进式。

image
新增渐进式处理,为false则回退至CSSMotion,但这里存在一个问题,走服务端渲染时,会存在两端不一致的问题,有什么建议?

image
动画实现可以参考

@IVLIU
Copy link
Author

IVLIU commented May 10, 2025

或许可以移除CSSMotion,根据是否支持::details-content伪元素将motionName设置到details元素或者<PanelContent />

@afc163
Copy link
Member

afc163 commented May 20, 2025

有冲突

Copy link

vercel bot commented May 20, 2025

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

A member of the Team first needs to authorize it.

Copy link

@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/Panel.tsx (1)

164-177: 将根元素从 div 更改为 details

使用语义化的 <details><summary> 元素替代了原来的 div 结构,这是一个很好的改进,符合 HTML 语义化原则,并且可以利用浏览器原生行为。

正确地将 isActive 状态映射到 detailsopen 属性,确保了组件状态与 DOM 状态的一致性。

🧹 Nitpick comments (1)
src/Panel.tsx (1)

102-127: 提取 PanelContent 创建逻辑到独立函数

将面板内容创建逻辑提取到 createPanelContent 函数中是一个很好的重构,它提高了代码的可读性并减少了重复代码。参数选项的类型定义也很清晰。

不过,由于这个函数是在每次渲染时重新创建的,可以考虑使用 useCallback 来优化性能,尤其是对于复杂组件可能频繁重渲染的情况。

可以考虑使用 useCallback 缓存 createPanelContent 函数,避免在每次渲染时重新创建:

- const createPanelContent = (
+ const createPanelContent = useCallback((
    options: Partial<{
      motionClassName: string;
      style: React.CSSProperties;
      motionRef: (node: HTMLDivElement) => void;
    }>,
-  ) => {
+  ) => {
    const { motionClassName, style, motionRef } = options;

    return (
      <PanelContent
        ref={motionRef}
        prefixCls={prefixCls}
        className={motionClassName}
        classNames={customizeClassNames}
        style={style}
        styles={styles}
        isActive={isActive}
        forceRender={forceRender}
        role={accordion ? 'tabpanel' : void 0}
      >
        {children}
      </PanelContent>
    );
-  };
+  }, [prefixCls, customizeClassNames, styles, isActive, forceRender, accordion, children]);
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 926e147 and 20ea000.

📒 Files selected for processing (1)
  • src/Panel.tsx (5 hunks)
🔇 Additional comments (7)
src/Panel.tsx (7)

4-4: 添加了 useMemo 导入以支持特性检测

引入了 useMemo 用于缓存浏览器特性检测结果,这是一个很好的优化,避免了不必要的重复计算。


8-8: 将引用类型从 HTMLDivElement 更新为 HTMLDetailsElement

将组件的引用类型从 HTMLDivElement 更改为 HTMLDetailsElement 是必须的,与后续将根元素改为 <details> 保持一致。


45-48: 更新了事件处理并阻止事件冒泡

onClick 事件类型更新为 React.MouseEvent 并添加了 e.stopPropagation()。阻止事件冒泡是必要的,因为 <details> 元素的默认行为可能与组件定义的行为冲突。

这样可以确保点击事件被组件控制,而不是由浏览器的默认行为处理。


80-82: 将动画类条件应用于 details 元素

巧妙地将 motionName 有条件地应用于 details 元素,确保在支持 ::details-content 的浏览器上正确应用动画效果。

代码注释清晰地解释了为什么需要将动画类设置在 details 元素上,有助于维护者理解实现细节。


94-94: 将 header 属性类型从 HTMLDivElement 泛化为 HTMLElement

headerProps 的类型从特定的 HTMLDivElement 改为更通用的 HTMLElement,符合语义化 HTML 的变更。这允许属性正确应用于 <summary> 元素。


128-144: 使用 CSSMotion 处理不支持原生动画的浏览器

为不支持 ::details-content 伪元素的浏览器保留了 CSSMotion 实现,确保了向后兼容性。配置与原先实现一致,并且正确地使用了先前定义的 createPanelContent 函数。


146-161: 手动模拟内容生命周期管理

为支持 ::details-content 的浏览器实现了手动内容生命周期管理,这是一个聪明的方案,可以充分利用浏览器原生功能而不依赖 CSSMotion

代码逻辑清晰,覆盖了各种情况(激活、隐藏但不销毁、强制渲染、销毁),与 CSSMotion 的行为一致。

Comment on lines +35 to +42
// ? 用于判断浏览器是否支持::details-content 否则使用CSSMotion
const supportsDetailsContentSelector = useMemo(
() =>
typeof document !== 'undefined' && typeof document.createElement === 'function'
? CSS.supports('selector(details::details-content)')
: false,
[],
);
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

浏览器特性检测实现

使用 CSS.supports 检测浏览器对 ::details-content 伪元素的支持是一个优雅的渐进增强方案。代码还考虑了 SSR 场景,通过检查 document 是否存在来防止服务端执行错误。

不过,可能需要考虑在组件初始挂载后处理 SSR 水合差异(hydration mismatch)的问题。

需要验证此实现在 SSR 环境中是否会导致客户端与服务端渲染结果不一致。在服务端 supportsDetailsContentSelector 将始终为 false,而在客户端可能为 true,这可能导致水合错误。


🏁 Script executed:

#!/bin/bash
# 检查项目是否使用了支持 SSR 的框架和相关配置
grep -r "SSR\|server-side rendering\|hydration" --include="*.md" --include="*.js" --include="*.ts" --include="*.tsx" .
# 检查是否有处理 hydration mismatch 的代码
grep -r "suppressHydrationWarning\|useEffect.*hydration\|supportsDetailsContentSelector" --include="*.tsx" --include="*.ts" .

Length of output: 106462


注意 SSR 与水合不一致

目前 supportsDetailsContentSelector 在服务端渲染时恒为 false,而客户端可能为 true,会导致首屏渲染结果差异,引发 React 的水合(hydration)警告。

建议:

  • 将特性检测逻辑从初始渲染中移入 useEffect(或 useLayoutEffect),并通过 useState 保存检测结果;
  • 保持初始渲染(SSR 与客户端首屏)一致——初始值都设为 false,待客户端挂载后再更新为实际支持情况;
  • 如确实无法同步,可在对应元素上添加 suppressHydrationWarning,静默水合差异。

请根据项目的 SSR 配置和业务需求,调整组件实现,确保服务端与客户端渲染的一致性。

🤖 Prompt for AI Agents
In src/Panel.tsx around lines 35 to 42, the supportsDetailsContentSelector value
is determined during render, causing a mismatch between server-side rendering
(always false) and client-side detection (possibly true), which leads to React
hydration warnings. To fix this, initialize supportsDetailsContentSelector state
to false, then move the CSS.supports detection into a useEffect hook that
updates this state after the component mounts on the client. This ensures
consistent initial rendering on both server and client, preventing hydration
issues. Optionally, add suppressHydrationWarning to the affected elements if
minor mismatches remain unavoidable.

@IVLIU
Copy link
Author

IVLIU commented May 20, 2025

有冲突

fixed

@afc163
Copy link
Member

afc163 commented May 20, 2025

  • ci 挂了,看看
  • 收起的时候报错。
图片

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