Skip to content

Conversation

@IKEYCY
Copy link
Contributor

@IKEYCY IKEYCY commented Dec 1, 2025

PR

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • Added right-click (contextmenu) trigger support for the dropdown component and demo scenario.
  • Documentation

    • Updated demos and docs to show contextmenu as a supported trigger (stable since 3.28.0) and added a demo with icon-based menu items.
  • Bug Fixes / Behavior

    • Made contextmenu open/close timing match click (no delay) for consistent interactions.
  • Tests

    • Added tests covering contextmenu interactions and visibility expectations.

✏️ Tip: You can customize this high-level summary in your review settings.

@github-actions github-actions bot added the enhancement New feature or request (功能增强) label Dec 1, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 1, 2025

Walkthrough

Adds support for a right-click (contextmenu) trigger for the dropdown component across demos, tests, docs, and renderless core logic; includes event binding, timing adjustments, demo scenarios, and test coverage.

Changes

Cohort / File(s) Change Summary
Demo scenarios
examples/sites/demos/pc/app/dropdown/trigger.vue, examples/sites/demos/pc/app/dropdown/trigger-composition-api.vue
Add a new scene (场景 3) demonstrating trigger="contextmenu" with a TinyDropdown and menu items (icons).
Test coverage
examples/sites/demos/pc/app/dropdown/trigger.spec.ts
Add a third dropdown reference for contextmenu, extend test flow to simulate right-click and verify visibility of the third menu.
Core dropdown logic
packages/renderless/src/dropdown/index.ts
Treat contextmenu like click for show/hide timing (zero delay), add contextmenu event binding in initEvent, remove its listener in beforeDestroy, and adjust event.target typing to HTMLElement.
Public API docs
examples/sites/demos/apis/dropdown.js
Expand trigger prop type to include 'contextmenu' and add meta: { stable: '3.28.0' } to the prop metadata.
User-facing docs
examples/sites/demos/pc/app/dropdown/webdoc/dropdown.js
Update zh-CN and en-US demo descriptions and feature text to list contextmenu as a supported trigger and note version support; minor formatting tweak.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Check timing behavior in packages/renderless/src/dropdown/index.ts to ensure zero-delay for contextmenu is intended and consistent with UX.
  • Verify contextmenu event binding/unbinding paths (including non-hover branch) to avoid leaks or duplicate handlers.
  • Confirm docs and API metadata (meta.stable) are accurate and version-aligned.

Poem

🐰 I hopped to the menu, the mouse gave a sound,
A right-click blossom gently opened down,
Zero-delay petals, three triggers now play,
I nibble the code and then hop away. 🥕✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding contextmenu as a new trigger type for the dropdown component, which is the primary objective of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a 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

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

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: 2

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c2c54d4 and 58c878d.

📒 Files selected for processing (4)
  • examples/sites/demos/pc/app/dropdown/trigger-composition-api.vue (1 hunks)
  • examples/sites/demos/pc/app/dropdown/trigger.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/dropdown/trigger.vue (1 hunks)
  • packages/renderless/src/dropdown/index.ts (5 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR E2E Test (pnpm test:e2e3)
🔇 Additional comments (5)
examples/sites/demos/pc/app/dropdown/trigger-composition-api.vue (1)

28-40: LGTM!

The contextmenu trigger scenario is correctly implemented and follows the same pattern as the existing scenarios.

examples/sites/demos/pc/app/dropdown/trigger.spec.ts (1)

12-35: LGTM!

The test correctly verifies contextmenu trigger behavior: hover should not show the menu, but right-click should.

packages/renderless/src/dropdown/index.ts (3)

54-59: LGTM!

Correctly treats contextmenu trigger the same as click with zero delay for immediate show behavior.


81-86: LGTM!

Correctly treats contextmenu trigger the same as click with zero delay for immediate hide behavior, consistent with the show() function.


130-130: LGTM!

Good type safety improvement by explicitly casting event.target to HTMLElement for correct typing in downstream operations.

Comment on lines +33 to +37
<tiny-dropdown-item :icon="tinyIconPlus">黄金糕</tiny-dropdown-item>
<tiny-dropdown-item :icon="tinyIconPlusCircle">狮子头</tiny-dropdown-item>
<tiny-dropdown-item :icon="tinyIconPlusSquare">螺蛳粉</tiny-dropdown-item>
<tiny-dropdown-item :icon="tinyIconCheckedLinear">双皮奶</tiny-dropdown-item>
<tiny-dropdown-item :icon="tinyIconCheckedSur">蚵仔煎</tiny-dropdown-item>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix incorrect variable references.

The :icon bindings reference tinyIconPlus, tinyIconPlusCircle, etc., but these variables don't exist in the data properties (lines 60-66). This will cause runtime errors. Scenario 2 (lines 20-24) correctly uses iconPlus, iconPlusCircle, etc.

Apply this diff to fix the variable references:

-          <tiny-dropdown-item :icon="tinyIconPlus">黄金糕</tiny-dropdown-item>
-          <tiny-dropdown-item :icon="tinyIconPlusCircle">狮子头</tiny-dropdown-item>
-          <tiny-dropdown-item :icon="tinyIconPlusSquare">螺蛳粉</tiny-dropdown-item>
-          <tiny-dropdown-item :icon="tinyIconCheckedLinear">双皮奶</tiny-dropdown-item>
-          <tiny-dropdown-item :icon="tinyIconCheckedSur">蚵仔煎</tiny-dropdown-item>
+          <tiny-dropdown-item :icon="iconPlus">黄金糕</tiny-dropdown-item>
+          <tiny-dropdown-item :icon="iconPlusCircle">狮子头</tiny-dropdown-item>
+          <tiny-dropdown-item :icon="iconPlusSquare">螺蛳粉</tiny-dropdown-item>
+          <tiny-dropdown-item :icon="iconCheckedLinear">双皮奶</tiny-dropdown-item>
+          <tiny-dropdown-item :icon="iconCheckedSur">蚵仔煎</tiny-dropdown-item>
📝 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.

Suggested change
<tiny-dropdown-item :icon="tinyIconPlus">黄金糕</tiny-dropdown-item>
<tiny-dropdown-item :icon="tinyIconPlusCircle">狮子头</tiny-dropdown-item>
<tiny-dropdown-item :icon="tinyIconPlusSquare">螺蛳粉</tiny-dropdown-item>
<tiny-dropdown-item :icon="tinyIconCheckedLinear">双皮奶</tiny-dropdown-item>
<tiny-dropdown-item :icon="tinyIconCheckedSur">蚵仔煎</tiny-dropdown-item>
<tiny-dropdown-item :icon="iconPlus">黄金糕</tiny-dropdown-item>
<tiny-dropdown-item :icon="iconPlusCircle">狮子头</tiny-dropdown-item>
<tiny-dropdown-item :icon="iconPlusSquare">螺蛳粉</tiny-dropdown-item>
<tiny-dropdown-item :icon="iconCheckedLinear">双皮奶</tiny-dropdown-item>
<tiny-dropdown-item :icon="iconCheckedSur">蚵仔煎</tiny-dropdown-item>
🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/dropdown/trigger.vue around lines 33 to 37, the
template uses non-existent variables tinyIconPlus, tinyIconPlusCircle,
tinyIconPlusSquare, tinyIconCheckedLinear, and tinyIconCheckedSur causing
runtime errors; change those :icon bindings to the existing data property names
iconPlus, iconPlusCircle, iconPlusSquare, iconCheckedLinear, and iconCheckedSur
respectively so the template references the defined variables.

Comment on lines +218 to +226
/** ---------------------------
* 新增:右键触发 contextmenu
* --------------------------- */
if (state.trigger === 'contextmenu') {
on(state.triggerElm, 'contextmenu', (e: MouseEvent) => {
e.preventDefault()
api.handleClick()
})
} else if (state.trigger === 'hover') {
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Memory leak: inline handler can't be removed in cleanup.

The inline arrow function (e: MouseEvent) => { e.preventDefault(); api.handleClick() } is bound to the contextmenu event, but beforeDistory (line 313) attempts to remove it using api.handleClick as the reference. Since off() requires the exact same function reference to remove a listener, the contextmenu handler will never be cleaned up, causing a memory leak.

Recommended solution: Store the handler function to enable proper cleanup:

+export const handleContextMenu =
+  ({ api }: Pick<IDropdownRenderlessParams, 'api'>) =>
+  (e: MouseEvent) => {
+    e.preventDefault()
+    api.handleClick()
+  }

Then in the API object (where handlers are composed), add:

const api = {
  // ... other handlers
  handleContextMenu: handleContextMenu({ api }),
  // ...
}

Update initEvent:

     if (state.trigger === 'contextmenu') {
-      on(state.triggerElm, 'contextmenu', (e: MouseEvent) => {
-        e.preventDefault()
-        api.handleClick()
-      })
+      on(state.triggerElm, 'contextmenu', api.handleContextMenu)
     } else if (state.trigger === 'hover') {

Update beforeDistory:

-      off(state.triggerElm, 'contextmenu', api.handleClick) /** 右键清理 */
+      off(state.triggerElm, 'contextmenu', api.handleContextMenu)
🤖 Prompt for AI Agents
In packages/renderless/src/dropdown/index.ts around lines 218-226 (and refer to
beforeDistory at line 313), the contextmenu listener is added with an inline
arrow function so off() later cannot remove it; replace the inline handler with
a named function stored on the instance/state and expose it via the API (e.g.,
api.handleContextMenu) so you can both add and remove the exact same function
reference. Concretely: create a handler factory or method that accepts the
event, calls preventDefault and api.handleClick, assign it to state or api
(handleContextMenu) during initEvent, use that reference when calling
on(state.triggerElm, 'contextmenu', handler) and remove it in beforeDistory with
off(state.triggerElm, 'contextmenu', handler); also add the new
handleContextMenu entry to the api object where other handlers are composed.

/** ---------------------------
* 新增:右键触发 contextmenu
* --------------------------- */
if (state.trigger === 'contextmenu') {
Copy link
Member

Choose a reason for hiding this comment

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

你好,这个应该属于新特性了,需要在对应的api文件中添加描述和版本信息哈

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

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 58c878d and 00cb1a0.

📒 Files selected for processing (2)
  • examples/sites/demos/apis/dropdown.js (1 hunks)
  • examples/sites/demos/pc/app/dropdown/webdoc/dropdown.js (3 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR E2E Test (pnpm test:e2e3)
🔇 Additional comments (3)
examples/sites/demos/pc/app/dropdown/webdoc/dropdown.js (2)

96-98: LGTM! Documentation properly describes the contextmenu trigger.

The trigger demo descriptions correctly document the new contextmenu (right-click) trigger option with appropriate version information (3.28.0) in both Chinese and English.


310-310: LGTM! Features list properly updated.

The trigger feature description correctly includes contextmenu (right-click) support with appropriate version information (3.28.0).

examples/sites/demos/apis/dropdown.js (1)

198-209: LGTM! API definition correctly extended with contextmenu support.

The trigger prop's type definition properly includes the new 'contextmenu' option, and the meta field appropriately marks version 3.28.0 as when this feature became stable. The changes are consistent with the documentation updates.

'zh-CN': '<p>通过 <code>visible</code> 属性手动控制下拉菜单显隐,优先级高于trigger。</p>\n',
'en-US':
'<p>Manually control the visibility of the dropdown menu through the<code>visible</code>attribute, with priority over trigger.</p>\n'
'<p>Manually control the visibility of the dropdown menu through the <code>visible</code>attribute, with priority over trigger.</p>\n'
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add missing space in the English description.

There's a missing space between </code> and attribute in the text.

Apply this diff:

-          '<p>Manually control the visibility of the dropdown menu through the <code>visible</code>attribute, with priority over trigger.</p>\n'
+          '<p>Manually control the visibility of the dropdown menu through the <code>visible</code> attribute, with priority over trigger.</p>\n'
📝 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.

Suggested change
'<p>Manually control the visibility of the dropdown menu through the <code>visible</code>attribute, with priority over trigger.</p>\n'
'<p>Manually control the visibility of the dropdown menu through the <code>visible</code> attribute, with priority over trigger.</p>\n'
🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/dropdown/webdoc/dropdown.js around line 111, the
English description string is missing a space between the closing code tag and
the word "attribute"; update the string to insert a single space after "</code>"
so it reads "</code> attribute" (adjust surrounding escaping/quotes if needed)
to correct the grammar.

@zzcr zzcr merged commit 3351336 into opentiny:dev Dec 8, 2025
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request (功能增强)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants