menu icon indicating copy to clipboard operation
menu copied to clipboard

feat: Support custom rendering

Open meet-student opened this issue 6 months ago • 3 comments

中文版模板 / Chinese template

🤔 This is a ...

  • [x] 🆕 New feature
  • [ ] 🐞 Bug fix
  • [ ] 📝 Site / documentation improvement
  • [ ] 📽️ Demo improvement
  • [ ] 💄 Component style improvement
  • [ ] 🤖 TypeScript definition improvement
  • [ ] 📦 Bundle size optimization
  • [ ] ⚡️ Performance optimization
  • [ ] ⭐️ Feature enhancement
  • [ ] 🌐 Internationalization
  • [ ] 🛠 Refactoring
  • [ ] 🎨 Code style optimization
  • [ ] ✅ Test Case
  • [ ] 🔀 Branch merge
  • [ ] ⏩ Workflow
  • [ ] ⌨️ Accessibility improvement
  • [ ] ❓ Other (about what?)

🔗 Related Issues

💡 Background and Solution

  • The specific problem to be addressed.
  • List the final API implementation and usage if needed.
  • If there are UI/interaction changes, consider providing screenshots or GIFs.

📝 Change Log

  • Read Keep a Changelog! Track your changes, like a cat tracks a laser pointer.
  • Describe the impact of the changes on developers, not the solution approach.
  • Reference: https://ant.design/changelog
Language Changelog
🇺🇸 English Support custom rendering
🇨🇳 Chinese Support custom rendering

Summary by CodeRabbit

  • 新功能
    • 增加 Menu 的 itemRender 属性,支持自定义菜单项、子菜单、分组与分割线渲染;示例新增演示项并展示将菜单项包装为外链及添加尾部分割线的用法。
  • 文档
    • 在 API 文档中补充 itemRender 的说明、签名与默认行为。
  • 测试
    • 新增测试覆盖自定义渲染场景,验证菜单项被正确包装为外链。
  • 重构/样式
    • 若干内部渲染路径与格式调整,外显行为保持一致。

meet-student avatar Aug 10 '25 15:08 meet-student

Walkthrough

为 Menu 引入可自定义的 itemRender 渲染回调,并将其类型与上下文贯穿到 Menu、SubMenu、MenuItem、MenuItemGroup、Divider、类型定义、示例与测试中;示例与测试新增用例将 item 包裹为外链。

Changes

Cohort / File(s) Summary
类型与上下文
src/interface.ts, src/context/MenuContext.tsx
新增导出类型 ItemRenderType,在 ItemSharedPropsMenuContextProps 中加入可选 itemRender
Menu:入口与转发
src/Menu.tsx
MenuProps 中新增 itemRender?: ItemRenderType,从 props 解构并通过 MenuContextProvider 转发;调整部分 useMemo 依赖。
菜单项渲染:Item
src/MenuItem.tsx
从 props 与上下文合并 itemRender,在渲染前调用 mergedItemRender(renderNode, { item: { type: 'item', ... }, keys, eventOpt }) 并用返回值替换渲染节点;过滤传入子组件的辅助 props。
菜单组渲染:Group
src/MenuItemGroup.tsx
接收并合并 prop/context 的 itemRendereventOpt,在非 measure 路径对 childList 调用 itemRender(childList, { item: { type: 'group', ... }, keys })
子菜单渲染:SubMenu
src/SubMenu/index.tsx
支持从 props 接收 itemRendereventOpt,在构建 childList 后通过 itemRender 转换 childList 节点并使用返回值。
分隔线:Divider
src/Divider.tsx
接收 prop/context itemRender 并合并;构建 renderNode 后可通过 itemRender(renderNode, { item: { type: 'divider', ... }, keys, eventOpt }) 转换;组件签名改为接收单一 props 参数。
工具与格式化
src/utils/nodeUtil.tsx, src/utils/commonUtil.ts
向合并组件传递额外 eventOpt,并对部分额外内容渲染做小幅格式/单行化调整,功能保持一致。
示例与文档
docs/examples/items.tsx, README.md
示例新增 itemRender 用例(对 type==='item' 的节点包裹外链)并新增示例项;README 增加 itemRender API 文档。
测试
tests/MenuItem.spec.tsx
新增测试验证 itemRender 将 item originNode 包裹为外链并检查 href(文件中出现重复测试插入)。

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Dev as 开发者
  participant Menu as Menu
  participant Context as MenuContext
  participant Component as 子组件(Item/Group/SubMenu/Divider)
  participant itemRender as itemRender 回调
  participant Renderer as 渲染管线

  Dev->>Menu: 提供 items 与 itemRender
  Menu->>Context: 将 itemRender 注入上下文
  Renderer->>Component: 构建 originNode / childList
  alt itemRender 存在(prop 或 context)
    Component->>itemRender: itemRender(originNode/childList, { item, keys, eventOpt })
    itemRender-->>Component: customNode
    Component-->>Renderer: 返回 customNode
  else 无 itemRender
    Component-->>Renderer: 返回 originNode
  end
  Renderer-->>Menu: 完整节点树
  Menu-->>Dev: 渲染完成

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

注意可能需要额外关注:

  • src/MenuItem.tsxsrc/MenuItemGroup.tsxsrc/SubMenu/index.tsxsrc/Divider.tsx 中构造传入 itemRender 的元数据(type、eventOpt、keys)是否一致且类型安全。
  • src/Menu.tsx 中 useMemo 依赖调整对重渲染或性能的影响。
  • tests/MenuItem.spec.tsx 中重复测试应去重并确认断言覆盖正确。

Possibly related PRs

  • react-component/menu#740 — 修改 src/utils/nodeUtil.tsx 中合并项构造逻辑,与本次对同一文件和合并传参的改动高度相关。

Suggested reviewers

  • zombieJ

Poem

小兔叼来一行 render,原生节点换新装,
外层轻裹成链接,菜单点滴更自如。
回调穿针又缝线,子树悄然换模样,
浅笑藏在 props 里,点击生风向。 🐰✨

Pre-merge checks and finishing touches

❌ 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%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题简洁明了地反映了PR的主要目标:支持自定义渲染。虽然未涵盖所有细节,但准确总结了核心功能改动。
Linked Issues check ✅ Passed PR完整实现了Issue #54289的所有核心要求:实现了itemRender API、支持包裹Menu.Item节点、支持与Link/Upload等组件集成、解决sticky布局样式问题。
Out of Scope Changes check ✅ Passed 所有改动均与itemRender功能的实现直接相关,包括类型定义、组件改造、上下文传递、文档更新和测试补充,无超出范围的变更。
✨ Finishing touches
  • [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • [ ] Create PR with unit tests
  • [ ] Post copyable unit tests in a comment

📜 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 b2981dd97b7ea2438e53aed80732a9e5e76f7048 and 478dcf8f0002c2b62cd204c1355887452ac841f2.

📒 Files selected for processing (3)
  • src/MenuItem.tsx (5 hunks)
  • src/MenuItemGroup.tsx (1 hunks)
  • src/SubMenu/index.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/MenuItemGroup.tsx
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-23T06:01:34.975Z
Learnt from: codewizardTM
Repo: react-component/menu PR: 818
File: src/Menu.tsx:415-431
Timestamp: 2025-10-23T06:01:34.975Z
Learning: In src/Menu.tsx focus logic, defaultFocusKey should only use keys from focusableElements/key2element, not from childList.find(), because childList items might not be rendered in DOM (e.g., in overflow menu) which would cause focus to fail.

Applied to files:

  • src/SubMenu/index.tsx
  • src/MenuItem.tsx
📚 Learning: 2025-10-23T07:19:07.493Z
Learnt from: codewizardTM
Repo: react-component/menu PR: 818
File: src/Menu.tsx:415-431
Timestamp: 2025-10-23T07:19:07.493Z
Learning: In src/Menu.tsx focus logic, when validating candidate focus keys (selected/active/default), must check against focusableElements (not just key2element) to exclude disabled items. Use focusableKeys = new Set(focusableElements.map(el => element2key.get(el))) and validate with focusableKeys.has(k), otherwise disabled selected items will cause focus to fail without fallback.

Applied to files:

  • src/MenuItem.tsx
🧬 Code graph analysis (2)
src/SubMenu/index.tsx (1)
src/interface.ts (1)
  • ItemType (79-79)
src/MenuItem.tsx (1)
src/context/MenuContext.tsx (1)
  • MenuContext (69-69)
🔇 Additional comments (1)
src/MenuItem.tsx (1)

92-94: itemRender 的双源合并逻辑正确

从 props 和 context 获取 itemRender 并通过 propItemRender || contextItemRender 合并的模式是合理的,允许在 Menu 级别统一配置或在单个 MenuItem 上覆盖。

Also applies to: 117-120


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.

coderabbitai[bot] avatar Aug 10 '25 15:08 coderabbitai[bot]

Codecov Report

:x: Patch coverage is 84.00000% with 4 lines in your changes missing coverage. Please review. :white_check_mark: Project coverage is 99.19%. Comparing base (3ba3f98) to head (364df90).

Files with missing lines Patch % Lines
src/MenuItemGroup.tsx 66.66% 1 Missing and 1 partial :warning:
src/Divider.tsx 88.88% 1 Missing :warning:
src/SubMenu/index.tsx 80.00% 1 Missing :warning:
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #792      +/-   ##
==========================================
- Coverage   99.72%   99.19%   -0.54%     
==========================================
  Files          26       26              
  Lines         727      743      +16     
  Branches      199      209      +10     
==========================================
+ Hits          725      737      +12     
- Misses          2        5       +3     
- Partials        0        1       +1     

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

:rocket: New features to boost your workflow:
  • :snowflake: Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • :package: JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

codecov[bot] avatar Aug 11 '25 15:08 codecov[bot]

No dependency changes detected. Learn more about Socket for GitHub.

👍 No dependency changes detected in pull request

socket-security[bot] avatar Sep 02 '25 05:09 socket-security[bot]