Skip to content

feat: The option supports virtual scrolling.#52

Merged
zzcr merged 3 commits into
mainfrom
lk-0625
Jun 25, 2026
Merged

feat: The option supports virtual scrolling.#52
zzcr merged 3 commits into
mainfrom
lk-0625

Conversation

@discreted66

@discreted66 discreted66 commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

feat:选项支持虚拟滚动

Summary by CodeRabbit

  • New Features
    • Added a virtual scrolling demo for the search box and documented how it behaves with large option lists.
    • The secondary panel now virtualizes long lists for radio, checkbox, and map option groups.
  • Bug Fixes
    • Improved dropdown performance and smoothness for large datasets via virtualized rendering.
    • Added panel-max-height support to better control the visible scrolling area.
  • Documentation
    • Updated props and example docs to explain virtual scrolling and how panel-max-height affects rendering.

@github-actions github-actions Bot added the enhancement New feature or request label Jun 25, 2026
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 31a299ee-659a-4fcd-9dee-1a788b8f0a7b

📥 Commits

Reviewing files that changed from the base of the PR and between 424a123 and ae4729f.

📒 Files selected for processing (1)
  • packages/search-box/src/components/second-level-panel.vue
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/search-box/src/components/second-level-panel.vue

Walkthrough

Adds fixed-height virtual scrolling to the search-box secondary panel, updates the supporting docs and demos, adjusts dropdown styling for the virtual list layout, and bumps the package version to 3.29.0.

Changes

Search box virtual scrolling

Layer / File(s) Summary
Virtual scroll composable
packages/search-box/src/composables/use-virtual-scroll.ts
useVirtualScroll computes buffered ranges, offsets, total height, visible items, and scroll state for fixed-height lists.
Panel virtualization
packages/search-box/src/components/second-level-panel.vue, packages/search-box/src/pc.vue
TinySearchBoxSecondLevelPanel initializes useVirtualScroll, filters list data by panel type, resets scroll on search changes, exposes virtual-scroll state, and receives panelMaxHeight from pc.vue.
Panel virtual items
packages/search-box/src/components/second-level-panel.vue
The radio, checkbox, and map branches render vsVisibleItems inside virtual phantom/content wrappers and use virtual indices for keys and selection handling.
Virtual list styles
packages/search-box/theme/index.less, packages/search-box/theme-saas/index.less
Dropdown, phantom, content, checkbox, radio, and button-row styles are updated for the virtual-list layout and fixed row height.
Example data and preview
packages/docs/search-box/virtual-scroll-data.ts, packages/docs/search-box/virtual-scroll.vue, packages/docs/search-box/virtual-scroll-options-api.vue
virtualScrollDataSource generates large radio, checkbox, and grouped map datasets, and the Vue demo components bind that data into tiny-search-box previews.
Docs and registry
packages/docs/examples/virtual-scroll.md, packages/docs/.vitepress/config.mts, packages/docs/apis/props.md, packages/docs/search-box/webdoc/search-box.js
The example page, sidebar entry, demo registry entry, and panel-max-height prop text describe the virtual-scroll example.
Release version bump
packages/search-box/package.json
packages/search-box/package.json updates the package version to 3.29.0.

Sequence Diagram(s)

sequenceDiagram
  participant pcVue as pc.vue
  participant secondLevelPanel as TinySearchBoxSecondLevelPanel
  participant virtualScroll as useVirtualScroll
  participant scrollContainer as virtual scroll container

  pcVue->>secondLevelPanel: pass panelMaxHeight
  secondLevelPanel->>virtualScroll: initialize with getList and itemHeight
  secondLevelPanel->>scrollContainer: bind vsHandleScroll
  scrollContainer->>virtualScroll: emit scroll event
  virtualScroll-->>secondLevelPanel: vsVisibleItems and offset values
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

🐰 I hopped through long lists, one row at a time,
With phantom and viewport in tidy rhyme.
The docs now point where the virtual leaves sway,
And smooth little scrolls bring carrots my way!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding virtual scrolling support for the options list.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch lk-0625

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.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Caution

Failed to replace (edit) comment. This is likely due to insufficient permissions or the comment being deleted.

Error details
{"name":"HttpError","status":500,"request":{"method":"PATCH","url":"https://api.github.com/repos/opentiny/tiny-search-box/issues/comments/4797527388","headers":{"accept":"application/vnd.github.v3+json","user-agent":"octokit.js/0.0.0-development octokit-core.js/7.0.6 Node.js/24","authorization":"token [REDACTED]","content-type":"application/json; charset=utf-8"},"body":{"body":"<!-- This is an auto-generated comment: summarize by coderabbit.ai -->\n<!-- review_stack_entry_start -->\n\n[![Review Change Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/opentiny/tiny-search-box/pull/52?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)\n\n<!-- review_stack_entry_end -->\n<!-- This is an auto-generated comment: review in progress by coderabbit.ai -->\n\n> [!NOTE]\n> Currently processing new changes in this PR. This may take a few minutes, please wait...\n> \n> <details>\n> <summary>⚙️ Run configuration</summary>\n> \n> **Configuration used**: Organization UI\n> \n> **Review profile**: CHILL\n> \n> **Plan**: Pro\n> \n> **Run ID**: `9c85bc00-c35d-46f2-b512-a9d6097ea103`\n> \n> </details>\n> \n> <details>\n> <summary>📥 Commits</summary>\n> \n> Reviewing files that changed from the base of the PR and between 57e51ffdf00f05fea4d50217cf0506a268828b48 and 424a12381f67ec5d16dd0657a8501d675fdcb149.\n> \n> </details>\n> \n> <details>\n> <summary>📒 Files selected for processing (13)</summary>\n> \n> * `packages/docs/.vitepress/config.mts`\n> * `packages/docs/apis/props.md`\n> * `packages/docs/examples/virtual-scroll.md`\n> * `packages/docs/search-box/virtual-scroll-data.ts`\n> * `packages/docs/search-box/virtual-scroll-options-api.vue`\n> * `packages/docs/search-box/virtual-scroll.vue`\n> * `packages/docs/search-box/webdoc/search-box.js`\n> * `packages/search-box/package.json`\n> * `packages/search-box/src/components/second-level-panel.vue`\n> * `packages/search-box/src/composables/use-virtual-scroll.ts`\n> * `packages/search-box/src/pc.vue`\n> * `packages/search-box/theme-saas/index.less`\n> * `packages/search-box/theme/index.less`\n> \n> </details>\n> \n> ```ascii\n>  ___________________________________________________________\n> < This loop is doing cardio. Your users are doing timeouts. >\n>  -----------------------------------------------------------\n>   \\\n>    \\   (\\__/)\n>        (•ㅅ•)\n>        /   づ\n> ```\n\n<!-- end of auto-generated comment: review in progress by coderabbit.ai -->\n\n<!-- finishing_touch_checkbox_start -->\n\n<details>\n<summary>✨ Finishing Touches</summary>\n\n<details>\n<summary>📝 Generate docstrings</summary>\n\n- [ ] <!-- {\"checkboxId\": \"7962f53c-55bc-4827-bfbf-6a18da830691\"} --> Create stacked PR\n- [ ] <!-- {\"checkboxId\": \"3e1879ae-f29b-4d0d-8e06-d12b7ba33d98\"} --> Commit on current branch\n\n</details>\n<details>\n<summary>🧪 Generate unit tests (beta)</summary>\n\n- [ ] <!-- {\"checkboxId\": \"f47ac10b-58cc-4372-a567-0e02b2c3d479\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Create PR with unit tests\n- [ ] <!-- {\"checkboxId\": \"6ba7b810-9dad-11d1-80b4-00c04fd430c8\", \"radioGroupId\": \"utg-output-choice-group-unknown_comment_id\"} -->   Commit unit tests in branch `lk-0625`\n\n</details>\n\n</details>\n\n<!-- finishing_touch_checkbox_end -->\n<!-- tips_start -->\n\n---\n\nThanks for using [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=opentiny/tiny-search-box&utm_content=52)! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.\n\n<details>\n<summary>❤️ Share</summary>\n\n- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)\n- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)\n- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)\n- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)\n\n</details>\n\n\n<sub>Comment `@coderabbitai help` to get the list of available commands.</sub>\n\n<!-- tips_end -->"},"request":{"retryCount":3,"signal":{},"retries":3,"retryAfter":16}}}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 (1)
packages/search-box/src/components/second-level-panel.vue (1)

402-415: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Narrow this watcher to the panel identity.

The deep watch on prevItem will reset scroll and remeasure on any nested mutation under that object, not just when the active panel changes. Watching the specific identity/type signal here will avoid unnecessary work on large datasets.

Suggested change
   watch(
-    () => props.state.prevItem,
+    () => [props.state.prevItem?.type, props.state.prevItem?.field, props.state.prevItem?.label],
     () => {
       vs.vsState.scrollTop = 0
       nextTick(() => {
         if (refs.vsScrollEl) {
           refs.vsScrollEl.scrollTop = 0
           vs.handleScroll({ target: refs.vsScrollEl })
         }
       })
-    },
-    { deep: true }
+    }
   )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/search-box/src/components/second-level-panel.vue` around lines 402 -
415, The watcher in second-level-panel.vue is too broad because it deep-watches
props.state.prevItem and will fire on nested mutations instead of only when the
active panel changes. Narrow the watch source in the existing watch callback to
the panel identity/type signal used by this component, so the reset logic with
vs.vsState.scrollTop, refs.vsScrollEl, and vs.handleScroll only runs when the
panel actually switches. Remove the deep option if it is no longer needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/search-box/src/components/second-level-panel.vue`:
- Around line 39-40: The highlight fragment loop in second-level-panel.vue uses
the fragment text as the Vue key, which can collide when item.match contains
repeated substrings. Update the v-for on the item.match fragments to use a
unique index-based key instead of text, so repeated matches in the search result
render and patch correctly during virtual scrolling. Locate the span v-for tied
to item.match and adjust the key generation to ensure each fragment is uniquely
identified.

---

Nitpick comments:
In `@packages/search-box/src/components/second-level-panel.vue`:
- Around line 402-415: The watcher in second-level-panel.vue is too broad
because it deep-watches props.state.prevItem and will fire on nested mutations
instead of only when the active panel changes. Narrow the watch source in the
existing watch callback to the panel identity/type signal used by this
component, so the reset logic with vs.vsState.scrollTop, refs.vsScrollEl, and
vs.handleScroll only runs when the panel actually switches. Remove the deep
option if it is no longer needed.
🪄 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: 9c85bc00-c35d-46f2-b512-a9d6097ea103

📥 Commits

Reviewing files that changed from the base of the PR and between 57e51ff and 424a123.

📒 Files selected for processing (13)
  • packages/docs/.vitepress/config.mts
  • packages/docs/apis/props.md
  • packages/docs/examples/virtual-scroll.md
  • packages/docs/search-box/virtual-scroll-data.ts
  • packages/docs/search-box/virtual-scroll-options-api.vue
  • packages/docs/search-box/virtual-scroll.vue
  • packages/docs/search-box/webdoc/search-box.js
  • packages/search-box/package.json
  • packages/search-box/src/components/second-level-panel.vue
  • packages/search-box/src/composables/use-virtual-scroll.ts
  • packages/search-box/src/pc.vue
  • packages/search-box/theme-saas/index.less
  • packages/search-box/theme/index.less

Comment thread packages/search-box/src/components/second-level-panel.vue Outdated
zzcr
zzcr previously approved these changes Jun 25, 2026
@zzcr zzcr merged commit c571917 into main Jun 25, 2026
3 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