-
Notifications
You must be signed in to change notification settings - Fork 138
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
base: master
Are you sure you want to change the base?
refactor: 重构collapse为details实现 #362
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
""" Walkthrough本次变更将折叠面板组件从基于 Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant Collapse
participant Panel (details)
participant PanelContent
User->>Collapse: 点击某面板
Collapse->>Collapse: React.startTransition(setActiveKey)
Collapse->>Panel: 传递 isActive, open
Panel->>Panel: 渲染 <details open={isActive}>
Panel->>PanelContent: 传递 isActive, forceRender
PanelContent->>PanelContent: 判断 isActive || forceRender
PanelContent-->>Panel: 渲染内容(动画或直接显示)
Poem
""" 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
src/PanelContent.tsxOops! 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. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
✨ Finishing Touches
🧪 Generate 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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
ci 挂了 |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #362 +/- ##
===========================================
+ Coverage 99.15% 100.00% +0.84%
===========================================
Files 5 5
Lines 118 118
Branches 43 42 -1
===========================================
+ Hits 117 118 +1
+ Misses 1 0 -1 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
fixed 少个包 |
收起动画丢了。 |
There was a problem hiding this 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 角色的必要性使用
details
和summary
元素后,这些元素已经具有原生的语义和辅助功能。可以考虑是否仍然需要设置role="tab"
、role="button"
和其他 ARIA 属性,因为这些可能与元素的原生语义冲突。HTML5 的
details
和summary
元素原生支持可访问性,无需额外的 ARIA 角色。Is it necessary to add ARIA roles to details and summary elements?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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 tsxLength 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.tsx
和src/Panel.tsx
)中作为回调使用。测试用例也验证了在点击时onItemClick
正确触发,并且在禁用或特定场景下,行为符合预期。- 从现有代码和测试来看,没有明显依赖点击事件冒泡的父组件逻辑。但由于
e.stopPropagation()
的作用会完全阻断事件冒泡,请您确认在业务场景下父组件或其他外部逻辑是否需要捕获同一事件进行额外处理。请根据具体业务逻辑,确认后续是否需要调整,以免破坏依赖事件冒泡的父组件的功能。
我在想有没有必要开个discussion讨论下这个问题 因此改造后的渲染流程如下 open = true时,content展现,然后高度过渡 所以我觉得需要讨论下这部分的实现,我先说下我的想法
个人上是更倾向方式1,这样的话,在高版本浏览器中,组件将变得足够简单,性能也将更上一层楼,仅做状态同步即可 |
1 可以的,我也倾向渐进式。 |
There was a problem hiding this 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
结构改为使用语义化的details
和summary
元素:
- 使用
details
作为根容器,通过open
属性控制展开状态- 使用
summary
作为标题容器- 根据条件渲染内容部分
这种修改充分利用了HTML的语义化结构,不仅提高了可访问性,还能利用浏览器原生行为。同时通过
open={isActive}
保持了对组件状态的受控特性。可能会影响动画效果,需要确认:
- 动画效果是否已恢复
details
元素的原生展开/折叠行为是否与CSSMotion
兼容
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 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.supports
API检测浏览器是否支持::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
函数和基于浏览器特性的条件渲染逻辑:
- 抽象出内容创建逻辑到单独的函数
- 根据浏览器支持情况决定使用
CSSMotion
还是原生CSS控制内容显示- 模拟CSSMotion的生命周期管理逻辑
这种设计能够在现代浏览器中利用原生功能实现更好的性能,同时为不支持的浏览器提供良好的回退方案。代码结构清晰,条件逻辑易于理解。
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; | ||
} |
There was a problem hiding this comment.
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.
或许可以移除CSSMotion,根据是否支持 |
有冲突 |
@IVLIU is attempting to deploy a commit to the React Component Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this 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
状态映射到details
的open
属性,确保了组件状态与 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
📒 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
的行为一致。
src/Panel.tsx
Outdated
// ? 用于判断浏览器是否支持::details-content 否则使用CSSMotion | ||
const supportsDetailsContentSelector = useMemo( | ||
() => | ||
typeof document !== 'undefined' && typeof document.createElement === 'function' | ||
? CSS.supports('selector(details::details-content)') | ||
: false, | ||
[], | ||
); |
There was a problem hiding this comment.
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.
fixed |
ping @IVLIU |
f8ac9ab
to
5026c13
Compare
There was a problem hiding this 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)
70-72
: 确认motionName
样式是否仍然生效
motionName
原用于驱动CSSMotion
的动画 class。
现在将其直接附加到<details>
,若相关 CSS 已迁移到基于[open]
/::details-content
的动画,可能出现多余或冲突的 class。请验证:
- 动画是否按预期触发
- 未使用到的 motionName 是否可移除,减少无用样式
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/Collapse.tsx
(1 hunks)src/Panel.tsx
(5 hunks)src/PanelContent.tsx
(2 hunks)src/interface.ts
(2 hunks)tests/index.spec.tsx
(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- tests/index.spec.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- src/Collapse.tsx
- src/PanelContent.tsx
- src/interface.ts
🔇 Additional comments (2)
src/Panel.tsx (2)
7-8
: API 变更:Ref 类型已从HTMLDivElement
➜HTMLDetailsElement
这属于破坏性修改。请检查:
- 外部库 / 应用是否直接通过
ref
操作面板节点属性,如scrollHeight
;- TypeScript 声明文件与文档是否同步更新。
如有必要,在下一个次版本注明 breaking change。
92-115
:❓ Verification inconclusive
SSR 首屏渲染仍存在水合不一致风险
open
属性直接由isActive
受控。若服务器首屏渲染为open={false}
,客户端首帧即因浏览器默认行为或特性检测结果改变而变为true
,React 会抛出 hydration 警告。
建议:
- 保持首屏一致:初始
isActive
状态宜在 Collapse 级别通过useState
与useEffect
延后切换;- 或在
<details>
上添加suppressHydrationWarning
,同时在挂载后同步open
状态;- 在 E2E / SSR 用例中增加覆盖。
请确认现有实现是否已在其他文件解决,如未覆盖,上述方案可避免生产 SSR 报错。
注意:SSR 首屏渲染仍存在水合不一致风险
<details>
的open
属性直接由isActive
受控。如果服务端首屏渲染出于关闭状态(open={false}
),客户端第一帧因浏览器默认行为或特性检测结果自动展开(open=true
),React 会抛出 hydration 警告。建议:
- 在 Collapse 组件层面,通过
useState
+useEffect
延后同步isActive
,确保首屏渲染前后行为一致;- 或者在
<details>
上添加suppressHydrationWarning
,并在挂载后用副作用(useEffect
)再同步open
;- 补充 E2E/SSR 场景的测试用例,覆盖不同初始展开状态。
请确认当前实现中是否已有类似处理,如尚未覆盖上述方案,请尽快补充以避免生产环境 SSR 水合报错。
src/Panel.tsx
Outdated
onClick: (e: React.MouseEvent) => { | ||
onItemClick?.(panelKey); | ||
e.stopPropagation(); | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
阻止 <summary>
默认行为,避免双重状态切换
点击位于 <summary>
内部的元素时,浏览器会先执行 <details>
的默认展开 / 折叠,再执行 React 更新逻辑,导致「闪动」及状态竞争;尤其在受控模式下容易出现不一致。
应同时 preventDefault
与 stopPropagation
,并在之后触发 onItemClick
。
- onClick: (e: React.MouseEvent) => {
- onItemClick?.(panelKey);
- e.stopPropagation();
- },
+ onClick: (e: React.MouseEvent) => {
+ e.preventDefault(); // 阻止原生 toggle
+ e.stopPropagation(); // 阻止冒泡
+ onItemClick?.(panelKey);
+ },
📝 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.
onClick: (e: React.MouseEvent) => { | |
onItemClick?.(panelKey); | |
e.stopPropagation(); | |
}, | |
onClick: (e: React.MouseEvent) => { | |
e.preventDefault(); // 阻止原生 toggle | |
e.stopPropagation(); // 阻止冒泡 | |
onItemClick?.(panelKey); | |
}, |
🤖 Prompt for AI Agents
In src/Panel.tsx around lines 35 to 38, the onClick handler inside the <summary>
element only calls e.stopPropagation(), which does not prevent the default
toggle behavior of <details>. To fix the flickering and state conflicts, add
e.preventDefault() before e.stopPropagation(), and then call onItemClick. This
will stop the default expand/collapse action and avoid double state changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
看看这个?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@afc163 CodeRabbit 提出的建议是正确的!这个问题很重要,因为在使用原生 <details>
元素的重构版本中:
问题分析:
- 当前代码只调用了
e.stopPropagation()
但缺少e.preventDefault()
<summary>
的默认行为是切换父级<details>
的open
属性- 在受控组件中,React 通过 props 管理
open
状态 - 没有
preventDefault()
会导致原生切换和 React 状态更新同时发生,造成状态竞争和闪烁
修复建议:
onClick: (e: React.MouseEvent) => {
e.preventDefault(); // 阻止原生 toggle 行为
e.stopPropagation(); // 阻止事件冒泡
onItemClick?.(panelKey); // React 控制状态更新
},
这个修复确保了:
- 阻止浏览器的默认展开/折叠行为
- 完全由 React 控制状态变化
- 避免双重切换导致的闪烁和不一致
这个修改对于从 div 实现迁移到原生 <details>
实现的稳定性至关重要。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
看看这个?
已处理
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
…llapse into refactor/native-details-element
|
||
&[open]::details-content { | ||
block-size: auto; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
兼容性如何?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
兼容性如何?
这只是demo实现,ant实现上考虑下css兼容吧
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
有方案么,最好提前考虑起来。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
有方案么,最好提前考虑起来。
- 兼容
::detail-content
的情况使用Panel
的className编写动画,openMotion.motionName
传入一个空实现 - 不兼容
::detail-content
的情况则使用openMotion.motionName
编写动画
你看下是不是可行,::detail-content
兼容性确实比较差
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
我尝试引入startTransition,编译报错,需要升级哪里吗?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
A refactor of the Collapse component to use native HTML <details>
and <summary>
for better semantics, accessibility, and simpler state handling.
- Replaced custom
<div>
panels andCSSMotion
with<details>
and<summary>
structure. - Updated tests and snapshots to match the new markup.
- Simplified rendering in
PanelContent
, adjusted types ininterface.ts
, and wrapped state updates instartTransition
. - Added CSS-based transitions in
assets/index.less
.
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
File | Description |
---|---|
tests/index.spec.tsx | Removed old inactive-panel assertions; tests now expect no inactive panel. |
tests/snapshots/index.spec.tsx.snap | Updated snapshot to use <details> /<summary> tags. |
src/interface.ts | Changed ref and CollapsePanelProps to use HTMLDetailsElement ; tightened style type. |
src/PanelContent.tsx | Removed useState /useEffect ; using inline display style to show/hide content. |
src/Panel.tsx | Wrapped each panel in <details open={isActive}> , replaced header <div> with <summary> , removed CSSMotion . |
src/Collapse.tsx | Wrapped setActiveKey in React.startTransition to sync state with native toggle. |
assets/index.less | Added CSS transitions targeting details content and placeholders for view-transition. |
Comments suppressed due to low confidence (1)
tests/index.spec.tsx:88
- After switching to
<details>
, it would be valuable to assert theopen
attribute on the<details>
element when active (and its absence when inactive) to ensure semantic toggling behavior is covered.
expect(collapse.container.querySelector('.rc-collapse-panel-inactive')).toBe(null);
&::details-content { | ||
block-size: 0; | ||
transition: block-size 0.6s, content-visibility 0.6s; | ||
transition-behavior: allow-discrete; | ||
} | ||
|
||
&[open]::details-content { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The CSS pseudo-element ::details-content
isn't part of the standard and won't target actual <details>
content. Consider wrapping the panel body in a dedicated element (e.g., .rc-collapse-content
) and applying transitions to that selector instead.
&::details-content { | |
block-size: 0; | |
transition: block-size 0.6s, content-visibility 0.6s; | |
transition-behavior: allow-discrete; | |
} | |
&[open]::details-content { | |
> .rc-collapse-content { | |
block-size: 0; | |
transition: block-size 0.6s, content-visibility 0.6s; | |
transition-behavior: allow-discrete; | |
} | |
&[open] > .rc-collapse-content { |
Copilot uses AI. Check for mistakes.
// ::view-transition-old(root), /* 旧视图*/ | ||
// ::view-transition-new(root) { /* 新视图*/ | ||
// animation-duration: 0.6s; | ||
// } | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] This commented-out view-transition snippet appears stale. Removing or relocating it behind a feature flag will keep the stylesheet clearer.
// ::view-transition-old(root), /* 旧视图*/ | |
// ::view-transition-new(root) { /* 新视图*/ | |
// animation-duration: 0.6s; | |
// } |
Copilot uses AI. Check for mistakes.
@@ -79,16 +82,16 @@ const CollapsePanel = React.forwardRef<HTMLDivElement, CollapsePanelProps>((prop | |||
); | |||
|
|||
// ======================== HeaderProps ======================== | |||
const headerProps: React.HTMLAttributes<HTMLDivElement> = { | |||
const headerProps: React.HTMLAttributes<HTMLElement> = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[nitpick] Since headerProps
are spread onto a <summary>
element, using React.HTMLAttributes<HTMLSummaryElement>
would give you more precise TypeScript support.
const headerProps: React.HTMLAttributes<HTMLElement> = { | |
const headerProps: React.HTMLAttributes<HTMLSummaryElement> = { |
Copilot uses AI. Check for mistakes.
There was a problem hiding this 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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
docs/examples/_util/motionUtil.ts
(1 hunks)src/Panel.tsx
(5 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- src/Panel.tsx
@@ -6,7 +6,7 @@ import type { | |||
|
|||
const getCollapsedHeight: MotionEventHandler = () => ({ height: 0, opacity: 0 }); | |||
const getRealHeight: MotionEventHandler = (node) => ({ height: node.scrollHeight, opacity: 1 }); | |||
const getCurrentHeight: MotionEventHandler = (node) => ({ height: node.offsetHeight }); | |||
const getCurrentHeight: MotionEventHandler = (node) => ({ height: node?.offsetHeight ?? 0 }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
可选链可能触发 TS18048 编译错误
MotionEventHandler
的签名中,node
参数通常被声明为 HTMLElement
,并未包含 null | undefined
。在严格空检查开启的项目中,对一个非可空类型使用 ?.
会被 TypeScript 报错(TS18048: “The left-hand side of an optional chain operation does not include ‘null’ or ‘undefined’”)。
建议两种修复思路,任选其一:
- 保持函数签名不变,改用三元判断:
-const getCurrentHeight: MotionEventHandler = (node) => ({ height: node?.offsetHeight ?? 0 });
+const getCurrentHeight: MotionEventHandler = (node) => ({ height: node ? node.offsetHeight : 0 });
- 若确有传入
null/undefined
的场景,则在参数层面显式放宽类型:
-const getCurrentHeight: MotionEventHandler = (node) => ({ height: node?.offsetHeight ?? 0 });
+const getCurrentHeight: MotionEventHandler = (node?: HTMLElement | null) => ({
+ height: node?.offsetHeight ?? 0,
+});
请根据实际调用情况选择,以确保通过 CI 并避免隐藏的空值问题。
📝 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.
const getCurrentHeight: MotionEventHandler = (node) => ({ height: node?.offsetHeight ?? 0 }); | |
// Option 1: keep the signature and use a ternary check | |
const getCurrentHeight: MotionEventHandler = (node) => ({ | |
height: node ? node.offsetHeight : 0, | |
}); |
const getCurrentHeight: MotionEventHandler = (node) => ({ height: node?.offsetHeight ?? 0 }); | |
// Option 2: relax the parameter type to include null/undefined | |
const getCurrentHeight: MotionEventHandler = (node?: HTMLElement | null) => ({ | |
height: node?.offsetHeight ?? 0, | |
}); |
🤖 Prompt for AI Agents
In docs/examples/_util/motionUtil.ts at line 9, the use of optional chaining on
the parameter 'node' causes a TS18048 error because 'node' is typed as
non-nullable HTMLElement. To fix this, either remove the optional chaining and
use a ternary check to handle potential null or undefined values while keeping
the parameter type unchanged, or update the function signature to explicitly
allow 'node' to be null or undefined if such cases occur. Choose the approach
based on actual usage to ensure type safety and pass CI.
关联antd ant-design/ant-design#48974
Summary by CodeRabbit
<details>
和<summary>
结构,提升可访问性与语义化。