Skip to content

feat: support tagRender in multiple picker#963

Merged
zombieJ merged 2 commits intoreact-component:masterfrom
QDyanbing:tag-render
Apr 17, 2026
Merged

feat: support tagRender in multiple picker#963
zombieJ merged 2 commits intoreact-component:masterfrom
QDyanbing:tag-render

Conversation

@QDyanbing
Copy link
Copy Markdown
Contributor

@QDyanbing QDyanbing commented Apr 17, 2026

Summary

  • add tagRender support for single picker multiple mode
  • export the tag render props and keep the default multiple tag rendering unchanged
  • add tests and a demo for custom multiple tag rendering

Testing

  • bun run lint
  • bunx tsc --noEmit
  • bun run compile
  • bun run test -- --coverage

Summary by CodeRabbit

发布说明

  • 新功能

    • 在多选模式中新增自定义标签渲染功能,支持通过 tagRender 回调自定义标签外观和交互。
    • 新增公开接口支持自定义标签属性的类型定义。
  • 文档

    • 更新示例代码展示自定义标签渲染的用法。
  • 测试

    • 添加测试覆盖自定义标签渲染功能。

@vercel
Copy link
Copy Markdown

vercel bot commented Apr 17, 2026

@QDyanbing 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
Copy Markdown

coderabbitai bot commented Apr 17, 2026

Warning

Rate limit exceeded

@QDyanbing has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 50 minutes and 14 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 50 minutes and 14 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a1630776-88d7-4878-867c-b0e98d5a49c2

📥 Commits

Reviewing files that changed from the base of the PR and between 3b4559b and 927d123.

📒 Files selected for processing (4)
  • docs/examples/multiple.tsx
  • src/PickerInput/Selector/SingleSelector/MultipleDates.tsx
  • src/PickerInput/SinglePicker.tsx
  • tests/multiple.spec.tsx

总览

该PR为SinglePicker组件添加了自定义标签渲染功能。通过引入CustomTagProps接口和tagRender属性,在多选模式下支持自定义标签的外观和关闭行为。该属性经由SingleSelectorMultipleDates组件层层传递,最终控制标签的渲染逻辑。

变更

内聚组/文件(s) 变更摘要
核心类型定义
src/PickerInput/SinglePicker.tsx, src/index.tsx
新增导出的CustomTagProps<DateType>接口,包含标签、值、禁用状态、关闭回调和可关闭标志等字段;在BasePickerProps中添加可选的tagRender属性;扩展公共类型导出。
Props 传递链路
src/PickerInput/Selector/SingleSelector/index.tsx, src/PickerInput/Selector/SingleSelector/MultipleDates.tsx
更新SingleSelectorPropsMultipleDatesProps的类型约束,将tagRender加入PickerPropsPick操作符;在组件中解构并向下传递tagRender属性;修改onClose处理器类型并调整renderItem逻辑以使用自定义标签渲染。
示例与测试
docs/examples/multiple.tsx, tests/multiple.spec.tsx
示例中展示两个周选择器实例使用自定义tagRender回调,根据日期条件渲染"锁定"标签或删除按钮;新增测试用例验证自定义标签渲染、条件关闭按钮显示和onChange回调触发。

代码审查工作量估算

🎯 3 (Moderate) | ⏱️ ~25 minutes

可能相关的 PR

  • feat: support prefix prop #884: 同样修改了src/PickerInput/Selector/SingleSelector/index.tsx中的SingleSelectorProps类型,添加新的prop(该PR添加prefix,本PR添加tagRender),存在类型定义冲突风险。

建议审核人

  • zombieJ
  • afc163

诗句

🐰 标签穿上新衣裳,
自定义渲染显风采,
Props 层层往下传,
多选时刻闪闪亮,
锁定按钮细心装!✨

🚥 Pre-merge checks | ✅ 2 | ❌ 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 (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确总结了主要更改:为多选模式下的 picker 添加 tagRender 支持,这与所有文件修改的核心目的一致。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 and usage tips.

Copy link
Copy Markdown
Contributor

@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 introduces a tagRender prop to the SinglePicker component, allowing for custom rendering of tags when the multiple selection mode is active. The changes include updating the MultipleDates and SingleSelector components to support the new prop, exporting the CustomTagProps interface, and adding relevant tests and documentation examples. Feedback suggests adding a safety check within the onClose callback in MultipleDates.tsx to prevent date removal when the component is disabled, ensuring robust behavior for custom tag implementations.

Comment thread src/PickerInput/Selector/SingleSelector/MultipleDates.tsx
Copy link
Copy Markdown

@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 (6)
docs/examples/multiple.tsx (2)

26-38: 多个 SinglePicker 共用同一个 singleRef

singleRef 被同时挂载到 4 个 SinglePicker 实例上,后挂载的会覆盖前者,ref.current 的语义不明确。虽然这是 demo 代码,但作为 tagRender 示例建议仅在需要的实例上保留 ref,避免误导使用者。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/multiple.tsx` around lines 26 - 38, The demo mistakenly mounts
the same React ref variable singleRef onto multiple SinglePicker instances so
later mounts overwrite earlier ones; update the JSX to only attach a ref to the
SinglePicker(s) that actually need it (e.g., keep singleRef on the instance
demonstrating tagRender or the one using onOpenChange) and remove the ref prop
from the other SinglePicker components, or create distinct refs (singleRef1,
singleRef2) if you need to control multiple pickers individually; adjust any
code that reads singleRef.current accordingly.

43-68: demo 中 tagRender 未使用 closable 字段。

既然在 CustomTagProps 中新增了 closable,建议 demo 示范如何根据 closable 决定是否显示 remove 按钮(而不是仅用业务逻辑 locked),让使用者更直观地了解该字段用途。此外,自定义 tag 的 <button> 建议加上 onMouseDown={e => e.preventDefault()},以避免点击 remove 时输入框失焦/重新打开面板,这也是更贴近实际使用的范例。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples/multiple.tsx` around lines 43 - 68, 在 tagRender 回调中使用
CustomTagProps 的 closable 字段来决定是否渲染删除按钮(而不是仅依赖业务变量 locked):检查传入的 closable
和当前逻辑中的 locked 并在两者都允许时才渲染 remove 按钮,调用现有的 onClose 保持不变;同时给自定义的 button 添加
onMouseDown={e => e.preventDefault()} 以防止点击 remove 时输入框失焦/面板重开,修改点集中在
tagRender、closable、locked、onClose 以及自定义 button 上。
src/PickerInput/Selector/SingleSelector/MultipleDates.tsx (2)

64-69: closable 的语义建议确认。

目前 closable = !disabled,在 disabled 为 true 时传 false。不过 disabledclosable 在用户侧语义并不完全一致(例如未来可能支持 tag 级别的 closable 控制)。当前实现作为首版没问题,但建议在 JSDoc 中明确 closable 当前仅受组件 disabled 影响,避免使用者基于更细粒度语义作假设。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/PickerInput/Selector/SingleSelector/MultipleDates.tsx` around lines 64 -
69, Add a JSDoc comment clarifying the current semantics of the closable flag:
explain that the local variable closable (in MultipleDates.tsx) is derived
solely from the component-level prop disabled (closable = !disabled) and that
tag-level or per-item closable control is not supported currently; update the
comment near the closable declaration (and mention related symbols like the
disabled prop and the onClose handler/CustomTagProps<DateType>) so users won't
assume finer-grained closable behavior in this first release.

62-82: 建议:tagRender 返回节点未包裹容器 & renderRest 未走自定义渲染。

两点建议,供取舍:

  1. 当提供 tagRender 时,返回值未包裹 selection-item 容器。这是符合“完全自定义”的常见设计,但需要在文档中明确说明 —— 使用者将失去默认的 title、mouseDown preventDefault(点击 tag 时输入焦点丢失)、以及 rc-picker-selection-item 相关样式。建议在 BasePickerProps.tagRender 的 JSDoc 中补充说明,或参考 antd Select 在外层追加 onMouseDown={e => e.preventDefault()} 的 wrapper。
  2. renderRest(+ N ... 折叠项)仍然使用默认 renderSelector,当 maxTagCount 触发折叠时,视觉风格会与自定义 tag 不一致,使用者可能会感到意外。可考虑在文档中说明此行为,或提供单独的自定义入口(例如 maxTagPlaceholder)。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/PickerInput/Selector/SingleSelector/MultipleDates.tsx` around lines 62 -
82, The tagRender return value is currently injected raw (so users lose default
container behaviors like rc-picker-selection-item styling, title, and
onMouseDown preventDefault) and renderRest still uses renderSelector which makes
folded "+ N" items visually inconsistent with custom tags; update docs and code
by either documenting this behavior in BasePickerProps.tagRender JSDoc
(explicitly state that tagRender must include its own wrapper and event
handlers) and/or wrap tagRender output with the default selection container and
onMouseDown prevention inside MultipleDates.renderItem, and add support for a
separate custom placeholder hook (e.g., maxTagPlaceholder) or route renderRest
through tagRender when maxTagCount folding occurs so the collapsed item can be
customized to match tagRender styling; reference tagRender, renderRest,
renderSelector, maxTagCount and BasePickerProps.tagRender when applying the
change.
src/PickerInput/SinglePicker.tsx (1)

39-45: CustomTagProps 接口定义清晰。

字段命名与 antd SelectCustomTagProps 对齐,便于使用者迁移认知。可选建议:为每个字段补充 JSDoc(尤其是 closabledisabled 的区别),提升 API 可发现性。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/PickerInput/SinglePicker.tsx` around lines 39 - 45, Add JSDoc comments to
the CustomTagProps interface fields to improve API discoverability: document
label, value, disabled, onClose, and closable in the interface declaration
(CustomTagProps<DateType>) and explicitly clarify the difference between
disabled and closable (e.g., disabled means the tag is non-interactive, closable
controls whether the close icon is shown/can trigger onClose). Keep the comments
concise and consistent with antd Select's CustomTagProps semantics so users can
map behavior easily.
tests/multiple.spec.tsx (1)

143-168: 测试覆盖核心路径,建议补充边界用例。

当前测试验证了自定义渲染与 onClose 触发 onChange 的主流程。可以考虑补充:

  • disabled 场景下 tagRender 收到的 disabled/closable 值是否符合预期。
  • 自定义 tagRendermaxTagCount 同时使用时的折叠(renderRest)行为(目前 MultipleDates.renderRest 仍走默认 renderSelector,未使用 tagRender,用户可能期望一致的外观)。
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/multiple.spec.tsx` around lines 143 - 168, Add tests covering two edge
cases: (1) verify tagRender receives correct disabled/closable flags and that
the close button is not rendered/clickable when the DayPicker or a specific date
is disabled (exercise DayPicker with multiple + disabled date(s) and assert the
tagRender props and that onClose/onChange are not invoked); (2) verify behavior
when maxTagCount is set so that MultipleDates.renderRest collapses tags using
the custom tagRender (not the default renderSelector) by rendering DayPicker
with multiple + tagRender + maxTagCount and asserting the rendered "rest" node
matches the custom tag appearance and that clicking the rest expands or triggers
expected callbacks; reference DayPicker, tagRender, MultipleDates.renderRest,
renderRest, renderSelector, disabled and closable in your assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/PickerInput/SinglePicker.tsx`:
- Around line 58-59: Fix the comment grammar for the tagRender prop in
SinglePicker.tsx: change "Only work when `multiple` is in used" to a consistent
and correct phrasing (e.g., "Only works when `multiple` is in use" or "Only used
when `multiple` is enabled") to match the style of the maxTagCount comment;
update the comment immediately above the tagRender?: (props:
CustomTagProps<DateType>) => React.ReactNode; declaration so both wording and
verb agreement ("works"/"used"/"enabled") are consistent with existing
annotations.

---

Nitpick comments:
In `@docs/examples/multiple.tsx`:
- Around line 26-38: The demo mistakenly mounts the same React ref variable
singleRef onto multiple SinglePicker instances so later mounts overwrite earlier
ones; update the JSX to only attach a ref to the SinglePicker(s) that actually
need it (e.g., keep singleRef on the instance demonstrating tagRender or the one
using onOpenChange) and remove the ref prop from the other SinglePicker
components, or create distinct refs (singleRef1, singleRef2) if you need to
control multiple pickers individually; adjust any code that reads
singleRef.current accordingly.
- Around line 43-68: 在 tagRender 回调中使用 CustomTagProps 的 closable
字段来决定是否渲染删除按钮(而不是仅依赖业务变量 locked):检查传入的 closable 和当前逻辑中的 locked 并在两者都允许时才渲染
remove 按钮,调用现有的 onClose 保持不变;同时给自定义的 button 添加 onMouseDown={e =>
e.preventDefault()} 以防止点击 remove 时输入框失焦/面板重开,修改点集中在
tagRender、closable、locked、onClose 以及自定义 button 上。

In `@src/PickerInput/Selector/SingleSelector/MultipleDates.tsx`:
- Around line 64-69: Add a JSDoc comment clarifying the current semantics of the
closable flag: explain that the local variable closable (in MultipleDates.tsx)
is derived solely from the component-level prop disabled (closable = !disabled)
and that tag-level or per-item closable control is not supported currently;
update the comment near the closable declaration (and mention related symbols
like the disabled prop and the onClose handler/CustomTagProps<DateType>) so
users won't assume finer-grained closable behavior in this first release.
- Around line 62-82: The tagRender return value is currently injected raw (so
users lose default container behaviors like rc-picker-selection-item styling,
title, and onMouseDown preventDefault) and renderRest still uses renderSelector
which makes folded "+ N" items visually inconsistent with custom tags; update
docs and code by either documenting this behavior in BasePickerProps.tagRender
JSDoc (explicitly state that tagRender must include its own wrapper and event
handlers) and/or wrap tagRender output with the default selection container and
onMouseDown prevention inside MultipleDates.renderItem, and add support for a
separate custom placeholder hook (e.g., maxTagPlaceholder) or route renderRest
through tagRender when maxTagCount folding occurs so the collapsed item can be
customized to match tagRender styling; reference tagRender, renderRest,
renderSelector, maxTagCount and BasePickerProps.tagRender when applying the
change.

In `@src/PickerInput/SinglePicker.tsx`:
- Around line 39-45: Add JSDoc comments to the CustomTagProps interface fields
to improve API discoverability: document label, value, disabled, onClose, and
closable in the interface declaration (CustomTagProps<DateType>) and explicitly
clarify the difference between disabled and closable (e.g., disabled means the
tag is non-interactive, closable controls whether the close icon is shown/can
trigger onClose). Keep the comments concise and consistent with antd Select's
CustomTagProps semantics so users can map behavior easily.

In `@tests/multiple.spec.tsx`:
- Around line 143-168: Add tests covering two edge cases: (1) verify tagRender
receives correct disabled/closable flags and that the close button is not
rendered/clickable when the DayPicker or a specific date is disabled (exercise
DayPicker with multiple + disabled date(s) and assert the tagRender props and
that onClose/onChange are not invoked); (2) verify behavior when maxTagCount is
set so that MultipleDates.renderRest collapses tags using the custom tagRender
(not the default renderSelector) by rendering DayPicker with multiple +
tagRender + maxTagCount and asserting the rendered "rest" node matches the
custom tag appearance and that clicking the rest expands or triggers expected
callbacks; reference DayPicker, tagRender, MultipleDates.renderRest, renderRest,
renderSelector, disabled and closable in your assertions.
🪄 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: 303be436-38a5-40f1-84ad-75b4c377880f

📥 Commits

Reviewing files that changed from the base of the PR and between d27127f and 3b4559b.

📒 Files selected for processing (6)
  • docs/examples/multiple.tsx
  • src/PickerInput/Selector/SingleSelector/MultipleDates.tsx
  • src/PickerInput/Selector/SingleSelector/index.tsx
  • src/PickerInput/SinglePicker.tsx
  • src/index.tsx
  • tests/multiple.spec.tsx

Comment thread src/PickerInput/SinglePicker.tsx Outdated
@codecov
Copy link
Copy Markdown

codecov bot commented Apr 17, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.81%. Comparing base (d27127f) to head (927d123).
⚠️ Report is 1 commits behind head on master.

Additional details and impacted files
@@           Coverage Diff           @@
##           master     #963   +/-   ##
=======================================
  Coverage   98.81%   98.81%           
=======================================
  Files          65       65           
  Lines        2691     2695    +4     
  Branches      722      749   +27     
=======================================
+ Hits         2659     2663    +4     
  Misses         29       29           
  Partials        3        3           

☔ 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.

@zombieJ zombieJ merged commit e3deedd into react-component:master Apr 17, 2026
7 of 8 checks passed
@QDyanbing QDyanbing deleted the tag-render branch April 17, 2026 07:36
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