Skip to content

Conversation

@discreted66
Copy link
Collaborator

@discreted66 discreted66 commented Dec 18, 2025

PR

feat:下拉树支持懒加载,

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

Release Notes

  • New Features

    • Added lazy loading support to the tree-select component, enabling efficient loading of large hierarchical datasets on demand through new configuration options.
  • Improvements

    • Updated select-wrapper component implementation across demo applications for enhanced compatibility and stability.

✏️ 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 18, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 18, 2025

Walkthrough

This PR introduces lazy loading support for TinyTreeSelect, migrates select-wrapper demos to use TinySelectWrapper, and updates base-select's dropdown visibility logic to handle panel slots. Changes span new component props, demo examples, API documentation, and selector updates across multiple demo files.

Changes

Cohort / File(s) Summary
Tree-Select Lazy Loading Feature
examples/sites/demos/apis/tree-select.js, packages/vue/src/tree-select/src/index.ts, packages/vue/src/tree-select/src/pc.vue, packages/vue/src/tree-select/src/mobile-first.vue
Added new props lazy, load, and afterLoad to TreeSelect component API documentation and component definitions with multilingual descriptions and demo references.
Tree-Select Lazy Demo Examples
examples/sites/demos/pc/app/tree-select/lazy.vue, examples/sites/demos/pc/app/tree-select/lazy-multiple.vue, examples/sites/demos/pc/app/tree-select/lazy-composition-api.vue, examples/sites/demos/pc/app/tree-select/lazy-multiple-composition-api.vue, examples/sites/demos/mobile-first/app/tree-select/lazy.vue
New demo files demonstrating lazy-loaded tree-select with single/multiple selection and different API styles (Options/Composition). Each includes load callback for phased data loading and afterLoad hook for lifecycle events.
Tree-Select Demo Registry
examples/sites/demos/pc/app/tree-select/webdoc/tree-select.js, examples/sites/demos/mobile-first/app/tree-select/webdoc/tree-select.js
Added new demo entry (demoId: 'lazy') with localized names and descriptions to make lazy-loading demos discoverable in documentation.
Select-Wrapper Migration (Import Updates)
examples/sites/demos/pc/app/select-wrapper/*.vue (50+ files)
Updated import statements across all select-wrapper demo files to use import { TinySelectWrapper as TinySelect, ... } instead of import { TinySelect, ... }, aliasing the wrapper component for local usage.
Select-Wrapper Migration (Test Updates)
examples/sites/demos/pc/app/select-wrapper/*.spec.ts (40+ files)
Updated Playwright tests to navigate to select-wrapper#* routes instead of select#*, and adjusted DOM selectors from .tiny-select__* to .tiny-base-select__* class references for consistency with wrapper implementation.
Base-Select Panel Slot Logic
packages/renderless/src/base-select/index.ts
Updated defaultOnQueryChange function to accept vm parameter and guard remoteMethod invocation when a panel slot is present, prioritizing filterMethod execution.
Base-Select Visibility Conditions
packages/vue/src/base-select/src/pc.vue, packages/vue/src/base-select/src/mobile-first.vue
Modified dropdown visibility condition from state.emptyText !== false to (slots.panel || state.emptyText !== false), allowing dropdown to render when a panel slot exists or emptyText is not explicitly false.

Sequence Diagram

sequenceDiagram
    actor User
    participant TreeSelect as TinyTreeSelect<br/>(Component)
    participant TreeNode as Tree Node
    participant AsyncLoad as Load Handler
    participant Data as Data Source

    User->>TreeSelect: Click node (lazy=true)
    TreeSelect->>TreeSelect: Check node.level
    alt Initial Load (level === 0)
        TreeSelect->>AsyncLoad: load(node, resolve)
        AsyncLoad->>Data: Fetch top-level nodes
        Data-->>AsyncLoad: [node1, node2, node3]
        AsyncLoad->>TreeSelect: resolve(topNodes)
    else Subsequent Load (has children)
        TreeSelect->>AsyncLoad: load(node, resolve)
        AsyncLoad->>AsyncLoad: setTimeout()
        AsyncLoad->>Data: Generate child nodes<br/>from parent
        Data-->>AsyncLoad: [child1...child5]
        AsyncLoad->>TreeSelect: resolve(childNodes)
    end
    TreeSelect->>TreeNode: Render loaded nodes
    TreeSelect->>TreeSelect: afterLoad(data)
    TreeSelect-->>User: Display expanded tree
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Areas requiring extra attention:

  • Tree-select lazy loading logic in packages/vue/src/tree-select/src/pc.vue and mobile-first.vue — verify defaultExpandAll conditional logic and prop cascading to internal tree component
  • Base-select defaultOnQueryChange refactoring — ensure panel slot guard doesn't break existing remote search behavior in non-wrapper scenarios
  • Dropdown visibility condition changes in base-select — test interaction between panel slots and emptyText state in both PC and mobile-first variants
  • Consistency of DOM class selectors across 50+ select-wrapper demo tests — verify all .tiny-base-select__ references are correct and complete

Possibly related PRs

Suggested labels

enhancement

Suggested reviewers

  • kagol

Poem

🐰 A lazy forest grows in stages,
Each node whispers from the depths,
Wrapper holds the UI's pages,
While data flows with gentle steps.
Select transforms, the tree expands,
Components dance at your command! 🌲✨

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 accurately describes the main change: adding lazy loading support to tree-select component across multiple packages.
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: 8

♻️ Duplicate comments (3)
examples/sites/demos/pc/app/select-wrapper/filter-method.vue (1)

39-39: Wrapper migration - see verification request in disabled.vue.

This file follows the same TinySelectWrapper aliasing pattern. Refer to the verification request in the disabled.vue review.

examples/sites/demos/pc/app/select-wrapper/nest-tree.vue (1)

67-67: Wrapper migration - see verification request in disabled.vue.

This file follows the same TinySelectWrapper aliasing pattern. Refer to the verification request in the disabled.vue review.

examples/sites/demos/pc/app/select-wrapper/allow-create.vue (1)

54-61: Wrapper migration - see verification request in disabled.vue.

This file follows the same TinySelectWrapper aliasing pattern. Refer to the verification request in the disabled.vue review.

🧹 Nitpick comments (8)
examples/sites/demos/pc/app/select-wrapper/filter-method.spec.ts (1)

3-89: Consider extracting shared test logic to reduce duplication.

The two test cases share nearly identical filtering logic. Consider extracting the common test steps into a helper function to improve maintainability.

Example refactor
async function testFilteringBehavior(page, selectIndex: 'first' | number) {
  const wrap = page.locator('#filter-method')
  const select = typeof selectIndex === 'number' 
    ? wrap.locator('.tiny-select').nth(selectIndex)
    : wrap.locator('.tiny-select').first()
  const input = select.locator('.tiny-input__inner')
  const dropdown = page.locator('body > .tiny-select-dropdown')
  const option = dropdown.locator('.tiny-option')

  // Test no match case
  await input.click()
  await expect(page.getByText('No Match')).toBeHidden()
  await input.press('1')
  await expect(input).toHaveValue('1')
  await input.press('Enter')
  await expect(page.getByText('No Match')).toBeVisible()

  await page.waitForTimeout(500)
  let allListItems = await option.all()
  allListItems.forEach(async (item) => {
    await expect(item).toHaveCSS('display', 'none')
  })

  // Test successful filter
  await input.fill('上海')
  await expect(input).toHaveValue('上海')
  await input.press('Enter')
  await page.waitForTimeout(200)

  allListItems.forEach(async (item) => {
    const isVisibleItem = (await item.innerText()) === '上海'
    if (isVisibleItem) {
      await expect(item).toHaveCSS('display', 'flex')
    } else {
      await expect(item).toHaveCSS('display', 'none')
    }
  })
  await expect(option.filter({ hasText: '上海' })).toBeVisible()
  await option.filter({ hasText: '上海' }).click()
  await expect(input).toHaveValue('上海')
}

test('默认搜索', async ({ page }) => {
  page.on('pageerror', (exception) => expect(exception).toBeNull())
  await page.goto('select-wrapper#filter-method')
  await testFilteringBehavior(page, 'first')
})

test('自定义过滤', async ({ page }) => {
  page.on('pageerror', (exception) => expect(exception).toBeNull())
  await page.goto('select-wrapper#filter-method')
  await testFilteringBehavior(page, 1)
})
examples/sites/demos/pc/app/select-wrapper/events.spec.ts (1)

68-68: Refactor to use semantic locators instead of fragile CSS path.

The deep CSS selector .is-show-close > div > .tiny-input__suffix > .tiny-input__suffix-inner > svg is brittle and will break with minor DOM structure changes. This approach is inconsistent with line 29, which correctly uses semantic locators (getByLabel + getByRole).

Consider refactoring to match the pattern used on line 29, or use a more resilient selector like getByRole('button', { name: /clear/i }) or a test-id attribute.

🔎 Suggested approach using semantic locators:
- await page.locator('.is-show-close > div > .tiny-input__suffix > .tiny-input__suffix-inner > svg').first().click()
+ await select.getByRole('img', { name: /clear|close/i }).click()

Or, if the structure matches line 29:

- await page.locator('.is-show-close > div > .tiny-input__suffix > .tiny-input__suffix-inner > svg').first().click()
+ await page.getByLabel('示例', { exact: true }).getByRole('img').nth(1).click()
examples/sites/demos/pc/app/select-wrapper/cache-usage.spec.ts (1)

13-17: Consider the selector change from semantic to CSS class-based.

The selectors changed from getByRole('listitem') to .tiny-option. While this change may be necessary due to the component structure, CSS class-based selectors are more brittle than semantic ARIA-based selectors. If the component's DOM structure or class names change, these tests will break.

If the TinySelectWrapper implementation still exposes proper ARIA roles, consider reverting to semantic selectors for better test resilience:

-  await dropdown.locator('.tiny-option').filter({ hasText: '北京' }).click()
+  await dropdown.getByRole('listitem').filter({ hasText: '北京' }).click()

However, if the component structure genuinely changed and no longer uses list items, the current approach is acceptable.

examples/sites/demos/pc/app/tree-select/lazy-composition-api.vue (1)

13-39: LGTM! Well-structured lazy loading demonstration.

The load function correctly demonstrates async lazy loading with:

  • Initial load detection via node.level === 0
  • Subsequent loads via node.data presence
  • Async simulation with setTimeout
  • Dynamic node properties (disabled, isLeaf)
💡 Optional: Consider clearer random boolean generation

The expression Math.random() - 0.5 > 0 works correctly but could be more readable:

-      disabled: Math.random() - 0.5 > 0, // 随机禁用节点
-      isLeaf: Math.random() - 0.5 > 0 // 随机设置叶子节点
+      disabled: Math.random() > 0.5, // 随机禁用节点
+      isLeaf: Math.random() > 0.5 // 随机设置叶子节点

Both produce 50% probability, but Math.random() > 0.5 is more straightforward.

examples/sites/demos/pc/app/select-wrapper/allow-create.spec.ts (1)

19-19: Consider accessibility implications of selector change.

The test now uses CSS class selectors (.tiny-option) instead of ARIA role selectors (getByRole('listitem')). While this aligns with the wrapper's DOM structure, it reduces verification of accessible markup.

Consider adding explicit accessibility checks:

If the wrapper's option elements should maintain ARIA roles, consider adding a separate test to verify the proper ARIA markup:

// Verify options have proper ARIA roles
await expect(dropdown.locator('[role="option"]').first()).toBeVisible()

Alternatively, if .tiny-option elements intentionally don't use ARIA roles, document this architectural decision.

Also applies to: 24-24, 49-49

examples/sites/demos/pc/app/tree-select/lazy.vue (1)

24-30: Consider async initial load for demo consistency.

The initial load (level 0) resolves synchronously, while subsequent loads (lines 43-44) use setTimeout. This inconsistency may confuse users trying to understand the lazy loading pattern. Consider wrapping the initial resolve in setTimeout as well for a consistent demo experience.

🔎 Suggested change for consistency:
       if (node.level === 0) {
-        resolve([
-          { value: '1', label: '一级 1' },
-          { value: '2', label: '一级 2' },
-          { value: '3', label: '一级 3' }
-        ])
+        setTimeout(() => {
+          resolve([
+            { value: '1', label: '一级 1' },
+            { value: '2', label: '一级 2' },
+            { value: '3', label: '一级 3' }
+          ])
+        }, 500)
       }
examples/sites/demos/apis/tree-select.js (2)

280-305: Type consistency between load and after-load.

The load prop uses inline function signature '(node, resolve) => void' (line 282), while after-load uses generic 'Function' (line 296). Consider using consistent typing approach for both, preferably the more descriptive function signature for after-load as well (e.g., '(data: any) => void').


322-324: Define referenced types ITreeNodeVm and IResolveType.

The interface references ITreeNodeVm and IResolveType but these types are not defined in the types section. Users consulting the API docs won't know what these types represent.

🔎 Add missing type definitions:
 interface ITreeOption {
   data: ITreeNode[] // 树数据,用法同 Tree
   lazy?: boolean // 是否懒加载子节点
-  load?: (node: ITreeNodeVm, resolve: IResolveType) => void // 加载子树数据的方法
+  load?: (node: ITreeNodeVm, resolve: (data: ITreeNode[]) => void) => void // 加载子树数据的方法
   afterLoad?: (data: any) => void // 节点懒加载完成后的回调函数
 }
+
+interface ITreeNodeVm {
+  level: number        // 节点层级
+  data: ITreeNode      // 节点数据
+}
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 851cab3 and 32bf1a1.

📒 Files selected for processing (102)
  • examples/sites/demos/apis/tree-select.js (2 hunks)
  • examples/sites/demos/mobile-first/app/tree-select/lazy.vue (1 hunks)
  • examples/sites/demos/mobile-first/app/tree-select/webdoc/tree-select.js (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/all-text.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/all-text.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/allow-create.spec.ts (3 hunks)
  • examples/sites/demos/pc/app/select-wrapper/allow-create.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/automatic-dropdown.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/select-wrapper/automatic-dropdown.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/basic-usage.spec.ts (3 hunks)
  • examples/sites/demos/pc/app/select-wrapper/basic-usage.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/binding-obj.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/binding-obj.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/cache-usage.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/cache-usage.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/clear-no-match-value.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/select-wrapper/clear-no-match-value.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/clearable.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/select-wrapper/clearable.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/collapse-tags.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/collapse-tags.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/copy-multi.spec.ts (3 hunks)
  • examples/sites/demos/pc/app/select-wrapper/copy-multi.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/copy-single.spec.ts (3 hunks)
  • examples/sites/demos/pc/app/select-wrapper/copy-single.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/disabled.spec.ts (4 hunks)
  • examples/sites/demos/pc/app/select-wrapper/disabled.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/events.spec.ts (3 hunks)
  • examples/sites/demos/pc/app/select-wrapper/events.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/extra-query-params.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/filter-method.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/select-wrapper/filter-method.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/filter-mode.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/hide-drop.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/hide-drop.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/init-label.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/input-box-type.spec.ts (4 hunks)
  • examples/sites/demos/pc/app/select-wrapper/input-box-type.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/is-drop-inherit-width.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/select-wrapper/is-drop-inherit-width.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/manual-focus-blur.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/manual-focus-blur.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/map-field.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/select-wrapper/map-field.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/memoize-usage.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/memoize-usage.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/multiple-mix.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/multiple.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/select-wrapper/multiple.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/native-properties.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/native-properties.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-grid-disable.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-grid-disable.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-grid-init-query.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-grid-remote.spec.ts (5 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-grid-remote.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-grid.spec.ts (3 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-grid.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-radio-grid-much-data.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-radio-grid-much-data.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-tree.spec.ts (3 hunks)
  • examples/sites/demos/pc/app/select-wrapper/nest-tree.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/no-data-text.spec.ts (3 hunks)
  • examples/sites/demos/pc/app/select-wrapper/no-data-text.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/optimization.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/select-wrapper/option-group.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/option-group.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/popup-style-position.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/popup-style-position.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/remote-method.spec.ts (3 hunks)
  • examples/sites/demos/pc/app/select-wrapper/remote-method.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/searchable.spec.ts (2 hunks)
  • examples/sites/demos/pc/app/select-wrapper/searchable.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/show-alloption.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/show-alloption.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/show-tip.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/size.spec.ts (4 hunks)
  • examples/sites/demos/pc/app/select-wrapper/size.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-default.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-default.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-empty.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-empty.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-header-footer.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-header-footer.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-label.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-prefix.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-prefix.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-reference.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/slot-reference.vue (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/tag-type.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/select-wrapper/tag-type.vue (1 hunks)
  • examples/sites/demos/pc/app/tree-select/lazy-composition-api.vue (1 hunks)
  • examples/sites/demos/pc/app/tree-select/lazy-multiple-composition-api.vue (1 hunks)
  • examples/sites/demos/pc/app/tree-select/lazy-multiple.vue (1 hunks)
  • examples/sites/demos/pc/app/tree-select/lazy.vue (1 hunks)
  • examples/sites/demos/pc/app/tree-select/webdoc/tree-select.js (1 hunks)
  • packages/renderless/src/base-select/index.ts (1 hunks)
  • packages/vue/src/base-select/src/mobile-first.vue (1 hunks)
  • packages/vue/src/base-select/src/pc.vue (1 hunks)
  • packages/vue/src/tree-select/src/index.ts (1 hunks)
  • packages/vue/src/tree-select/src/mobile-first.vue (2 hunks)
  • packages/vue/src/tree-select/src/pc.vue (2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2024-11-25T03:43:05.285Z
Learnt from: Davont
Repo: opentiny/tiny-vue PR: 2513
File: packages/vue/src/huicharts/huicharts-histogram/src/chart-histogram.vue:33-36
Timestamp: 2024-11-25T03:43:05.285Z
Learning: 在 Tiny Vue 代码库中,使用 `chart-core` 中的 `huiChartOption` 的组件,不应在其 `data` 中定义 `huiChartOption` 或 `option`,而是应该依赖 `chart-core` 提供的 `huiChartOption`。

Applied to files:

  • examples/sites/demos/pc/app/select-wrapper/slot-label.vue
  • examples/sites/demos/pc/app/select-wrapper/slot-header-footer.vue
  • examples/sites/demos/pc/app/select-wrapper/popup-style-position.vue
  • examples/sites/demos/pc/app/select-wrapper/automatic-dropdown.vue
  • examples/sites/demos/pc/app/select-wrapper/slot-reference.vue
  • examples/sites/demos/pc/app/select-wrapper/collapse-tags.vue
  • examples/sites/demos/pc/app/select-wrapper/remote-method.vue
  • examples/sites/demos/pc/app/select-wrapper/allow-create.vue
  • examples/sites/demos/pc/app/select-wrapper/events.vue
  • examples/sites/demos/pc/app/select-wrapper/option-group.vue
  • examples/sites/demos/pc/app/select-wrapper/clear-no-match-value.vue
  • examples/sites/demos/pc/app/select-wrapper/filter-method.vue
  • examples/sites/demos/pc/app/select-wrapper/show-alloption.vue
  • examples/sites/demos/pc/app/select-wrapper/binding-obj.vue
  • examples/sites/demos/pc/app/select-wrapper/hide-drop.vue
  • examples/sites/demos/pc/app/select-wrapper/disabled.vue
  • examples/sites/demos/pc/app/select-wrapper/show-tip.vue
  • examples/sites/demos/pc/app/select-wrapper/slot-prefix.vue
  • examples/sites/demos/pc/app/select-wrapper/copy-multi.vue
  • examples/sites/demos/pc/app/select-wrapper/memoize-usage.vue
  • examples/sites/demos/pc/app/select-wrapper/copy-single.vue
  • examples/sites/demos/pc/app/select-wrapper/clearable.vue
  • examples/sites/demos/pc/app/select-wrapper/slot-default.vue
  • examples/sites/demos/pc/app/select-wrapper/basic-usage.vue
  • examples/sites/demos/pc/app/select-wrapper/is-drop-inherit-width.vue
  • examples/sites/demos/pc/app/select-wrapper/filter-mode.vue
  • examples/sites/demos/pc/app/select-wrapper/manual-focus-blur.vue
  • examples/sites/demos/pc/app/select-wrapper/all-text.vue
  • examples/sites/demos/pc/app/select-wrapper/input-box-type.vue
  • examples/sites/demos/pc/app/select-wrapper/multiple.vue
  • examples/sites/demos/pc/app/select-wrapper/searchable.vue
  • examples/sites/demos/pc/app/select-wrapper/no-data-text.vue
  • examples/sites/demos/pc/app/select-wrapper/native-properties.vue
  • examples/sites/demos/pc/app/select-wrapper/tag-type.vue
⏰ 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 (100)
examples/sites/demos/pc/app/select-wrapper/manual-focus-blur.spec.ts (1)

5-5: LGTM! Verify test passes with the new component.

The navigation path update from select#manual-focus-blur to select-wrapper#manual-focus-blur correctly aligns with the migration to TinySelectWrapper. The change is consistent with the broader migration pattern across multiple test specs.

Please ensure this test passes with the new select-wrapper component, particularly verifying that the dropdown selector .tiny-select-dropdown on line 7 still correctly targets the rendered dropdown.

examples/sites/demos/pc/app/select-wrapper/hide-drop.spec.ts (1)

5-5: LGTM! Route update aligns with component migration.

The navigation path update from select#hide-drop to select-wrapper#hide-drop correctly reflects the broader migration of select demos to use the select-wrapper component structure. The test logic and assertions remain unchanged and appropriate for verifying the hide-drop functionality.

examples/sites/demos/pc/app/select-wrapper/no-data-text.vue (1)

24-24: LGTM! Import alias correctly migrates to TinySelectWrapper.

The import change aliases TinySelectWrapper as TinySelect, allowing the template and component registration to remain unchanged. This is consistent with the PR-wide migration pattern.

examples/sites/demos/pc/app/select-wrapper/no-data-text.spec.ts (1)

5-5: LGTM! Navigation paths correctly updated.

All three test cases now navigate to select-wrapper#no-data-text, correctly reflecting the demo's new location. The test logic, selectors, and assertions remain unchanged and appropriate.

Also applies to: 18-18, 31-31

examples/sites/demos/pc/app/select-wrapper/searchable.spec.ts (1)

5-5: LGTM! Navigation targets correctly updated for select-wrapper migration.

The changes appropriately update the test navigation URLs from select#searchable to select-wrapper#searchable, aligning with the PR's objective to migrate demos to use TinySelectWrapper. The test logic remains unchanged, which is correct since the component interface is preserved.

Also applies to: 37-37

examples/sites/demos/pc/app/select-wrapper/map-field.spec.ts (1)

5-5: LGTM! Navigation paths updated consistently.

The test navigation paths have been correctly updated to target select-wrapper#map-field instead of select#map-field, aligning with the component migration from TinySelect to TinySelectWrapper.

Also applies to: 25-25

examples/sites/demos/pc/app/select-wrapper/map-field.vue (2)

21-21: LGTM! Import alias maintains API compatibility.

The import has been correctly updated to use TinySelectWrapper aliased as TinySelect, which maintains backward compatibility with the existing template and component registration. This is consistent with the broader demo migration pattern.


1-68: Note: These files don't appear to relate to the PR's stated objective.

The PR title indicates "tree-select support lazy loading", but these files (map-field.vue and map-field.spec.ts) contain standard select component demos with no tree-select or lazy loading functionality. These changes appear to be part of a broader demo migration from TinySelect to TinySelectWrapper rather than the core feature implementation mentioned in the PR objectives.

examples/sites/demos/pc/app/select-wrapper/clear-no-match-value.vue (1)

23-23: Verify that TinySelectWrapper supports the clear-no-match-value prop.

The demo tests the clear-no-match-value feature (lines 7 and 16), which must be fully supported by TinySelectWrapper for this example to work correctly. Ensure the component implementation includes this prop and maintains identical behavior to the original TinySelect.

examples/sites/demos/pc/app/select-wrapper/binding-obj.vue (1)

14-14: Verify TinySelectWrapper API compatibility with demo features.

This demo migrates from TinySelect to TinySelectWrapper. Ensure TinySelectWrapper fully supports: value-key prop for object value identification, v-model binding with object values, and the default slot pattern with <tiny-option> components.

examples/sites/demos/pc/app/select-wrapper/slot-header-footer.spec.ts (1)

5-5: URL correctly updated for component migration.

The navigation URL has been properly updated from select to select-wrapper on line 5. The corresponding demo component exists with matching selectors (.select-header, .select-footer) and expected text content.

examples/sites/demos/pc/app/select-wrapper/searchable.vue (1)

26-26: Clean migration to TinySelectWrapper.

The aliasing approach is clean and requires no changes to the component registration or template. TinySelectWrapper fully supports all props used in this demo: searchable, multiple, and reserve-keyword. This aligns with the PR's objective to migrate select-wrapper demos to use TinySelectWrapper.

examples/sites/demos/pc/app/select-wrapper/nest-radio-grid-much-data.spec.ts (1)

5-5: LGTM! Selector updates align with the select-wrapper migration.

The navigation target and caret selector have been correctly updated to reflect the migration from select to select-wrapper and the internal use of base-select components. These changes are consistent with the PR's objective to refactor the component architecture.

Please verify that the test passes with the updated selectors to confirm they correctly target the DOM elements in the refactored component structure.

Also applies to: 11-11

examples/sites/demos/pc/app/select-wrapper/hide-drop.vue (1)

8-8: No action needed. TinySelectWrapper correctly supports the hide-drop prop. The component is properly exported with the alias, and the demo correctly applies the prop using Vue's kebab-case binding. The implementation is working as designed.

examples/sites/demos/pc/app/select-wrapper/manual-focus-blur.vue (1)

39-39: No changes needed – API compatibility confirmed.

TinySelectWrapper fully supports all APIs used in this demo. Both focus() and blur() methods are properly exposed through the renderless layer, and the filterable and automatic-dropdown props are defined in the component. The import change is correct and maintains full API compatibility.

examples/sites/demos/pc/app/select-wrapper/slot-empty.spec.ts (1)

5-5: LGTM! Path update aligns with component migration.

The navigation path correctly reflects the move from select to select-wrapper. The test logic remains unchanged, which indicates the expected behavior and DOM structure are preserved.

examples/sites/demos/pc/app/select-wrapper/slot-empty.vue (1)

13-13: The demo file is valid. TinySelectWrapper properly supports the #empty slot through its dynamic slot forwarding mechanism (v-for="slotName in slotNames"), and all underlying components (TinyBaseSelect, TinyTreeSelect, TinyGridSelect) define the #empty slot. The custom empty state rendering will work correctly.

examples/sites/demos/pc/app/select-wrapper/native-properties.spec.ts (1)

5-5: Update navigation URL to match select-wrapper component migration

The change from select#native-properties to select-wrapper#native-properties is correct and aligns with migrating the demo to use TinySelectWrapper. The corresponding demo file at examples/sites/demos/pc/app/select-wrapper/native-properties.vue exists with the same DOM structure, ensuring all test selectors (.tiny-select, .tiny-input__inner) work correctly without further modifications.

examples/sites/demos/pc/app/select-wrapper/clear-no-match-value.spec.ts (1)

5-5: Navigation routes updated correctly for select-wrapper migration.

The changes from select#clear-no-match-value to select-wrapper#clear-no-match-value have been verified in both test blocks (lines 5 and 16), and the element selectors are correctly preserved at lines 6 and 17. The test logic remains unchanged and both tests are updated identically, consistent with the demo migration objectives.

examples/sites/demos/pc/app/select-wrapper/show-alloption.spec.ts (1)

5-5: Navigation URL updated to select-wrapper demo component.

The test now correctly navigates to select-wrapper#show-alloption. All existing selectors (.tiny-select, .tiny-select-dropdown, .tiny-option) are compatible with the select-wrapper component, as both components maintain the same DOM structure and CSS classes.

packages/vue/src/base-select/src/pc.vue (1)

361-361: Panel slot visibility logic correctly enables lazy loading for tree-select and grid-select.

The change properly allows the dropdown to render when a panel slot is provided, even if state.emptyText === false. This is essential for lazy loading where tree/grid panels need to display loading states before data arrives. The complementary v-if="!slots.panel" guard on line 529 prevents duplicate rendering of empty text.

Tree-select and grid-select already use this #panel slot pattern and will benefit from this change without issues. No backward compatibility concerns identified—components without panel slots retain the previous behavior.

examples/sites/demos/pc/app/select-wrapper/nest-radio-grid-much-data.vue (1)

7-7: Grid render type is fully supported by TinySelectWrapper.

This change migrates from TinySelect to TinySelectWrapper, which is a wrapper component that dynamically routes to TinyGridSelect when renderType='grid'. The wrapper properly passes through both the renderType prop and gridOp configuration to handle the grid layout, radio selection mode, and large dataset (800 items) as demonstrated in this file. The import change is a safe refactoring with no functional impact.

packages/vue/src/base-select/src/mobile-first.vue (1)

378-378: LGTM! Panel slot integration with tree-select is properly implemented.

The visibility condition correctly enables custom panel slots for tree-select lazy loading. Both tree-select implementations (mobile-first and pc) provide a panel slot wrapping a tree component with lazy loading support through the lazy, load, and afterLoad props. The logic properly ensures the dropdown shows when either a panel slot is provided OR emptyText is not explicitly false, which aligns with the intended functionality.

The change is consistent with the empty text rendering logic at lines 554-568, which only displays when no panel slot exists, preventing conflicts with custom panel content.

examples/sites/demos/pc/app/select-wrapper/slot-prefix.spec.ts (1)

5-5: LGTM! Navigation path correctly updated.

The navigation path change from select#slot-prefix to select-wrapper#slot-prefix correctly aligns with the component migration. All test assertions and locators remain unchanged, maintaining consistent test coverage.

examples/sites/demos/pc/app/select-wrapper/slot-prefix.vue (1)

11-11: The import and feature usage are correct—no API compatibility issues exist.

The TinySelectWrapper fully supports all features used in this demo. It exports modelValue for v-model binding, multiple and collapseTags props, and dynamically forwards all named slots (including #prefix) to the underlying TinyBaseSelect component via its slot forwarding mechanism. The aliasing is safe and maintains complete API parity.

Likely an incorrect or invalid review comment.

examples/sites/demos/pc/app/select-wrapper/filter-mode.vue (1)

26-26: No issues found. TinySelect and TinySelectWrapper are distinct components, both exported from @opentiny/vue. The file is correctly located in the select-wrapper demo folder and properly imports TinySelectWrapper—the component designed for this folder. The aliasing pattern (TinySelectWrapper as TinySelect) is intentional and consistently used across all select-wrapper demos for convenience, not a migration or deprecation. Both components remain available and functional for their respective use cases.

examples/sites/demos/pc/app/select-wrapper/option-group.spec.ts (1)

5-5: LGTM! Test route updated to match component migration.

The navigation target correctly updates from select#option-group to select-wrapper#option-group, aligning with the migration to TinySelectWrapper. All test selectors and assertions remain valid.

Please ensure the demo site routing configuration includes the select-wrapper#option-group route and that all tests pass after this change.

examples/sites/demos/pc/app/select-wrapper/option-group.vue (1)

61-61: No changes needed—the import and usage are correct.

The import properly uses TinySelectWrapper with an alias for cleaner template syntax. TinyOption and TinyOptionGroup are correctly exported and fully compatible with SelectWrapper, as evidenced by consistent usage across multiple demo files in the repository.

examples/sites/demos/pc/app/select-wrapper/popup-style-position.spec.ts (1)

5-5: Navigation path correctly updated for select-wrapper migration.

The navigation target change from select#popup-style-position to select-wrapper#popup-style-position aligns with the component migration pattern.

examples/sites/demos/pc/app/select-wrapper/popup-style-position.vue (1)

8-8: No API compatibility issues found. TinySelectWrapper fully supports all props used in the template (v-model, popper-class, popper-append-to-body, placement) with correct bindings and defaults. The import statement is valid and the component usage is compatible.

examples/sites/demos/pc/app/select-wrapper/slot-reference.vue (1)

11-11: The import pattern is correct and follows library conventions.

TinySelectWrapper is the official export name for the SelectWrapper component from @opentiny/vue (as defined in packages/vue/index.ts and packages/vue/pc.ts). This aliasing approach is standard throughout the TinyVue library. The demo correctly uses the #reference slot with TinySelectWrapper, which is fully supported and consistently used across all select-wrapper demo files.

examples/sites/demos/pc/app/select-wrapper/slot-reference.spec.ts (1)

5-5: Route verified and exists.

The navigation route select-wrapper#slot-reference is correctly configured. The corresponding demo file exists at examples/sites/demos/pc/app/select-wrapper/slot-reference.vue with valid DOM structure, and the test locators reference elements that will be present when the demo is loaded.

examples/sites/demos/pc/app/select-wrapper/tag-type.spec.ts (1)

5-5: LGTM! Navigation path updated to match component wrapper.

The test navigation correctly changes from select#tag-type to select-wrapper#tag-type, aligning with the component migration to TinySelectWrapper. All element selectors remain unchanged, which is appropriate since the DOM structure is preserved.

examples/sites/demos/pc/app/select-wrapper/tag-type.vue (1)

8-8: No action required—TinySelectWrapper fully supports all props used in this demo.

The component TinySelectWrapper is properly exported from @opentiny/vue and has identical prop support for modelValue, multiple, and tagType as the standard Select component. The import alias and template usage are correct and compatible.

Likely an incorrect or invalid review comment.

packages/renderless/src/base-select/index.ts (3)

68-68: No action required. The vm parameter addition to defaultOnQueryChange is not a breaking change. The parameter is correctly captured in the factory function's closure in base-select/vue.ts (line 484) where vm is passed. All callers of api.defaultOnQueryChange(value, isInput) remain unchanged.


75-75: The panel slot detection guard already works reliably across component types. Tree-select properly defines and uses the panel slot in both pc.vue and mobile-first.vue, rendering a custom <tiny-tree> component within it. When the panel slot is present, the !vm.$slots?.panel check correctly prevents automatic remoteMethod invocation, allowing tree-select to manage remote searches through its own logic. The optional chaining syntax ensures safe access across all components extending base-select.


70-78: Complex conditional flow prioritizes filterMethod with guarded remoteMethod fallback.

The restructured logic now calls filterMethod first when available, followed by a conditional remoteMethod call only when remote is true, remoteMethod exists, and no panel slot is present. However, the claim about duplicate API calls with grid-select is misleading—grid-select's filterMethod performs client-side filtering on full data and doesn't invoke remote searches internally. The panel slot guard (!vm.$slots?.panel) is specifically for tree-select lazy loading compatibility.

The execution flow is more complex than before. Consider:

  1. Documenting the intent that this change supports tree-select lazy loading while maintaining backward compatibility
  2. Clarifying that grid-select's filterMethod operates client-side only
  3. Evaluating whether the panel slot detection is the most reliable guard across all use cases and Vue versions
examples/sites/demos/pc/app/select-wrapper/events.spec.ts (1)

5-5: LGTM: Navigation updated to reflect demo migration.

The navigation target correctly points to select-wrapper#events, aligning with the migration of select demos to use TinySelectWrapper.

Also applies to: 37-37

examples/sites/demos/pc/app/select-wrapper/remote-method.spec.ts (2)

5-5: LGTM! Navigation updated to select-wrapper route.

The navigation changes consistently update all three tests to use the select-wrapper#remote-method route, aligning with the PR's migration of select-wrapper demos to use TinySelectWrapper.

Also applies to: 27-27, 56-56


31-31: Selectors are correct and intentionally different by component design.

The test uses appropriate selectors for each scenario: single-select tests (lines 9, 60) correctly use .tiny-input__inner because they render through the TinyInput wrapper component, while the multi-select test (line 31) correctly uses .tiny-base-select__input for the inline filtering input. This difference reflects the intended DOM structure variation between single and multiple selection modes, not an incomplete migration.

Likely an incorrect or invalid review comment.

examples/sites/demos/pc/app/select-wrapper/slot-default.spec.ts (1)

5-5: LGTM! Navigation target updated consistently.

The test navigation has been updated to align with the component migration to TinySelectWrapper. The unchanged test selectors and assertions indicate that the wrapper maintains DOM compatibility.

examples/sites/demos/pc/app/select-wrapper/copy-single.spec.ts (1)

5-5: LGTM! Consistent navigation updates across all test cases.

All three test cases have been updated to navigate to the wrapper-based route. The test logic remains unchanged, indicating DOM compatibility.

Also applies to: 29-29, 56-56

examples/sites/demos/pc/app/select-wrapper/collapse-tags.vue (1)

29-29: Import aliasing maintains template compatibility.

The import has been systematically updated to use TinySelectWrapper with the TinySelect alias, ensuring all three select instances in the template continue to work without modification.

examples/sites/demos/pc/app/select-wrapper/is-drop-inherit-width.spec.ts (1)

5-5: LGTM! Navigation updates are consistent.

Both test cases have been updated to navigate to the wrapper-based route. The dropdown width calculation logic remains unchanged, assuming compatible rendering behavior.

Also applies to: 23-23

examples/sites/demos/pc/app/select-wrapper/memoize-usage.spec.ts (1)

5-5: LGTM! Navigation target updated.

The test has been updated to navigate to the wrapper-based route while preserving all caching validation logic.

examples/sites/demos/pc/app/select-wrapper/remote-method.vue (1)

106-106: Import aliasing preserves complex remote search functionality.

The import has been updated to use TinySelectWrapper with the TinySelect alias. This allows all six remote search scenarios in the template to continue working without modification, including the various remote-method and remote-config configurations.

examples/sites/demos/pc/app/select-wrapper/multiple.spec.ts (1)

5-5: LGTM! Navigation updates maintain test coverage.

Both test cases have been updated to navigate to the wrapper-based route. The multiple selection logic and limit validation remain unchanged, ensuring consistent test coverage.

Also applies to: 30-30

examples/sites/demos/pc/app/select-wrapper/memoize-usage.vue (1)

21-21: Import aliasing is correct and migration pattern is clean.

TinySelectWrapper provides full API compatibility with the original component through a proxy pattern that uses v-bind="mergedProps" and v-on="listeners" to forward all props, events, and slots. This ensures v-model, options, event handlers, and custom attributes work as expected.

examples/sites/demos/pc/app/select-wrapper/collapse-tags.spec.ts (1)

5-5: LGTM!

The navigation path update from select#collapse-tags to select-wrapper#collapse-tags correctly aligns with the component migration to TinySelectWrapper.

examples/sites/demos/pc/app/select-wrapper/slot-header-footer.vue (1)

18-18: LGTM!

The import aliasing to TinySelectWrapper is consistent with the broader refactoring. The template uses standard slot features (#dropdown, #footer) which should be well-supported.

examples/sites/demos/pc/app/select-wrapper/show-alloption.vue (1)

8-8: LGTM!

The import aliasing maintains template compatibility while switching to TinySelectWrapper. The demo uses standard props that should be well-supported.

examples/sites/demos/pc/app/select-wrapper/is-drop-inherit-width.vue (1)

18-18: LGTM!

The import aliasing to TinySelectWrapper is consistent with the migration pattern. The demo showcases dropdown width behavior which should work correctly with the wrapper component.

examples/sites/demos/pc/app/select-wrapper/cache-usage.spec.ts (1)

5-5: LGTM!

The navigation path correctly updated to select-wrapper#cache-usage to align with the component migration.

examples/sites/demos/pc/app/select-wrapper/slot-label.vue (1)

22-22: LGTM!

The import aliasing maintains compatibility while using TinySelectWrapper. The #label slot for custom rendering is a standard feature that should be well-supported.

examples/sites/demos/pc/app/select-wrapper/nest-grid-disable.vue (1)

57-57: TinySelectWrapper fully supports grid-specific rendering props.

The component explicitly defines renderType, gridOp, radioConfig, and selectConfig in its prop interface, with proper default values and rendering logic in place. The demo file demonstrates working implementation of all these props. The import alias does not affect functionality.

Likely an incorrect or invalid review comment.

examples/sites/demos/pc/app/select-wrapper/copy-multi.vue (1)

44-44: TinySelectWrapper supports all copy-related props.

The component definition in packages/vue/src/select-wrapper/src/pc.vue includes all three props mentioned in the demo: tagSelectable (used as tag-selectable), copyable, and textSplit (used as text-split). The import alias is valid, and all props are correctly utilized in the demo file.

examples/sites/demos/pc/app/select-wrapper/size.vue (1)

25-25: LGTM! Systematic refactor to use TinySelectWrapper.

The aliasing of TinySelectWrapper as TinySelect maintains backward compatibility in the template while switching to the wrapper implementation. This pattern is consistently applied across multiple select-wrapper demos in this PR.

examples/sites/demos/pc/app/select-wrapper/size.spec.ts (1)

5-5: LGTM! Navigation updates aligned with component changes.

The test navigation targets have been correctly updated from select#size to select-wrapper#size to match the underlying component switch to TinySelectWrapper. All test logic and assertions remain intact.

Also applies to: 18-18, 33-33, 49-49

examples/sites/demos/pc/app/select-wrapper/all-text.vue (1)

16-16: LGTM! Consistent aliasing pattern.

The import aliasing follows the same pattern as other select-wrapper demos, switching to TinySelectWrapper while preserving the TinySelect identifier for backward compatibility.

examples/sites/demos/pc/app/select-wrapper/all-text.spec.ts (1)

5-5: LGTM! Test navigation updated correctly.

The navigation target has been updated to select-wrapper#all-text to align with the component wrapper changes.

examples/sites/demos/pc/app/select-wrapper/input-box-type.spec.ts (2)

5-5: LGTM! Navigation updates aligned with component wrapper.

The test navigation targets have been correctly updated to select-wrapper#input-box-type.

Also applies to: 27-27, 50-50


70-70: Class name update reflects component structure change.

The assertion now expects tiny-base-select__multiple instead of tiny-select__multiple, which aligns with the internal component refactor to use base-select classes. The test will verify this is correct at runtime.

examples/sites/demos/pc/app/tree-select/lazy-composition-api.vue (1)

41-43: afterLoad hook appropriately demonstrates lifecycle.

The afterLoad implementation logs the loaded data, which is suitable for a demo that shows developers how to hook into the loading lifecycle.

examples/sites/demos/pc/app/select-wrapper/show-tip.vue (1)

8-8: LGTM! Consistent with refactor pattern.

The import aliasing follows the established pattern across select-wrapper demos.

examples/sites/demos/pc/app/select-wrapper/input-box-type.vue (1)

26-26: LGTM! Completes the consistent refactor pattern.

The import aliasing is consistent with all other select-wrapper demos, completing the systematic migration to TinySelectWrapper.

examples/sites/demos/pc/app/select-wrapper/slot-default.vue (1)

37-37: LGTM!

The import alias change from TinySelect to TinySelectWrapper as TinySelect aligns with the project-wide migration pattern observed across other select-wrapper demo files.

packages/vue/src/tree-select/src/mobile-first.vue (1)

162-169: LGTM!

The lazy loading props are well-defined with appropriate types and defaults, consistent with the main component definition in index.ts.

examples/sites/demos/pc/app/tree-select/lazy-multiple.vue (1)

1-65: LGTM!

This demo effectively illustrates the new lazy loading feature with multiple selection. The console.log statements serve as helpful documentation for developers learning the API, and the random delays appropriately simulate async data fetching.

packages/vue/src/tree-select/src/index.ts (1)

103-110: LGTM!

The new lazy loading props (lazy, load, afterLoad) are well-defined and extend the component's public API appropriately. The types and defaults are consistent with the template implementations in pc.vue and mobile-first.vue.

packages/vue/src/tree-select/src/pc.vue (1)

105-112: LGTM!

The lazy loading prop definitions are consistent with index.ts and mobile-first.vue, maintaining API uniformity across the component variants.

examples/sites/demos/pc/app/select-wrapper/copy-multi.spec.ts (1)

5-52: LGTM! Navigation targets and selectors updated consistently.

The test navigation targets have been correctly updated from select#copy-multi to select-wrapper#copy-multi, and the copy icon selector has been updated from .tiny-select__copy to .tiny-base-select__copy. These changes align with the broader migration to TinySelectWrapper.

examples/sites/demos/pc/app/select-wrapper/nest-grid.spec.ts (1)

5-95: LGTM! Consistent selector updates across all test cases.

Navigation targets and caret selectors have been correctly updated throughout the file to use select-wrapper#nest-grid and .tiny-base-select__caret, maintaining consistency with the wrapper-based component refactoring.

examples/sites/demos/pc/app/select-wrapper/init-label.vue (1)

29-29: LGTM! Import alias maintains backward compatibility.

The import has been updated to use TinySelectWrapper as TinySelect, which allows the component to use the wrapper implementation while maintaining the same template syntax and component registration. This is a clean refactoring approach.

examples/sites/demos/pc/app/select-wrapper/disabled.spec.ts (1)

5-88: LGTM! Navigation targets updated consistently.

All four test cases have been correctly updated to navigate to select-wrapper#disabled instead of select#disabled, aligning with the component migration.

examples/sites/demos/pc/app/select-wrapper/nest-tree.spec.ts (1)

5-84: LGTM! Tree select tests updated consistently.

Navigation targets and caret selectors have been properly updated across all three test cases to use select-wrapper#nest-tree and .tiny-base-select__caret, maintaining consistency with the wrapper migration.

examples/sites/demos/pc/app/select-wrapper/optimization.spec.ts (1)

5-46: LGTM! Virtual scrolling tests updated.

Both virtual scrolling test cases have been correctly updated to navigate to select-wrapper#optimization.

examples/sites/demos/pc/app/select-wrapper/automatic-dropdown.spec.ts (1)

5-31: LGTM! Improved selector specificity.

Navigation targets updated correctly. Additionally, the option selection strategy has been improved by using dropdown.locator('.tiny-option') instead of page.getByRole('listitem'), which provides better scope and specificity for the dropdown options.

examples/sites/demos/pc/app/select-wrapper/nest-grid-disable.spec.ts (1)

5-41: LGTM! Navigation targets updated consistently.

Both test cases have been correctly updated to navigate to select-wrapper#nest-grid-disable.

examples/sites/demos/pc/app/select-wrapper/basic-usage.spec.ts (1)

5-5: Test updates align with component migration.

The navigation target and selector updates correctly reflect the migration from TinySelect to TinySelectWrapper. The switch from ARIA role-based selectors to CSS class-based selectors (.tiny-option) is consistent throughout the test suite.

Also applies to: 9-9, 16-16, 28-28, 39-39

examples/sites/demos/pc/app/select-wrapper/binding-obj.spec.ts (1)

5-5: LGTM!

Test navigation and selector updates correctly reflect the component migration to select-wrapper.

Also applies to: 13-13, 18-18

examples/sites/demos/pc/app/select-wrapper/native-properties.vue (1)

8-8: Verify API compatibility between TinySelectWrapper and TinySelect.

This file follows the same import aliasing pattern as other demos in this PR. Ensure TinySelectWrapper is fully compatible with TinySelect's API surface (props, events, slots, methods).

examples/sites/demos/pc/app/select-wrapper/clearable.spec.ts (1)

5-5: LGTM!

Test updates properly reflect the select-wrapper component migration.

Also applies to: 19-19

examples/sites/demos/pc/app/select-wrapper/nest-grid-remote.vue (1)

63-63: Verify API compatibility between TinySelectWrapper and TinySelect.

This follows the same import aliasing pattern as other select-wrapper demos. Verify compatibility as noted in earlier comments.

examples/sites/demos/pc/app/select-wrapper/extra-query-params.vue (1)

47-47: Verify API compatibility between TinySelectWrapper and TinySelect.

Import aliasing follows the established pattern. Verify TinySelectWrapper compatibility as discussed in earlier comments.

examples/sites/demos/pc/app/select-wrapper/nest-grid-init-query.vue (1)

45-45: Verify API compatibility between TinySelectWrapper and TinySelect.

This is the final demo file following the import aliasing pattern. Ensure TinySelectWrapper maintains full API compatibility with TinySelect.

examples/sites/demos/pc/app/select-wrapper/multiple-mix.vue (1)

20-20: SelectWrapper is intentionally designed as a component adapter, not a direct alias for Select.

TinySelectWrapper (SelectWrapper) is a wrapper component that dynamically delegates to TinyBaseSelect, TinyTreeSelect, or TinyGridSelect based on the renderType prop. While the import aliasing pattern TinySelectWrapper as TinySelect is used consistently across select-wrapper demos, note that there are API differences:

  • Prop naming: inputBoxType (SelectWrapper) vs InputBoxType (Select)
  • Default values: 'normal' vs 'input' respectively

This demo currently uses only common compatible props (options, multiple, hover-expand, display-only), so it functions correctly. However, be aware that if specific Select-only properties are introduced, they may not be available in SelectWrapper.

examples/sites/demos/pc/app/select-wrapper/allow-create.spec.ts (1)

6-6: Navigation path updated to select-wrapper scope.

The test now navigates to select-wrapper#allow-create instead of select#allow-create, aligning with the component wrapper migration.

examples/sites/demos/pc/app/select-wrapper/multiple.vue (1)

103-103: Verify advanced multi-select features with TinySelectWrapper.

This demo exercises extensive multi-select functionality including collapse-tags, hover-expand, click-expand, show-all-text-tag, multiple-limit, and required/disabled options. Ensure all features work correctly with the wrapper implementation.

examples/sites/demos/pc/app/select-wrapper/copy-single.vue (1)

35-35: This concern is incorrect. TinySelectWrapper intentionally exposes child component state via a Proxy pattern, with cachedOptions explicitly mentioned in code comments as part of the public API. Multiple official demos consistently use this pattern, confirming it is the designed approach for accessing cached options.

Likely an incorrect or invalid review comment.

examples/sites/demos/pc/app/select-wrapper/nest-grid.vue (1)

41-41: No action required. TinySelectWrapper properly supports render-type="grid" and the grid-op prop. The component defines both props (renderType and gridOp) with appropriate defaults, imports TinyGridSelect for grid rendering, and the demo in nest-grid.vue demonstrates three working scenarios: single selection, multi-selection, and filterable grid rendering.

examples/sites/demos/pc/app/tree-select/lazy-multiple-composition-api.vue (1)

1-58: LGTM! Lazy loading demo is well-implemented.

The composition API demo correctly demonstrates lazy loading with multiple selection. The load function properly handles both initial and subsequent loads, and the random disabled/isLeaf flags effectively showcase dynamic node properties.

examples/sites/demos/pc/app/tree-select/webdoc/tree-select.js (1)

71-84: LGTM! Complete demo documentation.

The lazy loading demo entry is properly documented with both Chinese and English descriptions, correctly formatted, and appropriately positioned in the demos array.

examples/sites/demos/mobile-first/app/tree-select/lazy.vue (1)

1-59: LGTM! Mobile-first lazy loading demo is well-implemented.

The demo correctly implements lazy loading for mobile-first context. The load function properly handles both initial and subsequent node loads, and the attribute selector styles are appropriate for mobile-first components.

examples/sites/demos/pc/app/select-wrapper/disabled.vue (1)

71-71: SelectWrapper migration is verified as API-compatible. SelectWrapper is properly exported as TinySelectWrapper and provides full API compatibility with comprehensive props forwarding and slot delegation. All demo scenarios (disabled states, multiple selection, hover-expand, etc.) function correctly without changes.

examples/sites/demos/pc/app/select-wrapper/nest-grid-remote.spec.ts (3)

6-6: LGTM on URL migrations.

The navigation targets have been consistently updated from select#nest-grid-remote to select-wrapper#nest-grid-remote across all test blocks.

Also applies to: 42-42, 72-72, 104-104


12-12: Selector updates align with base-select component structure.

The class selectors have been correctly updated from .tiny-select__caret to .tiny-base-select__caret and .tiny-select__input to .tiny-base-select__input, consistent with the TinySelectWrapper migration.

Also applies to: 48-48, 75-77, 108-110


27-28: Verify trimmed row name expectations match actual data.

The row name patterns changed from including trailing numbers (e.g., '省份 1 城市 1 区域 1') to trimmed forms ('省份 1 城市 1 区域'). Ensure these match the actual grid data rendered by the demo; otherwise, the test assertions will fail.

examples/sites/demos/pc/app/tree-select/lazy.vue (1)

36-44: Demo logic is clear and appropriately randomized.

The random disabled and isLeaf flags effectively demonstrate the lazy loading flexibility. The simulated async delay via setTimeout clearly shows how to integrate with real API calls.

examples/sites/demos/pc/app/select-wrapper/events.vue (1)

38-38: Import alias maintains template compatibility.

Using TinySelectWrapper as TinySelect allows the demo to use the new wrapper component without requiring template changes. This is a clean migration pattern.

examples/sites/demos/apis/tree-select.js (1)

268-279: Lazy loading API documentation is well-structured.

The prop definitions include appropriate defaults, bilingual descriptions, and demo references for both pc and mobile-first modes.

Comment on lines +71 to +82
{
demoId: 'lazy',
name: {
'zh-CN': '懒加载',
'en-US': 'Lazy loading'
},
desc: {
'zh-CN':
'通过 <code>lazy</code> 属性,启用懒加载模式。<br>通过 <code>load</code> 函数属性,触发加载,初始会执行一次。<br>通过 <code>after-load</code> 函数属性,监听下级节点加载完毕的事件。'
},
codeFiles: ['lazy.vue']
},
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 en-US description.

The new lazy demo entry is missing the en-US description (Line 80), while the zh-CN description is complete. The PC version of this file (examples/sites/demos/pc/app/tree-select/webdoc/tree-select.js) includes both translations. Add the en-US description for i18n completeness.

🔎 Apply this diff to add the missing en-US description:
       desc: {
         'zh-CN':
-          '通过 <code>lazy</code> 属性,启用懒加载模式。<br>通过 <code>load</code> 函数属性,触发加载,初始会执行一次。<br>通过 <code>after-load</code> 函数属性,监听下级节点加载完毕的事件。'
+          '通过 <code>lazy</code> 属性,启用懒加载模式。<br>通过 <code>load</code> 函数属性,触发加载,初始会执行一次。<br>通过 <code>after-load</code> 函数属性,监听下级节点加载完毕的事件。',
+        'en-US':
+          'Enable lazy loading mode with the <code>lazy</code> property. <br>load is triggered by the <code>load</code> function property, which is initially executed once. <br>afterLoad </code> function properties are used to listen for events when a subordinate node has finished loading.'
       },
🤖 Prompt for AI Agents
In examples/sites/demos/mobile-first/app/tree-select/webdoc/tree-select.js
around lines 71 to 82, the demo entry for 'lazy' has a zh-CN description but is
missing the en-US description; add an 'en-US' field mirroring the zh-CN content
in English (e.g. "Enable lazy loading via the <code>lazy</code> prop. Use the
<code>load</code> function prop to trigger loading — it runs once initially. Use
the <code>after-load</code> function prop to listen for when child nodes finish
loading.") so both locales are present for i18n completeness.


<script>
import { TinySelect, TinyOption } from '@opentiny/vue'
import { TinySelectWrapper as TinySelect, TinyOption } from '@opentiny/vue'
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for TinySelectWrapper and TinySelect in the repository
# First, find the main export files for these components

echo "=== Searching for TinySelectWrapper definition ==="
fd -t f "select-wrapper" -i | head -20

echo -e "\n=== Searching for TinySelect definition ==="
fd -t f "select" -i | grep -v node_modules | grep -v dist | head -20

echo -e "\n=== Looking for export statements with TinySelectWrapper ==="
rg -n "export.*TinySelectWrapper" --type=ts --type=vue

echo -e "\n=== Looking for export statements with TinySelect ==="
rg -n "export.*TinySelect" --type=ts --type=vue | grep -v TinySelectWrapper | head -10

Repository: opentiny/tiny-vue

Length of output: 1958


🏁 Script executed:

#!/bin/bash
# Let's find the actual component source code

echo "=== Finding package structure ==="
ls -la packages/ | head -20

echo -e "\n=== Searching for select-wrapper component source ==="
find . -path ./node_modules -prune -o -path ./dist -prune -o -type f -name "*select-wrapper*" -print | head -20

echo -e "\n=== Searching for select component source ==="
find . -path ./node_modules -prune -o -path ./dist -prune -o -type f -name "*select.vue" -o -name "*select.ts" -print | grep -E "packages|src" | head -20

echo -e "\n=== Looking in vue package ==="
ls -la packages/vue/src/components/ | grep -i select

Repository: opentiny/tiny-vue

Length of output: 2090


🏁 Script executed:

#!/bin/bash
# Let's explore the vue package structure

echo "=== Structure of packages/vue ==="
ls -la packages/vue/src/

echo -e "\n=== Looking for select components ==="
ls -la packages/vue/src/

echo -e "\n=== Find all select-related files ==="
find packages/vue -name "*select*" -type f 2>/dev/null | grep -v node_modules | head -20

echo -e "\n=== Find select.ts or select.vue in packages ==="
find packages -name "select.ts" -o -name "select.vue" 2>/dev/null | grep -v node_modules | head -20

Repository: opentiny/tiny-vue

Length of output: 25878


🏁 Script executed:

#!/bin/bash
# Let's look at what files are in select and select-wrapper directories

echo "=== Files in select directory ==="
ls -la packages/vue/src/select/

echo -e "\n=== Files in select-wrapper directory ==="
ls -la packages/vue/src/select-wrapper/

echo -e "\n=== Content of select-wrapper index ==="
cat packages/vue/src/select-wrapper/index.ts 2>/dev/null || echo "Not found"

echo -e "\n=== Content of select index ==="
cat packages/vue/src/select/index.ts 2>/dev/null || echo "Not found"

Repository: opentiny/tiny-vue

Length of output: 2814


🏁 Script executed:

#!/bin/bash
# Let's check the src directories

echo "=== Files in select/src ==="
ls -la packages/vue/src/select/src/

echo -e "\n=== Files in select-wrapper/src ==="
ls -la packages/vue/src/select-wrapper/src/

echo -e "\n=== Content of select-wrapper/src/index.vue ==="
head -100 packages/vue/src/select-wrapper/src/index.vue 2>/dev/null || echo "Not found"

echo -e "\n=== Content of select/src/index.vue ==="
head -100 packages/vue/src/select/src/index.vue 2>/dev/null || echo "Not found"

Repository: opentiny/tiny-vue

Length of output: 941


🏁 Script executed:

#!/bin/bash
# Let's check the index.ts files which contain the actual component logic

echo "=== Content of select-wrapper/src/index.ts ==="
cat packages/vue/src/select-wrapper/src/index.ts

echo -e "\n=== Content of select/src/index.ts (first 150 lines) ==="
head -150 packages/vue/src/select/src/index.ts

Repository: opentiny/tiny-vue

Length of output: 10964


🏁 Script executed:

#!/bin/bash
# Let's get the complete select/src/index.ts to compare props

echo "=== Full content of select/src/index.ts ==="
cat packages/vue/src/select/src/index.ts

Repository: opentiny/tiny-vue

Length of output: 7658


🏁 Script executed:

#!/bin/bash
# Let's compare the props more carefully - let me extract and compare them

echo "=== Analyzing prop differences ==="
python3 << 'EOF'
import re

# Read both files
with open('packages/vue/src/select-wrapper/src/index.ts', 'r') as f:
    wrapper_content = f.read()

with open('packages/vue/src/select/src/index.ts', 'r') as f:
    select_content = f.read()

# Extract props section
wrapper_props = re.search(r'props:\s*\{(.*?)\n  \},', wrapper_content, re.DOTALL)
select_props = re.search(r'props:\s*\{(.*?)\n  \},', select_content, re.DOTALL)

if wrapper_props and select_props:
    wrapper_text = wrapper_props.group(1)
    select_text = select_props.group(1)
    
    # Find differences by comparing line by line
    wrapper_lines = set(wrapper_text.strip().split('\n'))
    select_lines = set(select_text.strip().split('\n'))
    
    only_in_wrapper = wrapper_lines - select_lines
    only_in_select = select_lines - wrapper_lines
    
    if only_in_wrapper or only_in_select:
        print("Props ONLY in SelectWrapper:")
        for line in sorted(only_in_wrapper):
            if line.strip():
                print(f"  {line.strip()}")
        
        print("\nProps ONLY in Select:")
        for line in sorted(only_in_select):
            if line.strip():
                print(f"  {line.strip()}")
    else:
        print("All props are identical between SelectWrapper and Select")
else:
    print("Could not parse props")
EOF

Repository: opentiny/tiny-vue

Length of output: 147


🏁 Script executed:

#!/bin/bash
# Let's do a simple diff instead

echo "=== Diff between select-wrapper and select props ==="
diff -u <(sed -n '/props: {/,/},/p' packages/vue/src/select/src/index.ts | grep -E "^\s+(.*?):" | head -50) <(sed -n '/props: {/,/},/p' packages/vue/src/select-wrapper/src/index.ts | grep -E "^\s+(.*?):" | head -50)

echo -e "\n=== Check for InputBoxType vs inputBoxType ==="
grep -n "inputBoxType\|InputBoxType" packages/vue/src/select/src/index.ts
grep -n "inputBoxType\|InputBoxType" packages/vue/src/select-wrapper/src/index.ts

Repository: opentiny/tiny-vue

Length of output: 314


🏁 Script executed:

#!/bin/bash
# Let's check the exact lines around the InputBoxType/inputBoxType difference

echo "=== Select InputBoxType (lines 325-335) ==="
sed -n '325,335p' packages/vue/src/select/src/index.ts

echo -e "\n=== SelectWrapper inputBoxType (lines 325-335) ==="
sed -n '325,335p' packages/vue/src/select-wrapper/src/index.ts

echo -e "\n=== Component names ==="
echo "Select name:"
grep "name: \$prefix" packages/vue/src/select/src/index.ts
echo "SelectWrapper name:"
grep "name: \$prefix" packages/vue/src/select-wrapper/src/index.ts

Repository: opentiny/tiny-vue

Length of output: 782


API Incompatibility: TinySelectWrapper does not fully implement TinySelect interface.

The import alias does not guarantee API compatibility. Verified differences:

  • Property name mismatch: InputBoxType (Select) vs inputBoxType (SelectWrapper) — case-sensitive, will cause prop binding failures
  • Default value mismatch: 'input' (Select) vs 'normal' (SelectWrapper) for the box type property

These breaking changes risk silent bugs where templates work but props are ignored. Either ensure TinySelectWrapper props match TinySelect exactly, or document that this is not a drop-in replacement.

await page.waitForTimeout(200)
await input.hover()
await select.locator('.tiny-select__caret.tiny-select__close').click()
await page.getByLabel('示例', { exact: true }).getByRole('img').first().click()
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the test file content around line 29
head -n 40 examples/sites/demos/pc/app/select-wrapper/events.spec.ts | tail -n +15

Repository: opentiny/tiny-vue

Length of output: 1126


🏁 Script executed:

#!/bin/bash
# Find the select-wrapper component files
find examples/sites/demos/pc/app/select-wrapper -type f \( -name "*.vue" -o -name "*.ts" -o -name "*.tsx" -o -name "*.jsx" \) | head -20

Repository: opentiny/tiny-vue

Length of output: 1584


🏁 Script executed:

#!/bin/bash
# Look at the events composition API component
cat -n examples/sites/demos/pc/app/select-wrapper/events-composition-api.vue | head -100

Repository: opentiny/tiny-vue

Length of output: 2725


🏁 Script executed:

#!/bin/bash
# Search for the TinySelectWrapper component implementation
find . -type f -name "*.vue" -o -name "*.ts" -o -name "*.tsx" | xargs grep -l "TinySelectWrapper\|SelectWrapper" | grep -v node_modules | grep -v demos | head -10

Repository: opentiny/tiny-vue

Length of output: 293


🏁 Script executed:

#!/bin/bash
# Look at the PC select-wrapper component structure
cat -n packages/vue/src/select-wrapper/src/pc.vue | head -150

Repository: opentiny/tiny-vue

Length of output: 4367


🏁 Script executed:

#!/bin/bash
# Find the BaseSelect component
find . -type f -path "*/vue-base-select*" -name "*.vue" | head -5

Repository: opentiny/tiny-vue

Length of output: 43


🏁 Script executed:

#!/bin/bash
# Search for base-select implementation
find . -type f -name "*base-select*" | grep -v node_modules | head -10

Repository: opentiny/tiny-vue

Length of output: 529


🏁 Script executed:

#!/bin/bash
# Find the actual base-select Vue component in packages
find packages -type f -name "*.vue" | xargs grep -l "clear\|caret" | grep -i select | head -10

Repository: opentiny/tiny-vue

Length of output: 527


🏁 Script executed:

#!/bin/bash
# Look at base-select PC component for the clear button structure
cat -n packages/vue/src/base-select/src/pc.vue | grep -A 10 -B 10 "clear\|caret" | head -80

Repository: opentiny/tiny-vue

Length of output: 3870


🏁 Script executed:

#!/bin/bash
# Look at the full base-select to understand icon structure better
cat -n packages/vue/src/base-select/src/pc.vue | sed -n '320,355p'

Repository: opentiny/tiny-vue

Length of output: 1825


🏁 Script executed:

#!/bin/bash
# Look at the full test file to see if there are any setup/context clues
wc -l examples/sites/demos/pc/app/select-wrapper/events.spec.ts

Repository: opentiny/tiny-vue

Length of output: 121


🏁 Script executed:

#!/bin/bash
# View the full test file
cat -n examples/sites/demos/pc/app/select-wrapper/events.spec.ts

Repository: opentiny/tiny-vue

Length of output: 3423


Refine the clear button locator to avoid ambiguity with .first().

The semantic locator refactor (getByLabel + getByRole) follows best practices, but multiple image elements match this chain (the copy and close icons). Using .first() is not recommended because when your page changes, Playwright may click on an element you did not intend; instead, create a locator that uniquely identifies the target element.

Consider using a more specific identifier such as a data-testid attribute on the icon-close component, or chaining with a filter to distinguish it from the copy icon.

🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/select-wrapper/events.spec.ts around line 29, the
test uses .first() on a semantic locator which can click the wrong image when
DOM changes; replace the ambiguous selector by targeting the clear/close icon
uniquely—add a stable identifier (e.g., data-testid or a distinct accessible
name) to the icon-close component in the app markup, then update the test to use
a locator that targets that identifier (or chain a more specific
filter/accessible-name on getByRole) instead of .first(), ensuring the test
reliably clicks the intended clear button.

test('默认搜索', async ({ page }) => {
page.on('pageerror', (exception) => expect(exception).toBeNull())
await page.goto('select#filter-method')
await page.goto('select-wrapper#filter-method')
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

🧩 Analysis chain

🏁 Script executed:

fd -t f "filter-method.spec.ts"

Repository: opentiny/tiny-vue

Length of output: 303


🏁 Script executed:

cat -n "examples/sites/demos/pc/app/select-wrapper/filter-method.spec.ts"

Repository: opentiny/tiny-vue

Length of output: 3581


🏁 Script executed:

# Check if select-wrapper route directory exists
fd -t d "select-wrapper" examples/sites/demos/pc/app/

# List the structure of select-wrapper
ls -la "examples/sites/demos/pc/app/select-wrapper/" 2>/dev/null | head -20

Repository: opentiny/tiny-vue

Length of output: 1495


🏁 Script executed:

# Check if filter-method.vue exists in select-wrapper
ls -la "examples/sites/demos/pc/app/select-wrapper/" | grep filter-method

# Also check the original select folder for comparison
ls -la "examples/sites/demos/pc/app/select/" | grep filter-method

Repository: opentiny/tiny-vue

Length of output: 514


🏁 Script executed:

# Check the demo file in select-wrapper to see the structure
cat -n "examples/sites/demos/pc/app/select-wrapper/filter-method.vue" | head -50

Repository: opentiny/tiny-vue

Length of output: 1500


🏁 Script executed:

# Get the full filter-method.vue to see if it has id="filter-method"
cat "examples/sites/demos/pc/app/select-wrapper/filter-method.vue"

Repository: opentiny/tiny-vue

Length of output: 1868


🏁 Script executed:

# Check the select (original) filter-method.vue to compare
cat "examples/sites/demos/pc/app/select/filter-method.vue"

Repository: opentiny/tiny-vue

Length of output: 1847


🏁 Script executed:

# Check if other demo files in select-wrapper have id attributes in their templates
grep -r "id=" "examples/sites/demos/pc/app/select-wrapper/" --include="*.vue" | head -10

# Also check in select folder
grep -r "id=" "examples/sites/demos/pc/app/select/" --include="*.vue" | head -10

Repository: opentiny/tiny-vue

Length of output: 43


🏁 Script executed:

# Search for where the demo routing/layout might add the id attribute
fd -t f "layout" "examples/sites/demos/pc/app/" -o | head -20

# Also look for index files that might render demos
find "examples/sites/demos/pc/app/" -name "index.vue" -o -name "index.ts" | head -10

# Check the playwright config to understand how routes work
find "examples/sites/demos/" -name "playwright.config.*" -o -name "*.config.ts"

Repository: opentiny/tiny-vue

Length of output: 177


🏁 Script executed:

# Look for playwright config
find "examples/sites/demos/" -name "playwright.config.*"

# Check how the demo site renders - look for main app file
ls -la "examples/sites/demos/pc/" | head -20

Repository: opentiny/tiny-vue

Length of output: 543


🏁 Script executed:

# Check the config and menus to understand routing
cat "examples/sites/demos/pc/config.js"

# Check menus
head -100 "examples/sites/demos/pc/menus.js"

Repository: opentiny/tiny-vue

Length of output: 2344


🏁 Script executed:

# Look for how demo pages are rendered/wrapped - check for router or app setup
find "examples/sites/demos/pc/" -name "*.vue" -o -name "*.ts" | grep -E "(app|main|index)" | head -10

# Check if there's a demo wrapper that adds IDs
grep -r "id=" "examples/sites/demos/pc/" --include="*.vue" --include="*.ts" | grep -E "(demo|wrapper)" | head -5

# Let's check one of the working tests to see if they have IDs
cat "examples/sites/demos/pc/app/select/filter-method.spec.ts" | head -20

Repository: opentiny/tiny-vue

Length of output: 2015


🏁 Script executed:

# Look at how the demo site is structured - check for layout or wrapper components
find "examples/sites/demos/pc/" -type f -name "*.vue" | xargs grep -l "slot\|component" | head -5

# Check if there's a main or layout file in the app directory
ls -la "examples/sites/demos/pc/app/" | grep -E "(App|Layout|Main|index)"

# Look for the build/render setup for demos
find "examples/sites/demos/" -name "vite.config.*" -o -name "*.config.ts" | head -5

Repository: opentiny/tiny-vue

Length of output: 377


🏁 Script executed:

# Search for where demo pages get their IDs - look for dynamic route setup
grep -r "filter-method" "examples/sites/demos/" --include="*.ts" --include="*.js" --include="*.vue" | grep -v ".spec.ts" | head -10

# Check if there's a docs/framework site file
find "examples/sites/" -maxdepth 3 -name "*.vue" -o -name "*.ts" | grep -E "(site|main|app)" | head -10

Repository: opentiny/tiny-vue

Length of output: 1192


🏁 Script executed:

# Check the select-wrapper API definition
grep -A 20 "select-wrapper" "examples/sites/demos/apis/base-select.js" | head -30

# Also check if select-wrapper has its own API file
find "examples/sites/demos/apis/" -name "*select*" -type f

# Look at how demos are indexed
head -50 "examples/sites/demos/apis/base-select.js"

Repository: opentiny/tiny-vue

Length of output: 2246


🏁 Script executed:

# Check the select-wrapper API file
head -100 "examples/sites/demos/apis/select-wrapper.js"

Repository: opentiny/tiny-vue

Length of output: 3774


Add missing id="filter-method" wrapper to demo template.

The test file references an element with id="filter-method" (lines 6, 50) via page.locator('#filter-method'), but the demo file examples/sites/demos/pc/app/select-wrapper/filter-method.vue does not contain this ID attribute. Wrap the template content in a <div id="filter-method"> to match what the tests expect.

🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/select-wrapper/filter-method.spec.ts around line
5 the test navigates to 'select-wrapper#filter-method', but the demo component
file examples/sites/demos/pc/app/select-wrapper/filter-method.vue lacks the
expected wrapper id; edit that .vue file and wrap the root template content in a
<div id="filter-method"> ... </div> (ensuring you close the div and keep
existing template structure/indentation intact) so the
page.locator('#filter-method') in the tests can find the element.

const wrap = page.locator('#popup-style-position')
const select = wrap.locator('.tiny-select')
const dropdown = select.locator('.tiny-select__tags-group > .tiny-select-dropdown')
const dropdown = page.locator('.tiny-select-dropdown')
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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Check file structure related to select-wrapper
fd "select-wrapper" --type f | head -20

# Look for the test file and related files
ls -la examples/sites/demos/pc/app/select-wrapper/ 2>/dev/null || echo "Directory not found, searching..."

# Search for select-wrapper files in the repo
find . -path "*select-wrapper*" -type f | grep -E "\.(vue|ts|js)$" | head -20

Repository: opentiny/tiny-vue

Length of output: 12472


🏁 Script executed:

#!/bin/bash

# Read the test file mentioned in the review
cat -n examples/sites/demos/pc/app/select-wrapper/popup-style-position.spec.ts

# Read the demo component file
cat -n examples/sites/demos/pc/app/select-wrapper/popup-style-position.vue

# Search for Select/SelectWrapper component definition to understand dropdown rendering
fd -e vue -e ts "Select" packages/components --type f | grep -i "select" | head -10

Repository: opentiny/tiny-vue

Length of output: 2027


🏁 Script executed:

#!/bin/bash

# Check if there are multiple select-wrapper instances in the demo or other selects on the page
cat -n examples/sites/demos/pc/app/select-wrapper/popup-style-position.vue | grep -i "tiny-select\|wrap"

# Check what's wrapped by the #popup-style-position id
rg -B 5 -A 5 "popup-style-position" examples/sites/demos/pc/app/select-wrapper/popup-style-position.vue

# Look at page structure to confirm wrap element contains the select
grep -r "id.*popup-style-position\|class.*popup-style-position" examples/sites/demos/pc/app/select-wrapper/

Repository: opentiny/tiny-vue

Length of output: 295


🏁 Script executed:

#!/bin/bash

# Search for demo page wrapper or layout that adds ids
rg -B 2 -A 2 "popup-style-position" examples/sites/demos/ --type vue --type ts --type js | head -50

# Check if there's a wrapper component or layout
find examples/sites/demos/pc/app/select-wrapper -name "*.vue" -o -name "*.ts" | xargs grep -l "popup-style-position" 2>/dev/null

# Look for how demo ids are generated
rg "id=" examples/sites/demos/pc/app/select-wrapper/ | head -10

Repository: opentiny/tiny-vue

Length of output: 177


🏁 Script executed:

#!/bin/bash

# Check how other select-wrapper tests handle dropdown locators to understand patterns
rg "page.locator.*tiny-select-dropdown\|wrap.locator.*tiny-select-dropdown" examples/sites/demos/pc/app/select-wrapper/ --type ts

# Check a few other spec files to see the pattern
head -20 examples/sites/demos/pc/app/select-wrapper/basic-usage.spec.ts

Repository: opentiny/tiny-vue

Length of output: 987


Scope dropdown locator to the component wrapper for proper test isolation.

The current global selector page.locator('.tiny-select-dropdown') is inappropriate for this test because the component explicitly disables popper-append-to-body (set to false on line 2 of the demo), meaning the dropdown renders within the component's DOM. This should be scoped to the wrapper element:

-  const dropdown = page.locator('.tiny-select-dropdown')
+  const dropdown = wrap.locator('.tiny-select-dropdown')

This ensures the locator targets only the dropdown associated with the test's specific select component, improving reliability and preventing matches against unrelated dropdowns if the test structure changes.

📝 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
const dropdown = page.locator('.tiny-select-dropdown')
const dropdown = wrap.locator('.tiny-select-dropdown')
🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/select-wrapper/popup-style-position.spec.ts
around line 9, the test uses page.locator('.tiny-select-dropdown') which is
global; because popper-append-to-body is false the dropdown is rendered inside
the component wrapper, so scope the locator to that wrapper instead. Replace the
global locator with one that targets the specific component wrapper (e.g. obtain
the wrapper locator first and call its locator('.tiny-select-dropdown'), or use
a combined selector like '<wrapper-selector> .tiny-select-dropdown') so the
dropdown is isolated to the component under test.

state.selectEmitter.emit(constants.COMPONENT_NAME.OptionGroup, constants.EVENT_NAME.queryChange)
// 如果同时存在 remoteMethod 且没有使用 panel 插槽,也调用 remoteMethod(兼容其他场景)
if (props.remote && typeof props.remoteMethod === 'function' && !vm.$slots?.panel) {
state.hoverIndex = -1
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

Remove duplicate hoverIndex reset.

The statement state.hoverIndex = -1 appears in both the new conditional block (line 76) and the fallback condition (line 80), which is redundant.

🔎 Refactor to reduce duplication:

Consider extracting the hoverIndex reset outside the conditional blocks if it should always happen when remote is true:

 if (typeof props.filterMethod === 'function') {
   props.filterMethod(value)
   state.selectEmitter.emit(constants.COMPONENT_NAME.OptionGroup, constants.EVENT_NAME.queryChange)
   // 如果同时存在 remoteMethod 且没有使用 panel 插槽,也调用 remoteMethod(兼容其他场景)
   if (props.remote && typeof props.remoteMethod === 'function' && !vm.$slots?.panel) {
-    state.hoverIndex = -1
     props.remoteMethod(value, props.extraQueryParams)
   }
 } else if (props.remote && (typeof props.remoteMethod === 'function' || typeof props.initQuery === 'function')) {
-  state.hoverIndex = -1
   props.remoteMethod && props.remoteMethod(value, props.extraQueryParams)
 } else {
   api.queryChange(value, isInput)
 }
+if (props.remote && (typeof props.remoteMethod === 'function' || typeof props.filterMethod === 'function')) {
+  state.hoverIndex = -1
+}

Also applies to: 80-80

🤖 Prompt for AI Agents
In packages/renderless/src/base-select/index.ts around lines 76 to 80, there is
a duplicated reset of state.hoverIndex = -1 inside both the new conditional
branch and its fallback; remove the redundant assignment and ensure the
hoverIndex reset runs exactly once (either move a single state.hoverIndex = -1
out of the conditional blocks to execute for the shared case, or keep it only in
the branch where it’s actually required), updating control flow so behavior
remains identical but the duplicate line is eliminated.

Comment on lines +55 to 60
:lazy="lazy !== undefined ? lazy : treeOp.lazy"
:load="load || treeOp.load"
:after-load="afterLoad || treeOp.afterLoad"
@check="check"
@node-click="nodeClick"
v-bind="treeOp"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential prop override via v-bind="treeOp".

The explicit :lazy, :load, and :after-load bindings on lines 55-57 may be overridden by v-bind="treeOp" on line 60 if treeOp contains lazy, load, or afterLoad keys. In Vue, when both explicit bindings and v-bind are used, the order determines precedence—later attributes win.

Since v-bind="treeOp" comes after, the explicit bindings will be overridden. Consider moving v-bind="treeOp" before the explicit bindings, or destructuring treeOp to exclude these keys.

🔎 Suggested fix: Move v-bind before explicit bindings
       <tiny-tree
         ref="treeRef"
+        v-bind="treeOp"
         :check-strictly="treeOp.checkStrictly"
         :current-node-key="!multiple ? state.currentKey : ''"
         :data="state.treeData"
         :default-checked-keys="multiple ? state.defaultCheckedKeys : treeOp.defaultCheckedKeys || []"
         :default-expand-all="
           treeOp.defaultExpandAll !== undefined
             ? treeOp.defaultExpandAll
             : (lazy !== undefined ? lazy : treeOp.lazy)
               ? false
               : true
         "
         :expand-on-click-node="false"
         :filter-node-method="filterMethod"
         :icon-trigger-click-node="false"
         :node-key="valueField"
         :props="{ label: textField }"
         :show-checkbox="multiple"
         :lazy="lazy !== undefined ? lazy : treeOp.lazy"
         :load="load || treeOp.load"
         :after-load="afterLoad || treeOp.afterLoad"
         @check="check"
         @node-click="nodeClick"
-        v-bind="treeOp"
       ></tiny-tree>

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/vue/src/tree-select/src/mobile-first.vue around lines 55 to 60,
v-bind="treeOp" is placed after explicit bindings for :lazy, :load and
:after-load so any corresponding keys in treeOp will override the explicit
props; to fix either move v-bind="treeOp" before those explicit bindings so the
explicit props take precedence, or filter/destructure treeOp to remove lazy,
load and afterLoad keys before binding (ensure attribute order or removal
prevents overrides).

Comment on lines +34 to 39
:lazy="lazy !== undefined ? lazy : treeOp.lazy"
:load="load || treeOp.load"
:after-load="afterLoad || treeOp.afterLoad"
@check="check"
@node-click="nodeClick"
v-bind="treeOp"
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Same v-bind ordering issue as in mobile-first.vue.

The explicit :lazy, :load, and :after-load bindings on lines 34-36 may be overridden by v-bind="treeOp" on line 39. Consider moving v-bind="treeOp" before the explicit lazy-related bindings to ensure component-level props take precedence.

🔎 Suggested fix: Move v-bind before explicit bindings
       <tiny-tree
         ref="treeRef"
+        v-bind="treeOp"
         :check-strictly="treeOp.checkStrictly"
         :current-node-key="!multiple ? state.currentKey : ''"
         :data="state.treeData"
         :default-checked-keys="multiple ? state.defaultCheckedKeys : treeOp.defaultCheckedKeys || []"
         :default-expand-all="treeOp.defaultExpandAll !== undefined ? treeOp.defaultExpandAll : ((lazy !== undefined ? lazy : treeOp.lazy) ? false : true)"
         :expand-on-click-node="false"
         :filter-node-method="filterMethod"
         :icon-trigger-click-node="false"
         :node-key="valueField"
         :props="{ label: textField }"
         :show-checkbox="multiple"
         :lazy="lazy !== undefined ? lazy : treeOp.lazy"
         :load="load || treeOp.load"
         :after-load="afterLoad || treeOp.afterLoad"
         @check="check"
         @node-click="nodeClick"
-        v-bind="treeOp"
       ></tiny-tree>

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In packages/vue/src/tree-select/src/pc.vue around lines 34 to 39, the explicit
:lazy, :load and :after-load bindings are placed before v-bind="treeOp", so
treeOp can override them; move v-bind="treeOp" to appear before the explicit
lazy-related bindings (i.e., place v-bind="treeOp" on the element above
:lazy="..." :load="..." :after-load="...") so the explicit component-level props
take precedence; keep the event handlers (@check, @node-click) unchanged.

@zzcr zzcr merged commit 0863f54 into opentiny:dev Dec 19, 2025
10 of 13 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