Skip to content

feat: support classNames/styles semantic DOM API#51

Merged
zombieJ merged 6 commits into
react-component:masterfrom
aojunhao123:feat/semantic-dom-api
Jun 30, 2026
Merged

feat: support classNames/styles semantic DOM API#51
zombieJ merged 6 commits into
react-component:masterfrom
aojunhao123:feat/semantic-dom-api

Conversation

@aojunhao123

@aojunhao123 aojunhao123 commented Jun 30, 2026

Copy link
Copy Markdown
Collaborator
image

Summary

  • Add a semantic DOM API: classNames and styles props with root / item / groupHeader slots (ListySemanticName, ListyClassNames, ListyStyles exported from the entry).
  • Wire the slots through both render modes — RawList and VirtualList, including the sticky group header in useStickyGroupHeader — so the two modes stay at parity.
  • Add tests/semantic.test.tsx covering slot application across both modes.
  • Tooling: ignore .claude worktrees in .gitignore and jest.config.js. jest-haste-map crawls the filesystem (not .gitignore), so a nested .claude worktree copy collided on the duplicate package name and crashed the whole suite with dupMap.get is not a function.

Test plan

  • pnpm test — 4 suites / 38 tests pass
  • Pass classNames/styles to <Listy> in virtual mode and confirm root/item/groupHeader (incl. sticky header) pick up the class/style
  • Same check in non-virtual (raw) mode for parity

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • 列表组件新增语义化样式配置,可分别为容器、分组标题和条目设置自定义类名与内联样式。
    • 分组标题在固定吸顶场景下也支持自定义样式,并保持原有布局表现。
  • Documentation
    • 新增语义化样式示例页面,方便查看不同渲染模式下的效果与用法。

Add root/item/groupHeader semantic slots via `classNames` and `styles`
props, wired through both RawList and VirtualList (including the sticky
group header) so the two render modes stay at parity.
@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

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

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jun 30, 2026

Copy link
Copy Markdown

Review Change Stack

概览

Listy 组件新增语义化样式支持:定义 ListySemanticName/ListyClassNames/ListyStyles 类型,并通过 classNames/styles props 将自定义类名与内联样式透传至 rootitemgroupHeader 三个语义节点,同时覆盖虚拟滚动模式下的吸顶表头克隆节点。

变更

语义化样式支持

层级 / 文件 摘要
语义类型与 Props 接口定义
src/List.tsx, src/GroupHeader.tsx, src/index.ts
List.tsx 中新增 ListySemanticNameListyClassNamesListyStyles 类型,并分别加入 ListyPropsListComponentPropsGroupHeaderProps 新增可选 className 字段;src/index.ts 补充三个新类型的公开导出。
GroupHeader className 透传实现
src/GroupHeader.tsx
GroupHeader 解构外部 classNamecustomClassName,通过 clsx 将其追加到原有基类与 sticky/fixed 条件类之后。
useStickyGroupHeader 吸顶表头样式透传
src/VirtualList/useStickyGroupHeader.tsx
StickyHeaderParams 新增 headerClassName/headerStyle 字段;extraRender 中固定 GroupHeaderstyle{ top } 扩展为 { ...headerStyle, top },依赖数组同步更新。
RawList 各节点 classNames/styles 应用
src/RawList/index.tsx
解构 classNames/styles,根容器 className 改为 clsx(prefixCls, classNames?.root) 并合入 styles?.rootrenderItem 使用 clsx 合并 item 类名并展开 styles?.itemGroupHeader 新增 className/style 透传。
VirtualList 各节点 classNames/styles 应用
src/VirtualList/index.tsx
解构 classNames/styles 并传入 useStickyGroupHeaderrenderHeaderRowGroupHeader 追加 className/styleRcVirtualList 根元素与普通行包裹 div 均同步应用语义样式。
语义 DOM 测试、文档示例及工具配置
tests/semantic.test.tsx, docs/demos/semantic.md, docs/examples/semantic.tsx, .gitignore
新增语义 DOM 断言测试,覆盖原生/虚拟/sticky 克隆三类场景;新增演示文档及示例页面;.gitignore 追加 .claude 忽略规则。

估算代码审查工作量

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

可能相关的 PR

  • react-component/listy#43:同样修改了 useStickyGroupHeader 的参数与 extraRenderGroupHeader 的渲染逻辑。
  • react-component/listy#45:引入/重构了 GroupHeader 组件,与本 PR 对 GroupHeaderProps.className 的扩展直接相关。
  • react-component/listy#50:同样修改了 StickyHeaderParamsVirtualList/index.tsx 中 sticky 表头的渲染逻辑,存在代码级重叠。

建议审查者

  • zombieJ

小诗

🐇 语义插槽已就位,
root、item、groupHeader 齐,
classNames 与 styles 并肩行,
sticky 表头也穿新衣。
小兔敲键乐悠悠~ 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 标题准确概括了本次为 Listy 增加 classNames/styles 语义化 DOM API 的主要改动。
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with 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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

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

Copy link
Copy Markdown
Contributor

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 introduces support for semantic styling in the Listy component by adding classNames and styles props, allowing customization of the root, item, and groupHeader elements across both native and virtual list implementations. It also includes comprehensive test coverage for these changes. Regarding the feedback, in useStickyGroupHeader.tsx, the dynamically calculated top style property should be placed after spreading headerStyle to ensure it is not overridden by custom styles, which would break the sticky header positioning.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread src/VirtualList/useStickyGroupHeader.tsx Outdated
@codecov

codecov Bot commented Jun 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (feab9ab) to head (b7e67b5).

Additional details and impacted files
@@            Coverage Diff            @@
##            master       #51   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files            8         8           
  Lines          211       211           
  Branches        63        62    -1     
=========================================
  Hits           211       211           

☔ View full report in Codecov by Harness.
📢 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/semantic.test.tsx (1)

186-215: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

改成走真实的 Listy / VirtualList 渲染路径来测 sticky clone。

这里直接调用 useStickyGroupHeader() 并手动执行 extraRender,绕过了 src/VirtualList/index.tsxclassNames.groupHeader / styles.groupHeader 透传给 hook 的那层集成。即使实际组件漏传了 headerClassNameheaderStyle,这个用例也还是会通过,覆盖不到这次 PR 最关键的接线。建议改成渲染开启 sticky 的 <Listy />,再断言 portal 里的固定表头。

🤖 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 `@tests/semantic.test.tsx` around lines 186 - 215, The current sticky clone
test bypasses the real Listy/VirtualList integration by calling
useStickyGroupHeader directly, so it won’t catch missing
headerClassName/headerStyle wiring from VirtualList. Update this test to render
the actual Listy or VirtualList path with sticky enabled, using the real props
flow through VirtualList/index.tsx and useStickyGroupHeader, then assert the
pinned clone in the portal contains the expected groupHeader class and style.
🤖 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 `@src/RawList/index.tsx`:
- Around line 62-69: `RawList` 的 `style` 合并顺序有问题,`styles?.item` 可能覆盖 sticky
分组下的内部 `scrollMarginTop`,导致滚动定位失效;请调整 `RawList/index.tsx` 中该对象展开顺序,让内部计算出的
`scrollMarginTop` 在 `sticky && groupKey !== undefined` 时保持最高优先级,并确保
`styles?.item` 仍可提供其他样式但不能覆盖这个偏移量。

In `@src/VirtualList/useStickyGroupHeader.tsx`:
- Around line 110-111: The cloned sticky group header is letting external
headerStyle.top override the internally computed sticky offset, which breaks the
push-off logic. Update useStickyGroupHeader so the calculated top value from the
hook stays authoritative in the header clone, and only merge the rest of
headerStyle’s custom styles without allowing its top to replace the internal
positioning.

---

Nitpick comments:
In `@tests/semantic.test.tsx`:
- Around line 186-215: The current sticky clone test bypasses the real
Listy/VirtualList integration by calling useStickyGroupHeader directly, so it
won’t catch missing headerClassName/headerStyle wiring from VirtualList. Update
this test to render the actual Listy or VirtualList path with sticky enabled,
using the real props flow through VirtualList/index.tsx and
useStickyGroupHeader, then assert the pinned clone in the portal contains the
expected groupHeader class and style.
🪄 Autofix (Beta)

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: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 75b213c4-7fc8-463c-8589-f8ad4b0a0d3a

📥 Commits

Reviewing files that changed from the base of the PR and between feab9ab and 4440202.

📒 Files selected for processing (9)
  • .gitignore
  • jest.config.js
  • src/GroupHeader.tsx
  • src/List.tsx
  • src/RawList/index.tsx
  • src/VirtualList/index.tsx
  • src/VirtualList/useStickyGroupHeader.tsx
  • src/index.ts
  • tests/semantic.test.tsx

Comment thread src/RawList/index.tsx
Comment thread src/VirtualList/useStickyGroupHeader.tsx Outdated
@aojunhao123
aojunhao123 force-pushed the feat/semantic-dom-api branch from 15bdd5b to 4f48026 Compare June 30, 2026 08:00
Demonstrate the classNames/styles slots (root/item/groupHeader) with a
virtual on/off toggle showing the same slots apply in both render modes.
In sticky grouped mode RawList sets scroll-margin-top on items so
scrollTo({ key }) lands them clear of the position:sticky group header
(the header height is measured live into the --*-item-scroll-margin-top
var). It's internal scrollTo machinery, not a style knob, so it must win
over styles.item — otherwise a user-supplied scrollMarginTop breaks the
scroll landing and the item ends up hidden behind the header.
@aojunhao123
aojunhao123 force-pushed the feat/semantic-dom-api branch from 4f48026 to 7fce56b Compare June 30, 2026 08:46
styles.item.scrollMarginTop must not override the sticky scrollTo offset,
and styles.groupHeader.top must not override the computed sticky-clone top.
The existing slot tests only asserted coexistence, so they stayed green even
with the override bug present; these two assert the internal value wins.

@zombieJ zombieJ left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

LGTM

@zombieJ
zombieJ merged commit f6345b8 into react-component:master Jun 30, 2026
8 of 9 checks passed
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