Skip to content

Conversation

shenjunjian
Copy link
Collaborator

@shenjunjian shenjunjian commented Sep 12, 2025

PR

修复select组件在searchable=true时,每次键入都调用setSelected而频繁打断输入的问题。

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: #3693

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • None
  • Bug Fixes

    • Prevents unintended selection changes while typing in a Select component’s search field. Focus-aware behavior ensures your input isn’t interrupted and selected values don’t change during search.
    • Improves focus handling in searchable dropdowns to avoid flicker and cursor jumps when filtering options, resulting in a smoother typing experience.

Copy link

coderabbitai bot commented Sep 12, 2025

Walkthrough

The select component’s watchOptions now adds a focus-context check before calling setSelected, avoiding updates when focus is inside a tiny-select-dropdown search input. This change ensures setSelected is not invoked during user interaction with the dropdown’s search field.

Changes

Cohort / File(s) Summary
Select focus-context guard
packages/renderless/src/select/index.ts
Tightened condition in watchOptions: after nextTick, skip api.setSelected if focus is on the parent input or on an input inside the tiny-select-dropdown search panel. Prevents selection syncing while user types in the searchable dropdown.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant U as User
  participant SI as Search Input (dropdown)
  participant WC as watchOptions
  participant NT as nextTick
  participant API as api.setSelected

  U->>SI: Focus + type in search
  SI-->>WC: options change triggers watch
  WC->>NT: Schedule post-DOM check
  NT->>WC: Callback executes
  alt Focus on parent input OR inside dropdown search input
    WC--XAPI: Guard: do not call setSelected
    Note right of WC: Selection remains unchanged during typing
  else Other focus context
    WC->>API: setSelected()
    API-->>WC: Selection synced
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Pre-merge checks (3 passed)

✅ 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 identifies the select component and the bug where frequent setSelected calls interrupt searchable input, so it accurately relates to the PR's main change; however the phrasing is awkward ("repairing searchable") and contains extra whitespace which reduces clarity for a quick scan.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

I twitch my ears at focus light,
Guarding clicks from typing night—
No sneaky syncs while searches flow,
I pause my paws and let it go.
Then hop to setSelected, neat—
When keys grow still, I press “complete.” 🐇✨

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch shen/fix-cascader

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

🧹 Nitpick comments (1)
packages/renderless/src/select/index.ts (1)

1601-1607: Tighten selector and compute activeEl once for robustness/readability.

  • Use the same explicit selector used elsewhere (input[data-tag="tiny-input-inner"]) to avoid matching unintended inputs.
  • Cache document.activeElement and rely on .closest('.tiny-select-dropdown__search') to detect focus within the search panel (no need to also assert tiny-input__inner).

Apply within the same nextTick block:

-      if (
-        parent.$el.querySelector('input') !== document.activeElement && // filterable时, 从 input 框离开了
-        !(
-          document.activeElement?.classList.contains('tiny-input__inner') && // 并且当前不在下拉面板的searchable 的input中时,  才需要更新一下setSelect
-          document.activeElement.closest('.tiny-select-dropdown__search')
-        )
-      ) {
+      const activeEl = document.activeElement
+      const parentInput = parent.$el.querySelector('input[data-tag="tiny-input-inner"]')
+      const inDropdownSearch =
+        activeEl instanceof HTMLElement && !!activeEl.closest('.tiny-select-dropdown__search')
+      if (activeEl !== parentInput && !inDropdownSearch) {
         api.setSelected()
       }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7284629 and 8766ff8.

📒 Files selected for processing (1)
  • packages/renderless/src/select/index.ts (1 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 (2)
packages/renderless/src/select/index.ts (2)

1601-1607: Focus guard prevents setSelected while typing in dropdown search — fix aligns with PR goal.

This additional activeElement/context check correctly avoids calling api.setSelected() when the user is focused in the dropdown’s searchable input, eliminating the keystroke interruption described in #3693.


1601-1607: Harden focus-guard selectors — verify across themes / micro-frontends

  • Repo check: guard at packages/renderless/src/select/index.ts:1601–1607; .tiny-select-dropdown__search found in packages/vue/src/select/src/pc.vue:421 and packages/vue/src/base-select/src/pc.vue:393; inputs use data-tag="tiny-input-inner" in packages/vue/src/input/src/pc.vue:76 and packages/vue/src/input/src/mobile-first.vue:81; renderless also queries input[data-tag="tiny-input-inner"] at packages/renderless/src/select/index.ts:2095 and 2416 — so the current class-based guard matches the repo DOM.
  • Action: still verify behavior in Wujie/micro-frontend hosts and theme-scoped builds; replace brittle class+closest check with a more robust test (e.g. match input[data-tag="tiny-input-inner"] or use parent.$el.contains(document.activeElement)) to avoid missed focus cases.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
1 participant