Skip to content

Release/v0.2.x#132

Merged
hexqi merged 14 commits intoopentiny:developfrom
gene9831:merge-release-0.2-into-dev
Jun 30, 2025
Merged

Release/v0.2.x#132
hexqi merged 14 commits intoopentiny:developfrom
gene9831:merge-release-0.2-into-dev

Conversation

@gene9831
Copy link
Collaborator

@gene9831 gene9831 commented Jun 30, 2025

Summary by CodeRabbit

  • New Features

    • Dropdown menus now support opening on hover in addition to click and manual modes.
    • Suggestion Pills component introduces two new options: "expand" or "scroll" overflow modes, and an auto-scroll-on-hover feature for improved navigation.
    • Added a reusable popper component for positioning floating elements.
  • Improvements

    • Dropdown menu and suggestion pills documentation updated for clarity and new features.
    • Dropdown menu styling now uses CSS variables for easier customization.
    • Refined event handling for better user interaction, including improved hover and click behaviors.
  • Bug Fixes

    • Fixed event emission on suggestion pill buttons for more consistent behavior.
  • Chores

    • Version numbers updated across packages to 0.2.11.

gene9831 and others added 14 commits June 13, 2025 14:50
* refactor: update event handling in dropdown and suggestion components

- Changed event listeners from `@click` to `@pointerup` in DropdownMenu and PillButtonWrapper components for improved responsiveness.
- Added `max-height` style to suggestion popover for better layout control.

* feat: add manual trigger and click-outside handling to dropdown and suggestion components

- Introduced a `manual` trigger option for DropdownMenu and SuggestionPopover to allow external control of visibility.
- Implemented `@click-outside` event to close the dropdown and popover when clicking outside.
- Updated documentation to include new properties and event details for both components.
* feat: enhance DropdownMenu with hover trigger support

- Added support for 'hover' trigger in the DropdownMenu component, allowing menus to display on hover events.
- Updated documentation to reflect the new trigger options and their descriptions.
- Refactored event handling to manage hover states and click events more effectively.
- Improved styling variables for better customization of dropdown appearance.

* feat: add TODO for safePolygon implementation in DropdownMenu hover trigger
@coderabbitai
Copy link

coderabbitai bot commented Jun 30, 2025

Walkthrough

This update introduces a new TrBasePopper component and composable utilities for teleport targets, refactors DropdownMenu to use the popper for positioning and event handling, and enhances SuggestionPills with new overflow and auto-scroll features. Documentation and demos are updated to reflect these API and behavior changes, and package versions are incremented.

Changes

Files/Group Change Summary
packages/components/src/base-popper/index.ts, index.vue Introduced the TrBasePopper Vue component, providing flexible popper positioning, trigger event handling, and teleport logic. Exports the component with a designated name.
packages/components/src/shared/composables/useTeleportTarget.ts, index.ts Added a composable to compute appropriate teleport targets, supporting Shadow DOM and selector-based targeting. Re-exported from composables index.
packages/components/src/dropdown-menu/index.vue Refactored to use TrBasePopper for dropdown positioning and event handling, added hover trigger support, simplified template, and standardized styling with CSS variables.
packages/components/src/dropdown-menu/index.type.ts Updated types: added 'hover' to trigger, replaced default slot with named trigger slot, added click-outside event, removed unused style props.
packages/components/src/suggestion-pills/index.vue, index.type.ts, components/PillButtonWrapper.vue Added overflowMode and autoScrollOnHover props for controlling overflow behavior and auto-scroll on hover. Implemented scroll-on-hover logic for pills, updated event emission signatures, and added mouseenter event. Updated "show more" logic for expand mode.
packages/components/src/suggestion-popover/index.vue Changed trigger event from pointerup to click.
docs/demos/dropdown-menu/basic.vue, docs/demos/suggestion/pills-popper-config.vue, docs/demos/suggestion/pills-popper.vue Updated demos to use named trigger slots for dropdowns, added hover-triggered dropdowns, and exposed new props and controls for suggestion pills overflow and auto-scroll features.
docs/src/components/dropdown-menu.md, docs/src/components/suggestion-pills.md Updated documentation for new/changed props, slots, types, and events for DropdownMenu and SuggestionPills, including detailed type definitions and usage notes.
docs/src/releases/update-log.md Added a release entry for version 0.2.10 summarizing breaking and new features for DropdownMenu and SuggestionPills.
packages/components/package.json, packages/kit/package.json, packages/svgs/package.json Bumped version numbers from 0.2.10 to 0.2.11.
packages/components/tsconfig.json, vite.config.ts Removed path alias (~) and related TypeScript/Vite configuration.

Sequence Diagram(s)

sequenceDiagram
    participant App
    participant DropdownMenu
    participant TrBasePopper
    participant TeleportTarget

    App->>DropdownMenu: Render with trigger="hover" or "click"
    DropdownMenu->>TrBasePopper: Pass trigger slot, content slot, trigger events
    TrBasePopper->>TeleportTarget: Compute target for popper placement
    TrBasePopper-->>DropdownMenu: Emits events (e.g., click-outside)
    TrBasePopper-->>App: Renders trigger and dropdown at correct position
Loading
sequenceDiagram
    participant App
    participant SuggestionPills

    App->>SuggestionPills: Render with overflowMode and autoScrollOnHover props
    SuggestionPills->>App: Render pills, listen for mouseenter on pill
    App-->>SuggestionPills: Mouse enters pill
    SuggestionPills->>SuggestionPills: If scroll mode & autoScrollOnHover, scroll pill into view
Loading

Possibly related PRs

  • Release/v0.2.x #126: Adds a manual-trigger dropdown example and related state to the same dropdown menu demo file, directly relating to changes in trigger API usage and examples.

Suggested reviewers

  • hexqi

Poem

In a garden of slots and poppers anew,
Dropdowns hover, suggestions scroll through.
Overflow tamed, triggers refined,
Teleporting menus with logic aligned.
With every hop, the UI grows bright—
This bunny codes on through the night!
🐇✨

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

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

docs/demos/suggestion/pills-popper.vue

Oops! Something went wrong! :(

ESLint: 9.30.0

Error: The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.
at /node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:145:10
at async loadTypeScriptConfigFileWithJiti (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:144:3)
at async loadConfigFile (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:266:11)
at async ConfigLoader.calculateConfigArray (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:589:23)
at async #calculateConfigArray (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:743:23)
at async /node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/eslint/eslint.js:760:6
at async Promise.all (index 0)
at async ESLint.lintFiles (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/eslint/eslint.js:757:19)
at async Object.execute (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/cli.js:632:14)
at async main (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/bin/eslint.js:175:19)

docs/demos/suggestion/pills-popper-config.vue

Oops! Something went wrong! :(

ESLint: 9.30.0

Error: The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.
at /node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:145:10
at async loadTypeScriptConfigFileWithJiti (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:144:3)
at async loadConfigFile (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:266:11)
at async ConfigLoader.calculateConfigArray (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:589:23)
at async #calculateConfigArray (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:743:23)
at async /node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/eslint/eslint.js:760:6
at async Promise.all (index 0)
at async ESLint.lintFiles (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/eslint/eslint.js:757:19)
at async Object.execute (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/cli.js:632:14)
at async main (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/bin/eslint.js:175:19)

docs/demos/dropdown-menu/basic.vue

Oops! Something went wrong! :(

ESLint: 9.30.0

Error: The 'jiti' library is required for loading TypeScript configuration files. Make sure to install it.
at /node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:145:10
at async loadTypeScriptConfigFileWithJiti (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:144:3)
at async loadConfigFile (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:266:11)
at async ConfigLoader.calculateConfigArray (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:589:23)
at async #calculateConfigArray (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/config/config-loader.js:743:23)
at async /node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/eslint/eslint.js:760:6
at async Promise.all (index 0)
at async ESLint.lintFiles (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/eslint/eslint.js:757:19)
at async Object.execute (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/lib/cli.js:632:14)
at async main (/node_modules/.pnpm/eslint@9.30.0/node_modules/eslint/bin/eslint.js:175:19)

  • 10 others
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate Unit Tests
  • Create PR with Unit Tests
  • Post Copyable Unit Tests in 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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need 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)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai auto-generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

🧹 Nitpick comments (4)
packages/components/src/shared/composables/useTeleportTarget.ts (1)

12-12: Fix typo in variable name.

There's a typo in the variable name referentceEl. It should be referenceEl.

-    const referentceEl = unrefElement(reference)
+    const referenceEl = unrefElement(reference)

Also update line 13:

-    const rootNode = referentceEl?.getRootNode?.()
+    const rootNode = referenceEl?.getRootNode?.()
packages/components/src/suggestion-pills/index.vue (1)

216-220: Consider adding scrollbar styling for consistency.

The overflow-scroll class enables scrolling, but you might want to style the scrollbar for better visual consistency across browsers.

Consider adding custom scrollbar styling:

&.overflow-scroll {
  overflow-x: auto;
  scroll-behavior: smooth;
+  scrollbar-width: thin;
+  scrollbar-color: #dbdbdb transparent;
+
+  &::-webkit-scrollbar {
+    height: 4px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background-color: #dbdbdb;
+    border-radius: 2px;
+  }
}
packages/components/src/dropdown-menu/index.vue (1)

45-45: Consider implementing the TODO for better hover UX.

The comment mentions using @floating-ui/dom's safePolygon() utility for improved hover behavior.

Would you like me to create an issue to track implementing the safePolygon() utility for smoother hover interactions?

packages/components/src/base-popper/index.vue (1)

44-56: Consider improving Fragment handling robustness.

The current Fragment handling only processes the first VNode and assumes it's the only Fragment. This may not handle complex slot content correctly.

Consider this more robust approach:

const triggerVNodes = computed(() => {
  const triggerSlot = slots.trigger?.()
  const vnodes = triggerSlot ? (Array.isArray(triggerSlot) ? triggerSlot : [triggerSlot]) : []

-  // 如果第一个 vnode 是 Fragment 类型,并且 children 是数组,则返回 children(只渲染第一个 v-for Fragment)
-  if (vnodes[0].type === Fragment && Array.isArray(vnodes[0].children)) {
-    return vnodes[0].children
-  }
+  // Flatten all Fragments to their children
+  const flattened: VNode[] = []
+  for (const vnode of vnodes) {
+    if (vnode.type === Fragment && Array.isArray(vnode.children)) {
+      flattened.push(...vnode.children as VNode[])
+    } else {
+      flattened.push(vnode)
+    }
+  }
+  return flattened.length ? flattened : vnodes

-  return vnodes
})
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9160ca7 and 4f2cf9c.

📒 Files selected for processing (21)
  • docs/demos/dropdown-menu/basic.vue (2 hunks)
  • docs/demos/suggestion/pills-popper-config.vue (2 hunks)
  • docs/demos/suggestion/pills-popper.vue (1 hunks)
  • docs/src/components/dropdown-menu.md (1 hunks)
  • docs/src/components/suggestion-pills.md (2 hunks)
  • docs/src/releases/update-log.md (1 hunks)
  • packages/components/package.json (1 hunks)
  • packages/components/src/base-popper/index.ts (1 hunks)
  • packages/components/src/base-popper/index.vue (1 hunks)
  • packages/components/src/dropdown-menu/index.type.ts (2 hunks)
  • packages/components/src/dropdown-menu/index.vue (5 hunks)
  • packages/components/src/shared/composables/index.ts (1 hunks)
  • packages/components/src/shared/composables/useTeleportTarget.ts (1 hunks)
  • packages/components/src/suggestion-pills/components/PillButtonWrapper.vue (3 hunks)
  • packages/components/src/suggestion-pills/index.type.ts (1 hunks)
  • packages/components/src/suggestion-pills/index.vue (4 hunks)
  • packages/components/src/suggestion-popover/index.vue (1 hunks)
  • packages/components/tsconfig.json (0 hunks)
  • packages/components/vite.config.ts (0 hunks)
  • packages/kit/package.json (1 hunks)
  • packages/svgs/package.json (1 hunks)
💤 Files with no reviewable changes (2)
  • packages/components/vite.config.ts
  • packages/components/tsconfig.json
🧰 Additional context used
🧠 Learnings (13)
📓 Common learnings
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
packages/components/src/base-popper/index.ts (2)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.
packages/components/src/suggestion-popover/index.vue (2)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.
docs/demos/suggestion/pills-popper.vue (1)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
docs/demos/dropdown-menu/basic.vue (2)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.
docs/src/releases/update-log.md (1)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
packages/components/src/suggestion-pills/components/PillButtonWrapper.vue (2)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.
docs/src/components/dropdown-menu.md (1)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
docs/demos/suggestion/pills-popper-config.vue (2)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
Learnt from: SonyLeo
PR: opentiny/tiny-robot#119
File: packages/components/src/attachments/index.less:213-213
Timestamp: 2025-06-18T09:29:47.974Z
Learning: 在 packages/components/src/attachments/index.less 中,.tr-file-card__close 的背景色使用了硬编码的 rgb(194, 194, 194),但这个UI元素(关闭按钮)将会被直接替换为图标,所以不需要抽取为CSS变量。
packages/components/src/dropdown-menu/index.type.ts (2)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.
packages/components/src/dropdown-menu/index.vue (3)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.
Learnt from: SonyLeo
PR: opentiny/tiny-robot#119
File: packages/components/src/attachments/index.less:213-213
Timestamp: 2025-06-18T09:29:47.974Z
Learning: 在 packages/components/src/attachments/index.less 中,.tr-file-card__close 的背景色使用了硬编码的 rgb(194, 194, 194),但这个UI元素(关闭按钮)将会被直接替换为图标,所以不需要抽取为CSS变量。
packages/components/src/suggestion-pills/index.vue (2)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.
packages/components/src/base-popper/index.vue (2)
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:131-133
Timestamp: 2025-05-27T03:35:11.008Z
Learning: In the SuggestionPopover component (packages/components/src/suggestion-popover/index.vue), the click handler can be bound unconditionally because the `show` computed property has a custom setter that prevents state mutations when `props.trigger === 'manual'`. This design centralizes trigger mode logic in the computed property rather than requiring conditional checks in event handlers.
Learnt from: gene9831
PR: opentiny/tiny-robot#59
File: packages/components/src/suggestion-popover/index.vue:0-0
Timestamp: 2025-05-27T03:45:56.392Z
Learning: In Vue components using VueUse's onClickOutside, calling stopPropagation() in the onClickOutside handler can prevent subsequent click event handlers on the same element from being triggered. This means that clicking a trigger element while a popover is open can successfully close the popover without immediately reopening it, even when the onClickOutside only listens to the popover element and not the trigger element.
🔇 Additional comments (52)
packages/components/package.json (1)

3-3: Version bump looks good — don’t forget the release housekeeping
The increment to 0.2.11 is consistent with the other packages.
Please make sure the CHANGELOG is updated and a matching git tag is pushed so that automated publishing can pick it up.

packages/svgs/package.json (1)

3-3: SVG package version aligned
No issues spotted. Confirm that this package is included in the release notes and publish workflow alongside the others.

packages/kit/package.json (1)

3-3: Kit package version bump acknowledged
Everything is consistent. Ensure lock-files (if any) and root work-space references are updated before publishing.

packages/components/src/suggestion-pills/index.type.ts (1)

52-63: LGTM! Well-documented type extensions.

The new properties overflowMode and autoScrollOnHover are properly typed with clear JSDoc documentation and appropriate default values. The implementation aligns well with the enhanced overflow functionality described in the AI summary.

packages/components/src/shared/composables/useTeleportTarget.ts (1)

4-29: Excellent composable implementation for teleport target resolution.

The logic correctly handles both Shadow DOM and regular DOM scenarios with appropriate fallbacks. The special handling for the 'body' selector is a nice optimization. The comprehensive JSDoc documentation makes the behavior clear.

packages/components/src/suggestion-popover/index.vue (1)

220-220: Good change to standardize trigger interaction.

Switching from @pointerup to @click provides more predictable and standard user interaction behavior. This aligns with the custom setter logic in the show computed property that centralizes trigger mode handling.

packages/components/src/base-popper/index.ts (1)

1-5: Standard component export pattern.

Clean and simple component wrapper following Vue.js conventions with appropriate naming (TrBasePopper).

packages/components/src/shared/composables/index.ts (1)

1-1: Appropriate barrel export for new composable.

Standard re-export pattern to make the new useTeleportTarget composable available through the shared composables index.

docs/demos/suggestion/pills-popper.vue (1)

15-19: LGTM! Correctly updated to use the new trigger slot API.

The change from direct child to the named #trigger slot aligns with the DropdownMenu API breaking changes documented in the changelog.

docs/demos/dropdown-menu/basic.vue (3)

3-5: LGTM! Correctly updated to use the new trigger slot API.

The existing dropdown menu correctly migrated from direct child to the named #trigger slot.


15-17: LGTM! Manual trigger example properly updated.

The manual trigger dropdown correctly uses the new #trigger slot while maintaining the manual trigger functionality.


19-31: LGTM! Excellent demonstration of the new hover trigger feature.

The new section effectively demonstrates the trigger="hover" functionality with proper usage of the #trigger slot. The horizontal layout with flexbox provides a clear visual example.

docs/src/releases/update-log.md (1)

4-12: LGTM! Comprehensive changelog entry for breaking changes.

The changelog entry clearly documents all the breaking changes and new features in version 0.2.10, including:

  • New hover trigger support for DropdownMenu
  • API changes (slot and prop modifications)
  • New SuggestionPills overflow and auto-scroll features

This provides clear guidance for users upgrading to the new version.

packages/components/src/suggestion-pills/components/PillButtonWrapper.vue (4)

9-12: LGTM! Event emission signature correctly updated.

The event signatures are properly updated to emit only MouseEvent for both click and mouseenter events, which supports the new auto-scroll functionality in the parent SuggestionPills component.


26-26: LGTM! Consistent event emission in popover context.

The PillButton within SuggestionPopover correctly emits both click and mouseenter events with the updated signature.


38-40: LGTM! Correctly updated to use new DropdownMenu trigger slot API.

The DropdownMenu usage properly migrated to the named #trigger slot while maintaining consistent event emission.


42-48: LGTM! Fallback case properly handles updated events.

The fallback PillButton rendering correctly emits both events with the updated signature and maintains style binding.

docs/src/components/dropdown-menu.md (3)

21-25: LGTM! Props documentation accurately reflects the new API.

The props table correctly documents:

  • The new 'hover' trigger mode alongside existing modes
  • Proper descriptions for each trigger type
  • Removal of obsolete props (minWidth, topOffset)

31-33: LGTM! Slots documentation correctly updated for new API.

The slots section properly documents the change from default slot to the named trigger slot, with correct TypeScript type annotation.


39-42: LGTM! Events documentation clearly explains behavior constraints.

The events section correctly documents that click-outside only fires for 'click' or 'manual' trigger modes, which is important for developers to understand the event behavior.

packages/components/src/dropdown-menu/index.type.ts (4)

1-1: LGTM!

The VNode import is correctly added and used in the trigger slot definition.


17-17: Good addition of hover trigger mode.

The new 'hover' trigger mode expands the component's flexibility and aligns with the implementation.


21-21: Well-structured slot API change.

The change from a generic default slot to a specifically typed trigger slot improves type safety and API clarity.


26-29: Excellent documentation for the click-outside event.

The comment clearly specifies when this event fires, which helps developers understand its behavior.

docs/demos/suggestion/pills-popper-config.vue (3)

5-6: Correct usage of new SuggestionPills props.

The demo properly binds the new overflowMode and autoScrollOnHover props.


41-45: Well-structured overflow mode options.

The radio group options correctly match the allowed values for the overflowMode prop.


18-28: Clean UI layout for demonstrating new features.

The controls are well-organized with proper spacing and clear labels.

docs/src/components/suggestion-pills.md (2)

54-60: Comprehensive documentation for new props.

The table clearly documents the new overflowMode and autoScrollOnHover props with appropriate types and descriptions.


103-129: Improved type definitions with better structure.

Breaking down SuggestionPillAction into specific SuggestionPillPopoverAction and SuggestionPillMenuAction types improves clarity and type safety.

packages/components/src/suggestion-pills/index.vue (4)

10-10: Good default value for overflowMode.

Setting 'expand' as the default maintains backward compatibility.


25-25: Correct logic for conditional show more button.

The button is properly hidden when in scroll mode.


123-149: Well-implemented auto-scroll functionality.

The scroll logic correctly handles both left and right hidden cases with smooth scrolling behavior.


151-155: Efficient hover handling.

The mouseenter handler properly checks the conditions before triggering scroll behavior.

packages/components/src/dropdown-menu/index.vue (4)

2-4: Clean refactoring to use TrBasePopper.

The migration to TrBasePopper significantly simplifies the positioning logic.


44-58: Good hover trigger implementation.

The hover logic with appropriate delays prevents flickering when moving between trigger and dropdown.


101-108: Excellent use of CSS variables.

The CSS variables approach improves theming flexibility and maintainability.


73-98: Clean template structure with TrBasePopper.

The template is much simpler and more maintainable with the base popper handling positioning.

packages/components/src/base-popper/index.vue (15)

1-16: LGTM: Well-structured imports and necessary ESLint disable.

The ESLint disable for no-explicit-any is justified given the generic event handler system. All imports are relevant and properly organized.


18-20: Good use of inheritAttrs: false.

This correctly prevents automatic attribute inheritance, allowing manual control over where attributes are applied (to the popper element).


22-22: Flexible and appropriate type definition.

The TriggerEvents type correctly handles the variety of possible DOM event handlers with proper capitalization pattern matching.


24-37: Well-designed props interface.

The props provide good flexibility with:

  • Multiple placement options covering common scenarios
  • Flexible offset configuration (number or axis-specific object)
  • Clear boolean flags for behavior control
  • Proper default values

39-42: Proper slot type definitions.

The slot definitions correctly handle both single VNode and VNode array scenarios for flexible content rendering.


58-83: Robust ref management system.

The implementation properly handles:

  • Both Vue component instances and native DOM elements
  • Array length synchronization with proper cleanup
  • Post-flush timing to ensure DOM updates are complete
  • Clear warning messages for unsupported element types

85-99: Well-designed indexed event handling system.

The implementation correctly:

  • Validates event handler naming with proper regex pattern
  • Injects trigger index into event calls for multi-trigger scenarios
  • Creates isolated handler sets for each trigger element

101-111: Clean offset normalization logic.

The computed property properly handles both number and object offset formats with sensible defaults.


113-114: Proper use of VueUse composables for element tracking.

The border-box sizing option ensures accurate dimension calculations including borders and padding.


116-151: Sophisticated positioning logic with modern overflow prevention.

The implementation features:

  • Proper position calculations for all placement options
  • Smart overflow prevention using CSS clamp() and viewport units
  • Correct handling of bottom positioning with calc()
  • Accurate center positioning calculations

The string-based placement matching using includes() works correctly for the defined placement options.


153-162: Necessary bounds update on visibility change.

The watcher correctly recalculates element bounds when the popper becomes visible, ensuring accurate positioning after DOM updates.


164-164: Appropriate use of teleport target composable.

Using the trigger reference to determine the teleport target ensures proper positioning context, including Shadow DOM support.


166-170: Well-designed component exposure.

Exposing both individual and array trigger references along with the popper ref provides flexibility for advanced use cases.


173-187: Well-structured template with proper Vue patterns.

The template correctly implements:

  • Indexed ref setting and event handler binding
  • Proper key management for v-for rendering
  • Conditional teleport rendering to avoid unnecessary DOM
  • Attribute forwarding to the popper element
  • Transition wrapper integration

190-194: Appropriate minimal styling.

The fixed positioning is essential for popper functionality, and scoped styling prevents conflicts.

@hexqi hexqi merged commit f683c91 into opentiny:develop Jun 30, 2025
@gene9831 gene9831 deleted the merge-release-0.2-into-dev branch June 30, 2025 08:20
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.

3 participants