Skip to content

Conversation

@zzcr
Copy link
Member

@zzcr zzcr commented Jul 26, 2025

同步内部代码

PR

PR Checklist

Please check if your PR fulfills the following requirements:

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

PR Type

What kind of change does this PR introduce?

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

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • Added new properties and slots to components, including trigger-simple for split, text-position and a default slot for time-line, and an onClose prop for dialog box.
    • Introduced interactive controls for QR code icon size, overall size, and color customization.
    • Added new demos and documentation for numeric input events and time-line default slots.
    • Enhanced dialog select, numeric input, and time-line components with new test coverage and examples.
  • Bug Fixes

    • Improved event typing and expanded supported modes for numeric component input events.
  • Tests

    • Added comprehensive Playwright and Vitest test cases for dialog select, numeric input, and time-line components.
  • Chores

    • Updated build and testing scripts, including new scripts for viewing test reports.
    • Enhanced PostCSS configuration with nesting support and added relevant dependencies.
  • Style

    • Improved button and timeline styles for better visual consistency.
  • Refactor

    • Simplified import statements for type definitions across multiple components.

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

coderabbitai bot commented Jul 26, 2025

Walkthrough

This update introduces new demos and Playwright tests for Timeline, Numeric, DialogSelect, Pager, and QR Code components. It adds new props and slots to Timeline, Split, and DialogBox components, and adjusts import strategies for Vue files. The QR Code and Pager demos are enhanced with interactive controls. Various configuration files are updated for PostCSS nesting and e2e reporting.

Changes

Files/Groups Change Summary
examples/docs/newsrc/resourceMobileFirst.js, resourcePc.js Updated import.meta.glob options for importing Vue files as raw strings.
examples/sites/demos/apis/numeric.js Refined input event type, expanded supported modes, and added English description.
examples/sites/demos/apis/split.js Added trigger-simple boolean prop to Split component API.
examples/sites/demos/apis/time-line.js Added text-position prop and default slot to Timeline component API.
examples/sites/demos/pc/app/dialog-select/*.spec.ts Added Playwright tests for dialog-select grid/tree single/multi selection and selection state.
examples/sites/demos/pc/app/numeric/input-event*.vue, input-event.spec.ts, webdoc/numeric.js Added Numeric input event demos (Composition API and Options API) and corresponding Playwright test and doc entry.
examples/sites/demos/pc/app/pager/align*.vue, align.spec.ts Refactored Pager demo to use dynamic alignment via radio group and updated test for dynamic alignment switching.
examples/sites/demos/pc/app/qr-code/icon*.vue, icon.spec.ts Enhanced QR Code demo with interactive icon/size controls and updated test to validate dynamic sizing.
examples/sites/demos/pc/app/qr-code/style*.vue, style.spec.ts Replaced color change button with color picker in QR Code demo and updated test for canvas color verification.
examples/sites/demos/pc/app/time-line/slot-default*.vue, slot-default.spec.ts, webdoc/time-line.js Added Timeline default slot demos (Composition/Options API), Playwright test, and documentation.
examples/sites/postcss.config.cjs, vue3/postcss.config.cjs Added Tailwind CSS nesting plugin via postcss-nesting.
examples/sites/src/components/version-tip.vue Changed PropType import source to @opentiny/vue-common.
examples/vue3/package.json, package.json Added "open:report" script and postcss-nesting dev dependency.
examples/vue3/vitest.setup.ts Added global mock for ResizeObserver for testing environment.
packages/theme/src/button/index.less Updated .is-circle selector and added aspect ratio, min-width, and padding styles.
packages/vue/src/button-group/src/index.ts, pager/src/index.ts, radio-group/src/index.ts, radio/src/index.ts, slider/src/index.ts Consolidated PropType import from @opentiny/vue-common.
packages/vue/src/dialog-box/src/index.ts Added onClose prop to DialogBox props.
packages/vue/src/dialog-box/tests/dialog-box.test.tsx Refactored DialogBox "visible" attribute test for async prop update and visibility assertion.
packages/vue/src/dialog-select/tests/dialog-select.test.tsx Added comprehensive DialogSelect tests for PC mode, slots, and selection logic.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant DemoPage
    participant Component
    participant PlaywrightTest

    User->>DemoPage: Interacts with demo (e.g., changes alignment, icon size, color)
    DemoPage->>Component: Updates props or triggers events
    Component-->>DemoPage: Renders updated UI
    PlaywrightTest->>DemoPage: Simulates user actions (fill input, click, select)
    DemoPage-->>PlaywrightTest: UI updates, event counts, selection states
    PlaywrightTest->>PlaywrightTest: Asserts expected DOM and state
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

Hopping through demos, the rabbit delights,
New slots and props make timelines bright.
Numeric events now count with glee,
QR codes and pagers switch dynamically.
Playwright tests run, reports in store—
With nested buttons, styles, and more!
🐇✨

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

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

examples/sites/demos/apis/numeric.js

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-vue".

(The package "eslint-plugin-vue" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-vue@latest --save-dev

The plugin "eslint-plugin-vue" was referenced from the config file in ".eslintrc.js » @antfu/eslint-config » @antfu/eslint-config-vue".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

examples/docs/newsrc/resourceMobileFirst.js

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-vue".

(The package "eslint-plugin-vue" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-vue@latest --save-dev

The plugin "eslint-plugin-vue" was referenced from the config file in ".eslintrc.js » @antfu/eslint-config » @antfu/eslint-config-vue".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

examples/docs/newsrc/resourcePc.js

Oops! Something went wrong! :(

ESLint: 8.57.1

ESLint couldn't find the plugin "eslint-plugin-vue".

(The package "eslint-plugin-vue" was not found when loaded as a Node module from the directory "".)

It's likely that the plugin isn't installed correctly. Try reinstalling by running the following:

npm install eslint-plugin-vue@latest --save-dev

The plugin "eslint-plugin-vue" was referenced from the config file in ".eslintrc.js » @antfu/eslint-config » @antfu/eslint-config-vue".

If you still can't figure out the problem, please stop by https://eslint.org/chat/help to chat with the team.

  • 35 others

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch zzc/sync-inner-to-out-0726

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

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

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

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

Other keywords and placeholders

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

CodeRabbit Configuration File (.coderabbit.yaml)

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

Documentation and Community

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🔭 Outside diff range comments (1)
examples/sites/demos/pc/app/qr-code/style.vue (1)

33-36: Remove unused changeColor method.

The changeColor method is no longer used since the color picker now handles color changes directly via v-model. Additionally, the code this.params.color = '#666' would not work correctly since params is now a computed property, not a data property.

- methods: {
-   changeColor() {
-     this.params.color = '#666'
-   }
- }
🧹 Nitpick comments (13)
packages/theme/src/button/index.less (1)

36-40: Avoid redundant double-class selector – use &&.is-circle for specificity instead
Writing the selector as &.is-circle.is-circle only inflates the rule’s weight while harming readability; the second .is-circle provides no semantic value. If the intent is to bump specificity, the conventional Less pattern is &&.is-circle, which duplicates the whole parent selector once and is self-documenting.

-  &.is-circle.is-circle {
+  &&.is-circle {
     border-radius: var(--tv-Button-border-radius-circle);
     aspect-ratio: 1;
     min-width: initial;
     padding: initial;
   }

This keeps the same specificity boost, avoids repetition, and makes future maintenance easier.

examples/sites/demos/pc/app/qr-code/icon.spec.ts (1)

12-19: Consider using more specific selectors for better test stability.

The current approach uses nth-based selectors for buttons and inputs, which could break if the UI structure changes. Consider using more semantic selectors like data-testid attributes or more descriptive role/label combinations.

- await page.getByLabel('示例', { exact: true }).getByRole('button').nth(1).click()
+ await page.getByRole('button', { name: 'decrease-icon-size' }).click()
- const inputIconSizeWidth = await page.getByRole('spinbutton').first().inputValue()
+ const inputIconSizeWidth = await page.getByLabel('Icon Size').inputValue()
package.json (1)

97-99: Check script path correctness and naming consistency

"open:report": "pnpm -C examples/vue3 open:report" hard-codes the Vue 3 example workspace.
If a future PR adds Vue 2 Playwright reports, the root script name will become ambiguous.
Consider a more explicit alias (open:report:vue3) or a generic wrapper that detects the active example directory.

examples/vue3/vitest.setup.ts (1)

1-8: LGTM! Clean ResizeObserver mock implementation.

The mock correctly provides the essential ResizeObserver interface for testing environments. This will prevent test failures when components use ResizeObserver.

Consider adding TypeScript typing for better type safety:

-global.ResizeObserver = class ResizeObserver {
-  constructor(callback) {
+global.ResizeObserver = class ResizeObserver {
+  constructor(callback: ResizeObserverCallback) {
     this.callback = callback
   }
examples/sites/demos/pc/app/dialog-select/set-selection.spec.ts (1)

1-20: Well-structured Playwright test with room for improvement.

The test correctly verifies dialog select multi-selection functionality with proper error handling and user interaction simulation.

Consider these improvements for better maintainability:

  1. Use English test name for international teams:
-test('dialogSelect 设置多选状态', async ({ page }) => {
+test('dialogSelect multi-selection state management', async ({ page }) => {
  1. More robust selection verification:
-  for (let i = 0; i < trs.length; i++) {
-    const classes = await trs[i].getAttribute('class')
-    if (i === 1) {
-      expect(classes?.includes('row__selected')).toBeTruthy()
-    } else {
-      expect(classes?.includes('row__selected')).toBeFalsy()
-    }
-  }
+  // Verify only the second row is selected
+  await expect(trs[1]).toHaveClass(/row__selected/)
+  
+  // Verify other rows are not selected
+  for (let i = 0; i < trs.length; i++) {
+    if (i !== 1) {
+      await expect(trs[i]).not.toHaveClass(/row__selected/)
+    }
+  }
examples/sites/demos/pc/app/numeric/input-event.spec.ts (1)

8-14: Consider using deterministic values and verify initial state.

Using Math.random() can make tests non-deterministic. Consider using predictable values for better test reliability. Also, verify the initial counter state before starting the loop.

+ // Verify initial counter state
+ let count = await page.locator('.count').textContent()
+ expect(Number(count)).toBe(0)
+
  for (let i = 0; i < 5; i++) {
-   await page.locator('.tiny-numeric__input-inner').fill(String(Math.random()))
+   await page.locator('.tiny-numeric__input-inner').fill(String(i + 1))

    count = await page.locator('.count').textContent()

    expect(Number(count)).toBe(i + 1)
  }
examples/sites/demos/pc/app/dialog-select/nest-tree-single.spec.ts (1)

15-25: Consider using consistent element selection methods.

The test logic is correct, but mixing getByText() and getByRole() for similar elements could make the test harder to maintain. Consider using consistent locator strategies.

  let current
- current = await page.getByText('201一级')
+ current = await page.getByRole('treeitem', { name: '201一级' }).locator('label')
  await current.click()
  expect(await current.locator('input[type="radio"]').isChecked()).toBe(true)

  current = await page.getByRole('treeitem', { name: '二级 6' }).locator('label')
  await current.click()
  expect(await current.locator('input[type="radio"]').isChecked()).toBe(true)
- current = await page.getByText('201一级')
+ current = await page.getByRole('treeitem', { name: '201一级' }).locator('label')
  expect(await current.locator('input[type="radio"]').isChecked()).toBe(false)
examples/sites/demos/pc/app/dialog-select/nest-grid-single.spec.ts (1)

19-39: Consider extracting repeated row verification logic.

The test logic is correct, but the row verification pattern is repeated. Consider extracting it into a helper function for better maintainability.

+ async function verifyRowSelection(page, expectedSelectedIndex) {
+   const rows = await page.locator('.tiny-grid-body__row').all()
+   for (let i = 0; i < rows.length; i++) {
+     const checked = await rows[i].locator('input[type="radio"]').first().isChecked()
+     expect(checked).toBe(i === expectedSelectedIndex)
+   }
+ }

  await page.getByRole('row', { name: 'GFD 科技有限公司 福建 福州' }).locator('path').nth(1).click()

- rows = await page.locator('.tiny-grid-body__row').all()
- for (let i = 0; i < rows.length; i++) {
-   const checked = await rows[i].locator('input[type="radio"]').first().isChecked()
-   if (i === 0) {
-     expect(checked).toBe(true)
-   } else {
-     expect(checked).toBe(false)
-   }
- }
+ await verifyRowSelection(page, 0)

  await page.getByRole('row', { name: 'WWW 科技有限公司 广东 深圳' }).locator('path').nth(1).click()

- rows = await page.locator('.tiny-grid-body__row').all()
- for (let i = 0; i < rows.length; i++) {
-   const checked = await rows[i].locator('input[type="radio"]').first().isChecked()
-   if (i === 1) {
-     expect(checked).toBe(true)
-   } else {
-     expect(checked).toBe(false)
-   }
- }
+ await verifyRowSelection(page, 1)
examples/sites/demos/pc/app/numeric/input-event.vue (1)

24-31: Add defensive programming for event target access.

The implementation is solid, but consider adding a null check for the event target to improve robustness:

onInput(event: InputEvent) {
-  const currentValue = (event.target as HTMLInputElement).value
+  const target = event.target as HTMLInputElement
+  if (!target) return
+  const currentValue = target.value
  TinyModal.message({
    message: `新值: ${currentValue}`,
    status: 'info'
  })
  this.inputCount++
}
examples/sites/demos/pc/app/dialog-select/nest-tree-multi.spec.ts (2)

3-6: Consider using English test descriptions for better maintainability.

The test description uses Chinese characters which may limit accessibility for international contributors and automated tooling.

-test('dialogSelect 树多选', async ({ page }) => {
+test('dialogSelect nested tree multi-select', async ({ page }) => {

8-13: Simplify checkbox type verification.

The current approach uses string manipulation to verify checkbox type. Consider using more direct DOM queries for better reliability.

-  const nodeContent = await page.locator('.tiny-tree-node__content-left label').nth(1)
-
-  const iconNode = await nodeContent.getAttribute('class')
-
-  expect(iconNode?.includes('tiny-radio')).toBe(false)
-  expect(iconNode?.includes('tiny-checkbox')).toBe(true)
+  // Verify checkboxes are present (not radio buttons)
+  await expect(page.locator('.tiny-tree-node__content-left .tiny-checkbox')).toBeVisible()
+  await expect(page.locator('.tiny-tree-node__content-left .tiny-radio')).not.toBeVisible()
examples/sites/demos/pc/app/time-line/slot-default-composition-api.vue (1)

32-39: Improve CSS custom property organization.

The CSS custom properties are well-used but could be better organized and documented.

 .demo-timeline-default-slot {
+  /* Timeline colors */
   --color: #d3d5d6;
+  --active-color: #5073e5;
+  /* Timeline dimensions */
+  --size: 20px;
+  
   .done {
-    --color: #5073e5;
+    --color: var(--active-color);
   }
-  --size: 20px;
 }
examples/sites/demos/pc/app/time-line/slot-default.vue (1)

47-53: Consider more specific CSS variable naming.

The generic variable names like --color and --size could be more descriptive to improve maintainability and avoid potential conflicts.

Consider renaming to more specific names:

 .demo-timeline {
-  --color: #d3d5d6;
+  --timeline-color: #d3d5d6;
   .done {
-    --color: #5073e5;
+    --timeline-color: #5073e5;
   }
-  --size: 20px;
+  --timeline-icon-size: 20px;
 }

And update the corresponding references throughout the styles.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 6b27c30 and f644153.

📒 Files selected for processing (41)
  • examples/docs/newsrc/resourceMobileFirst.js (1 hunks)
  • examples/docs/newsrc/resourcePc.js (1 hunks)
  • examples/sites/demos/apis/numeric.js (1 hunks)
  • examples/sites/demos/apis/split.js (1 hunks)
  • examples/sites/demos/apis/time-line.js (2 hunks)
  • examples/sites/demos/pc/app/dialog-select/nest-grid-single.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/dialog-select/nest-tree-multi.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/dialog-select/nest-tree-single.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/dialog-select/set-selection.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/numeric/input-event-composition-api.vue (1 hunks)
  • examples/sites/demos/pc/app/numeric/input-event.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/numeric/input-event.vue (1 hunks)
  • examples/sites/demos/pc/app/numeric/webdoc/numeric.js (1 hunks)
  • examples/sites/demos/pc/app/pager/align-composition-api.vue (1 hunks)
  • examples/sites/demos/pc/app/pager/align.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/pager/align.vue (1 hunks)
  • examples/sites/demos/pc/app/qr-code/icon-composition-api.vue (1 hunks)
  • examples/sites/demos/pc/app/qr-code/icon.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/qr-code/icon.vue (1 hunks)
  • examples/sites/demos/pc/app/qr-code/style-composition-api.vue (1 hunks)
  • examples/sites/demos/pc/app/qr-code/style.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/qr-code/style.vue (1 hunks)
  • examples/sites/demos/pc/app/time-line/slot-default-composition-api.vue (1 hunks)
  • examples/sites/demos/pc/app/time-line/slot-default.spec.ts (1 hunks)
  • examples/sites/demos/pc/app/time-line/slot-default.vue (1 hunks)
  • examples/sites/demos/pc/app/time-line/webdoc/time-line.js (1 hunks)
  • examples/sites/postcss.config.cjs (1 hunks)
  • examples/sites/src/components/version-tip.vue (1 hunks)
  • examples/vue3/package.json (1 hunks)
  • examples/vue3/postcss.config.cjs (1 hunks)
  • examples/vue3/vitest.setup.ts (1 hunks)
  • package.json (2 hunks)
  • packages/theme/src/button/index.less (1 hunks)
  • packages/vue/src/button-group/src/index.ts (1 hunks)
  • packages/vue/src/dialog-box/__tests__/dialog-box.test.tsx (1 hunks)
  • packages/vue/src/dialog-box/src/index.ts (2 hunks)
  • packages/vue/src/dialog-select/__tests__/dialog-select.test.tsx (1 hunks)
  • packages/vue/src/pager/src/index.ts (1 hunks)
  • packages/vue/src/radio-group/src/index.ts (1 hunks)
  • packages/vue/src/radio/src/index.ts (1 hunks)
  • packages/vue/src/slider/src/index.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (15)
packages/vue/src/slider/src/index.ts (3)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

Learnt from: Davont
PR: #2513
File: packages/vue/src/huicharts/huicharts-sunburst/src/chart-sunburst.vue:30-32
Timestamp: 2024-11-25T03:24:05.740Z
Learning: 在位于packages/vue/src/huicharts/huicharts-sunburst/src/chart-sunburst.vue的组件中,当使用chart-core时,应删除错误的option定义,使用chart-core中的huiChartOption

Learnt from: Davont
PR: #2513
File: packages/vue/src/huicharts/huicharts-heatmap/src/chart-heatmap.vue:38-40
Timestamp: 2024-11-25T03:43:19.322Z
Learning: 在 Vue.js 组件(如 chart-heatmap.vue)中,使用来自 chart-corehuiChartOption 来管理图表选项,不要在 data() 中声明 option

packages/vue/src/radio/src/index.ts (1)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

packages/vue/src/pager/src/index.ts (1)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

packages/theme/src/button/index.less (1)

Learnt from: zzcr
PR: #2481
File: packages/theme/src/time-range/vars.less:27-28
Timestamp: 2024-11-04T09:35:13.159Z
Learning: 在 packages/theme/src/time-range/vars.less 文件中,应使用 var(--tv-TimeRange-header-height) 作为 --tv-TimeRange-header-line-height 的值,以保持一致性。

examples/sites/demos/pc/app/qr-code/icon-composition-api.vue (3)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

Learnt from: Davont
PR: #2513
File: packages/vue/src/huicharts/huicharts-sunburst/src/chart-sunburst.vue:30-32
Timestamp: 2024-11-25T03:24:05.740Z
Learning: 在位于packages/vue/src/huicharts/huicharts-sunburst/src/chart-sunburst.vue的组件中,当使用chart-core时,应删除错误的option定义,使用chart-core中的huiChartOption

Learnt from: Davont
PR: #2513
File: packages/vue/src/huicharts/huicharts-heatmap/src/chart-heatmap.vue:38-40
Timestamp: 2024-11-25T03:43:19.322Z
Learning: 在 Vue.js 组件(如 chart-heatmap.vue)中,使用来自 chart-corehuiChartOption 来管理图表选项,不要在 data() 中声明 option

examples/sites/src/components/version-tip.vue (1)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

examples/sites/demos/pc/app/numeric/input-event-composition-api.vue (1)

Learnt from: zzcr
PR: #2584
File: packages/renderless/src/numeric/index.ts:124-127
Timestamp: 2024-12-02T08:56:05.176Z
Learning: 在packages/renderless/src/numeric/index.ts文件中,在访问props.step.value之前,应先判断props.step是否为对象,以确保容错处理。

examples/sites/demos/pc/app/qr-code/style.vue (3)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

Learnt from: Davont
PR: #2513
File: packages/vue/src/huicharts/huicharts-sunburst/src/chart-sunburst.vue:30-32
Timestamp: 2024-11-25T03:24:05.740Z
Learning: 在位于packages/vue/src/huicharts/huicharts-sunburst/src/chart-sunburst.vue的组件中,当使用chart-core时,应删除错误的option定义,使用chart-core中的huiChartOption

Learnt from: Davont
PR: #2513
File: packages/vue/src/huicharts/huicharts-heatmap/src/chart-heatmap.vue:38-40
Timestamp: 2024-11-25T03:43:19.322Z
Learning: 在 Vue.js 组件(如 chart-heatmap.vue)中,使用来自 chart-corehuiChartOption 来管理图表选项,不要在 data() 中声明 option

examples/sites/demos/pc/app/numeric/input-event.spec.ts (1)

Learnt from: zzcr
PR: #2584
File: packages/renderless/src/numeric/index.ts:124-127
Timestamp: 2024-12-02T08:56:05.176Z
Learning: 在packages/renderless/src/numeric/index.ts文件中,在访问props.step.value之前,应先判断props.step是否为对象,以确保容错处理。

packages/vue/src/radio-group/src/index.ts (1)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

examples/sites/demos/pc/app/qr-code/style-composition-api.vue (2)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

Learnt from: Davont
PR: #2513
File: packages/vue/src/huicharts/huicharts-sunburst/src/chart-sunburst.vue:30-32
Timestamp: 2024-11-25T03:24:05.740Z
Learning: 在位于packages/vue/src/huicharts/huicharts-sunburst/src/chart-sunburst.vue的组件中,当使用chart-core时,应删除错误的option定义,使用chart-core中的huiChartOption

packages/vue/src/dialog-box/src/index.ts (1)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

examples/sites/demos/pc/app/qr-code/icon.vue (2)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

Learnt from: Davont
PR: #2513
File: packages/vue/src/huicharts/huicharts-heatmap/src/chart-heatmap.vue:38-40
Timestamp: 2024-11-25T03:43:19.322Z
Learning: 在 Vue.js 组件(如 chart-heatmap.vue)中,使用来自 chart-corehuiChartOption 来管理图表选项,不要在 data() 中声明 option

examples/sites/demos/pc/app/time-line/slot-default.vue (1)

Learnt from: Davont
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 中定义 huiChartOptionoption,而是应该依赖 chart-core 提供的 huiChartOption

examples/sites/demos/pc/app/numeric/input-event.vue (1)

Learnt from: zzcr
PR: #2584
File: packages/renderless/src/numeric/index.ts:124-127
Timestamp: 2024-12-02T08:56:05.176Z
Learning: 在packages/renderless/src/numeric/index.ts文件中,在访问props.step.value之前,应先判断props.step是否为对象,以确保容错处理。

🧬 Code Graph Analysis (2)
examples/docs/newsrc/resourcePc.js (1)
examples/docs/newsrc/resourceMobileFirst.js (2)
  • demoStr (3-7)
  • demoStr (3-7)
examples/docs/newsrc/resourceMobileFirst.js (1)
examples/docs/newsrc/resourcePc.js (2)
  • demoStr (8-12)
  • demoStr (8-12)
⏰ 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 (54)
examples/sites/demos/pc/app/pager/align.spec.ts (1)

10-17: LGTM! Test correctly validates interactive alignment behavior.

The test properly verifies the dynamic alignment functionality by simulating user clicks on alignment buttons and asserting the corresponding CSS changes. The test flow logically covers the default state and all three alignment options.

examples/sites/demos/pc/app/pager/align-composition-api.vue (2)

9-16: LGTM! Composition API implementation is well-structured.

The reactive state setup and component imports are correct. The options mapping properly transforms the alignment strings into the expected object format for the radio group.


3-4: LGTM! Template binding is properly implemented.

The v-model binding on TinyRadioGroup and :align prop binding on TinyPager correctly establish the reactive relationship between the radio selection and pager alignment.

examples/sites/demos/pc/app/pager/align.vue (3)

9-15: LGTM! Component imports and registration are correct.

The TinyPager and TinyRadioGroup components are properly imported and registered, enabling the interactive alignment functionality.


16-21: LGTM! Data structure matches composition API implementation.

The data function returns the correct structure with align defaulting to 'left' and options properly mapped to label/text objects, maintaining consistency with the composition API version.


3-4: LGTM! Template implementation is consistent.

The v-model and prop bindings correctly establish the reactive relationship between the radio group selection and pager alignment, matching the composition API implementation pattern.

examples/sites/demos/pc/app/qr-code/icon.spec.ts (1)

20-29: LGTM! Good validation of QR code size changes.

The test logic correctly validates that the QR code dimensions match the input values after user interaction. The approach of using evaluate() to access computed styles and comparing with input values is appropriate.

examples/sites/demos/pc/app/qr-code/style.spec.ts (2)

10-20: Verify pixel sampling coordinates are reliable.

The test samples the canvas pixel at coordinates (1,1) to check the QR code color. Ensure this coordinate consistently falls within the colored portion of the QR code regardless of QR code content or size variations.

Consider testing multiple coordinates or using a more central position:

- { x: 1, y: 1 }
+ { x: 10, y: 10 } // Or use dynamic coordinates based on canvas size

29-39: LGTM! Comprehensive color validation logic.

The test effectively validates that the color picker interaction updates the QR code canvas color. The approach of comparing the color picker's background color with the actual canvas pixel color provides good confidence in the feature functionality.

examples/sites/demos/pc/app/qr-code/style-composition-api.vue (2)

3-3: LGTM! Improved user experience with direct color picker integration.

The replacement of the manual button with a TinyColorPicker bound via v-model to params.color provides a much better user experience for color selection. The two-way binding will automatically update the QR code color as users interact with the picker.


9-9: LGTM! Import statement correctly updated.

The import statement properly reflects the component changes by replacing TinyButton with TinyColorPicker.

examples/sites/demos/pc/app/qr-code/icon-composition-api.vue (4)

4-4: LGTM! Smart constraint logic for icon size.

The iconSize constraint using :max="params.size * 0.3" is excellent design - it ensures the icon never exceeds 30% of the QR code size, maintaining visual proportions. The reactive binding makes this constraint update automatically when the size changes.


11-12: LGTM! Proper Vue 3 Composition API imports.

The addition of reactive import and TinyNumeric component import correctly supports the new interactive functionality.


14-21: LGTM! Appropriate use of reactive() for interactive controls.

Converting params from ref() to reactive() is the right choice here since you need deep reactivity for the object properties that are bound to the numeric inputs. This enables proper two-way binding with the form controls.


24-30: LGTM! Clean CSS layout for controls.

The flexbox styling with align-items: center and gap: 20px provides a clean, modern horizontal layout for the numeric input controls.

examples/sites/demos/pc/app/qr-code/style.vue (2)

3-3: LGTM! Improved color picker integration.

The addition of TinyColorPicker with v-model="color" provides much better user experience compared to the previous button-based approach.


22-30: LGTM! Proper reactive pattern with computed property.

Converting params to a computed property that references this.color is the correct approach to make the QR code parameters reactive to color changes. This ensures the QR code updates automatically when the color picker value changes.

examples/sites/demos/pc/app/qr-code/icon.vue (6)

2-6: LGTM! Well-implemented interactive controls.

The dynamic constraint ensuring iconSize stays within 30% of the QR code size is a thoughtful design choice that maintains QR code readability. The use of reactive max values in the template should work correctly with Vue's reactivity system.


12-12: LGTM! Clean import addition.

The addition of TinyNumeric to the existing import follows the established pattern and is properly structured.


16-16: LGTM! Proper component registration.

The TinyNumeric component is correctly registered following Vue.js conventions.


21-23: LGTM! Well-chosen default values.

The default values (size: 250, iconSize: 60) are sensible, with the icon size representing 24% of the QR code size, which stays comfortably within the 30% constraint.


25-36: LGTM! Excellent use of computed property for reactive parameters.

The params computed property correctly leverages Vue's reactivity system to dynamically update QR code parameters when iconSize or size changes. The preservation of the existing icon URL logic with environment variable handling is well done.


40-46: LGTM! Clean and modern CSS styling.

The scoped CSS uses modern flexbox layout with appropriate spacing (gap: 20px) and alignment (align-items: center). The scoped nature prevents global style conflicts.

package.json (1)

146-146: Validate build-time vs dev-time dependency placement

postcss-nesting is added as a devDependency.
If the library is referenced by the production Vite/PostCSS pipeline (e.g., packages/theme build), it must live in "dependencies" for consumers that install the published package.
Double-check the compiled artifacts; move it if it’s bundled at runtime.

packages/vue/src/radio-group/src/index.ts (1)

12-12: Import consolidation looks good

Switching to type PropType from @opentiny/vue-common avoids the side-effect import from 'vue' and keeps it purely type-only. No functional impact detected.

packages/vue/src/slider/src/index.ts (1)

12-12: Consistent type-only import – OK

Same consolidation as other components; keeps treeshaking clean.

packages/vue/src/pager/src/index.ts (1)

1-1: Consolidated PropType source – OK

No behavioural change; compile-time only.

packages/vue/src/button-group/src/index.ts (1)

12-12: Uniform PropType import – OK

Matches the updated pattern across the codebase.

examples/vue3/package.json (1)

17-18: LGTM! Clean addition of Playwright report viewing capability.

The trailing comma and new open:report script are properly formatted and provide useful functionality for viewing Playwright test reports.

packages/vue/src/radio/src/index.ts (1)

12-12: LGTM! Import consolidation improves consistency.

The consolidation of PropType import into the existing @opentiny/vue-common import with proper type annotation follows the established pattern across the codebase.

examples/sites/src/components/version-tip.vue (1)

25-25: LGTM! Consistent import pattern applied.

The import consolidation of PropType to use @opentiny/vue-common maintains consistency with the broader refactoring pattern across the codebase.

packages/vue/src/dialog-box/src/index.ts (2)

12-12: LGTM! Import consolidation follows established pattern.

The consolidation of PropType import to @opentiny/vue-common with proper type annotation maintains consistency across the codebase.


134-136: LGTM! Well-typed onClose callback prop.

The new onClose prop provides a clean callback mechanism for dialog close events. The typing as () => void is appropriate and the optional nature (no default value) allows flexible usage.

examples/sites/postcss.config.cjs (1)

3-3: LGTM! PostCSS nesting support added.

The addition of 'tailwindcss/nesting': 'postcss-nesting' properly enables CSS nesting support through the Tailwind CSS nesting plugin, enhancing CSS authoring capabilities.

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

89-99: Well-structured API property addition.

The new trigger-simple property follows the established patterns in the API definition with proper bilingual documentation and appropriate typing.

examples/vue3/postcss.config.cjs (1)

3-3: Correct PostCSS nesting configuration.

The addition of the tailwindcss/nesting plugin mapping to postcss-nesting is properly configured and will enable CSS nesting support in the project.

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

463-470: Excellent API improvements for the input event.

The changes enhance the API definition with:

  • More precise TypeScript typing using InputEvent instead of generic Function
  • Added English documentation
  • Expanded platform support to include PC mode

These improvements will provide better developer experience with enhanced type safety and broader compatibility.

packages/vue/src/dialog-box/__tests__/dialog-box.test.tsx (1)

12-23: Excellent improvement to the test approach!

The rewritten test is much more comprehensive than a static existence check. Testing both the initial false state and the dynamic update to true provides better coverage of the component's reactive behavior.

examples/sites/demos/pc/app/time-line/webdoc/time-line.js (1)

189-201: LGTM! Well-structured demo addition.

The new "slot-default" demo entry follows the established pattern with proper localization and clear descriptions.

examples/sites/demos/pc/app/time-line/slot-default.spec.ts (1)

1-13: LGTM: Well-structured Playwright test for timeline default slot.

The test correctly verifies the empty default slot behavior by checking for zero timeline items while ensuring the basic structure (ordered list) exists. The error handling and page navigation are properly implemented.

examples/sites/demos/pc/app/numeric/webdoc/numeric.js (1)

168-179: LGTM: Consistent demo entry addition for input event.

The new demo entry follows the established pattern with proper localization, positioning, and HTML formatting. The placement between change-event and focus-event demos is logical and maintains good organization.

examples/docs/newsrc/resourcePc.js (1)

8-12: LGTM: Updated import.meta.glob configuration for better explicitness.

The change from as: 'raw' to explicit query: '?raw', import: 'default' improves clarity and aligns with the parallel change in resourceMobileFirst.js. This ensures consistent Vue file loading behavior across both PC and mobile-first demo resources.

examples/docs/newsrc/resourceMobileFirst.js (1)

3-7: LGTM: Consistent import configuration update.

This change mirrors the update in resourcePc.js, ensuring consistent Vue file loading behavior across PC and mobile-first demo resources. The explicit configuration improves maintainability.

examples/sites/demos/pc/app/numeric/input-event.vue (1)

1-34: LGTM: Well-implemented input event demo component.

The component effectively demonstrates the numeric input's input event functionality with clear visual feedback through both modal messages and counter display. The TypeScript integration and Vue component structure follow established patterns.

examples/sites/demos/apis/time-line.js (2)

202-212: LGTM! Well-structured prop addition.

The text-position prop is properly documented with clear descriptions in both languages, appropriate type definition, and correct mode restriction to PC only.


263-271: LGTM! Proper slot documentation.

The default slot is correctly documented following the established pattern, with bilingual descriptions and appropriate PC mode restriction.

examples/sites/demos/pc/app/numeric/input-event-composition-api.vue (2)

1-8: LGTM! Clean template structure.

The template is well-structured with clear binding and appropriate Chinese text for the demo context.


10-16: LGTM! Proper Composition API setup.

The imports and reactive references are correctly implemented following Vue 3 Composition API best practices.

examples/sites/demos/pc/app/time-line/slot-default-composition-api.vue (1)

1-19: LGTM! Well-structured slot usage.

The template properly demonstrates the default slot functionality with good conditional rendering and clean iteration pattern.

packages/vue/src/dialog-select/__tests__/dialog-select.test.tsx (3)

7-17: LGTM! Well-structured test data.

The hierarchical tree data structure is comprehensive and properly formatted for testing tree functionality with parent-child relationships.


22-38: LGTM! Proper visibility testing pattern.

The test correctly verifies the dialog visibility state changes with appropriate async handling and clear assertions.


80-97: LGTM! Comprehensive tree mode testing.

The test properly verifies both radio and checkbox modes for the tree component based on the multi prop, with appropriate async prop updates.

examples/sites/demos/pc/app/time-line/slot-default.vue (2)

1-19: LGTM! Well-structured template with proper slot usage.

The template correctly demonstrates the TinyTimeLine component's default slot functionality with semantic HTML structure using an ordered list.


21-43: Script implementation is appropriate for demo purposes.

The component structure and data handling are correct. The use of toLocaleString() for datetime formatting will adapt to the user's locale, which is suitable for a demo component.

Comment on lines +17 to +31
isChecked = await page
.getByRole('treeitem', { name: '三级 9' })
.locator('.tiny-checkbox input[type="checkbox"]')
.isChecked()
expect(isChecked).toBeFalsy()

let current
current = await page.getByRole('treeitem', { name: '三级 9' }).locator('path').nth(1)
await current.click()

isChecked = await page
.getByRole('treeitem', { name: '三级 9' })
.locator('.tiny-checkbox input[type="checkbox"]')
.isChecked()
expect(isChecked).toBeTruthy()
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Extract repeated checkbox state checking into a helper function.

The pattern of checking checkbox state is repeated multiple times. Consider creating a reusable helper function.

+  // Helper function to check checkbox state
+  const getCheckboxState = async (nodeName: string) => {
+    return await page
+      .getByRole('treeitem', { name: nodeName })
+      .locator('.tiny-checkbox input[type="checkbox"]')
+      .isChecked()
+  }
+
+  const clickNodeCheckbox = async (nodeName: string) => {
+    await page.getByRole('treeitem', { name: nodeName }).locator('path').nth(1).click()
+  }

-  let isChecked
-
-  isChecked = await page
-    .getByRole('treeitem', { name: '三级 9' })
-    .locator('.tiny-checkbox input[type="checkbox"]')
-    .isChecked()
-  expect(isChecked).toBeFalsy()
-
-  let current
-  current = await page.getByRole('treeitem', { name: '三级 9' }).locator('path').nth(1)
-  await current.click()
-
-  isChecked = await page
-    .getByRole('treeitem', { name: '三级 9' })
-    .locator('.tiny-checkbox input[type="checkbox"]')
-    .isChecked()
-  expect(isChecked).toBeTruthy()
+  // Test initial unchecked state
+  expect(await getCheckboxState('三级 9')).toBeFalsy()
+
+  // Click to check
+  await clickNodeCheckbox('三级 9')
+  expect(await getCheckboxState('三级 9')).toBeTruthy()
📝 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
isChecked = await page
.getByRole('treeitem', { name: '三级 9' })
.locator('.tiny-checkbox input[type="checkbox"]')
.isChecked()
expect(isChecked).toBeFalsy()
let current
current = await page.getByRole('treeitem', { name: '三级 9' }).locator('path').nth(1)
await current.click()
isChecked = await page
.getByRole('treeitem', { name: '三级 9' })
.locator('.tiny-checkbox input[type="checkbox"]')
.isChecked()
expect(isChecked).toBeTruthy()
// Helper function to check checkbox state
const getCheckboxState = async (nodeName: string) => {
return await page
.getByRole('treeitem', { name: nodeName })
.locator('.tiny-checkbox input[type="checkbox"]')
.isChecked()
}
const clickNodeCheckbox = async (nodeName: string) => {
await page
.getByRole('treeitem', { name: nodeName })
.locator('path')
.nth(1)
.click()
}
// Test initial unchecked state
expect(await getCheckboxState('三级 9')).toBeFalsy()
// Click to check
await clickNodeCheckbox('三级 9')
expect(await getCheckboxState('三级 9')).toBeTruthy()
🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/dialog-select/nest-tree-multi.spec.ts around
lines 17 to 31, the code repeatedly checks the checkbox state for the same tree
item. Refactor by extracting this repeated checkbox state checking logic into a
reusable helper function that takes the tree item name as input and returns the
checkbox state. Replace the repeated code with calls to this helper function to
improve readability and reduce duplication.

Comment on lines +33 to +44
await page
.locator('div')
.filter({ hasText: /^一级 1二级 4三级 8三级 9暂无数据$/ })
.getByRole('img')
.nth(3)
.click()

isChecked = await page
.getByRole('treeitem', { name: '三级 9' })
.locator('.tiny-checkbox input[type="checkbox"]')
.isChecked()
expect(isChecked).toBeFalsy()
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve locator specificity and add descriptive comments.

The current locator using filter({ hasText: /^一级 1二级 4三级 8三级 9暂无数据$/ }) is brittle and hard to understand.

+  // Click to uncheck the node (using a more specific locator)
-  await page
-    .locator('div')
-    .filter({ hasText: /^一级 1二级 4三级 8三级 9暂无数据$/ })
-    .getByRole('img')
-    .nth(3)
-    .click()
+  await clickNodeCheckbox('三级 9')

-  isChecked = await page
-    .getByRole('treeitem', { name: '三级 9' })
-    .locator('.tiny-checkbox input[type="checkbox"]')
-    .isChecked()
-  expect(isChecked).toBeFalsy()
+  expect(await getCheckboxState('三级 9')).toBeFalsy()

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

🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/dialog-select/nest-tree-multi.spec.ts around
lines 33 to 44, the locator using filter with a complex regex on text is brittle
and unclear. Replace this with a more specific locator targeting unique
attributes or roles that clearly identify the element, and add comments
explaining the purpose of the locator to improve readability and
maintainability.

Comment on lines +46 to +52
await page.getByRole('treeitem', { name: '三级 9' }).locator('path').nth(1).click()

isChecked = await page
.getByRole('treeitem', { name: '三级 9' })
.locator('.tiny-checkbox input[type="checkbox"]')
.isChecked()
expect(isChecked).toBeTruthy()
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Complete the refactoring with helper functions.

Apply the same helper function pattern to the final test steps for consistency.

-  await page.getByRole('treeitem', { name: '三级 9' }).locator('path').nth(1).click()
-
-  isChecked = await page
-    .getByRole('treeitem', { name: '三级 9' })
-    .locator('.tiny-checkbox input[type="checkbox"]')
-    .isChecked()
-  expect(isChecked).toBeTruthy()
+  // Click to check again
+  await clickNodeCheckbox('三级 9')
+  expect(await getCheckboxState('三级 9')).toBeTruthy()
📝 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
await page.getByRole('treeitem', { name: '三级 9' }).locator('path').nth(1).click()
isChecked = await page
.getByRole('treeitem', { name: '三级 9' })
.locator('.tiny-checkbox input[type="checkbox"]')
.isChecked()
expect(isChecked).toBeTruthy()
// Click to check again
await clickNodeCheckbox('三级 9')
expect(await getCheckboxState('三级 9')).toBeTruthy()
🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/dialog-select/nest-tree-multi.spec.ts around
lines 46 to 52, the final test steps directly interact with the page and check
the checkbox state without using helper functions. Refactor these steps by
creating and using appropriate helper functions for clicking the tree item and
checking the checkbox state, ensuring consistency with the rest of the test
code.

Comment on lines +18 to +25
const onInput = (event: InputEvent) => {
const currentValue = (event.target as HTMLInputElement).value
TinyModal.message({
message: `新值: ${currentValue}`,
status: 'info'
})
inputCount.value++
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve type safety and error handling in event handler.

The current implementation assumes the event target is an HTMLInputElement but doesn't handle potential null values or type mismatches.

-const onInput = (event: InputEvent) => {
-  const currentValue = (event.target as HTMLInputElement).value
+const onInput = (event: InputEvent) => {
+  const target = event.target as HTMLInputElement | null
+  if (!target) {
+    console.warn('Event target is null')
+    return
+  }
+  const currentValue = target.value
   TinyModal.message({
     message: `新值: ${currentValue}`,
     status: 'info'
   })
   inputCount.value++
 }
📝 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 onInput = (event: InputEvent) => {
const currentValue = (event.target as HTMLInputElement).value
TinyModal.message({
message: `新值: ${currentValue}`,
status: 'info'
})
inputCount.value++
}
const onInput = (event: InputEvent) => {
const target = event.target as HTMLInputElement | null
if (!target) {
console.warn('Event target is null')
return
}
const currentValue = target.value
TinyModal.message({
message: `新值: ${currentValue}`,
status: 'info'
})
inputCount.value++
}
🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/numeric/input-event-composition-api.vue around
lines 18 to 25, the onInput event handler assumes event.target is always an
HTMLInputElement without checking for null or type mismatches. To fix this, add
a type guard to verify event.target exists and is an instance of
HTMLInputElement before accessing its value. If the check fails, handle the
error gracefully, for example by returning early or logging a warning, to
improve type safety and prevent runtime errors.

Comment on lines +24 to +29
const items = [
{ desc: '提交申请', user: '张三', datetime: new Date(Date.now() - 60 * 60 * 1e3).toLocaleString(), status: 'done' },
{ desc: '直接主管', user: '李四', datetime: new Date().toLocaleString(), status: 'done' },
{ desc: '部门主管', user: '王五' },
{ desc: '完成' }
]
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve date handling and data structure.

The current date generation approach has potential issues and the data structure could be more maintainable.

+// Define a helper function for date formatting
+const formatDateTime = (offsetHours = 0) => {
+  const date = new Date(Date.now() + offsetHours * 60 * 60 * 1000)
+  return date.toLocaleString()
+}

 const items = [
-  { desc: '提交申请', user: '张三', datetime: new Date(Date.now() - 60 * 60 * 1e3).toLocaleString(), status: 'done' },
-  { desc: '直接主管', user: '李四', datetime: new Date().toLocaleString(), status: 'done' },
+  { desc: '提交申请', user: '张三', datetime: formatDateTime(-1), status: 'done' },
+  { desc: '直接主管', user: '李四', datetime: formatDateTime(0), status: 'done' },
   { desc: '部门主管', user: '王五' },
   { desc: '完成' }
 ]
📝 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 items = [
{ desc: '提交申请', user: '张三', datetime: new Date(Date.now() - 60 * 60 * 1e3).toLocaleString(), status: 'done' },
{ desc: '直接主管', user: '李四', datetime: new Date().toLocaleString(), status: 'done' },
{ desc: '部门主管', user: '王五' },
{ desc: '完成' }
]
// Define a helper function for date formatting
const formatDateTime = (offsetHours = 0) => {
const date = new Date(Date.now() + offsetHours * 60 * 60 * 1000)
return date.toLocaleString()
}
const items = [
{ desc: '提交申请', user: '张三', datetime: formatDateTime(-1), status: 'done' },
{ desc: '直接主管', user: '李四', datetime: formatDateTime(0), status: 'done' },
{ desc: '部门主管', user: '王五' },
{ desc: '完成' }
]
🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/time-line/slot-default-composition-api.vue around
lines 24 to 29, the current date handling uses inline Date and toLocaleString
calls which can lead to inconsistent formatting and maintenance issues. Refactor
the date generation by creating a reusable function or computed property to
format dates consistently. Also, improve the data structure by ensuring all
items have consistent keys and default values where appropriate to enhance
maintainability.

Comment on lines +51 to +59
div {
position: relative;
color: var(--active-color);
&:not(:first-of-type) {
margin: 5px 0;
display: flex;
justify-content: center;
}
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Fix CSS selector specificity issue.

The generic div selector may cause unintended styling conflicts. Use more specific selectors.

-div {
+.demo-timeline-default-slot li > div {
   position: relative;
   color: var(--active-color);
   &:not(:first-of-type) {
     margin: 5px 0;
     display: flex;
     justify-content: center;
   }
 }
📝 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
div {
position: relative;
color: var(--active-color);
&:not(:first-of-type) {
margin: 5px 0;
display: flex;
justify-content: center;
}
}
.demo-timeline-default-slot li > div {
position: relative;
color: var(--active-color);
&:not(:first-of-type) {
margin: 5px 0;
display: flex;
justify-content: center;
}
}
🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/time-line/slot-default-composition-api.vue around
lines 51 to 59, the CSS uses a generic div selector which can cause unintended
styling conflicts. Replace the generic div selector with a more specific class
or ID selector that targets only the intended elements to avoid affecting other
divs globally. Update the nested selectors accordingly to maintain the intended
styles.

Comment on lines +55 to +57
ol {
display: flex;
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Correct the flexbox direction for vertical timeline.

The display: flex on the ordered list creates a horizontal layout, which conflicts with the vertical timeline configuration.

Apply this change to ensure proper vertical layout:

 ol {
-  display: flex;
+  display: flex;
+  flex-direction: column;
 }
📝 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
ol {
display: flex;
}
ol {
display: flex;
flex-direction: column;
}
🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/time-line/slot-default.vue around lines 55 to 57,
the CSS for the ordered list uses display: flex which defaults to a horizontal
layout, conflicting with the vertical timeline design. Fix this by adding
flex-direction: column to the ol style to ensure the timeline items stack
vertically.


div {
position: relative;
color: var(--active-color);
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix undefined CSS variable reference.

The style references --active-color which is not defined anywhere in this component, potentially causing styling issues.

Replace the undefined variable with an appropriate color value:

-  color: var(--active-color);
+  color: #333; /* or another appropriate color */
📝 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
color: var(--active-color);
color: #333; /* or another appropriate color */
🤖 Prompt for AI Agents
In examples/sites/demos/pc/app/time-line/slot-default.vue at line 67, the CSS
variable --active-color is used but not defined, causing potential styling
issues. Replace the reference to --active-color with a valid color value or
define --active-color in the component's style section to ensure the color is
applied correctly.

Comment on lines +40 to +59
test('grid data', async () => {
const wrapper = mount(DialogSelect, {
props: {
visible: true,
gridOp: {
columns: [{ field: 'id', title: 'ID' }]
}
}
})
expect(wrapper.findComponent(Grid).vm.data).toBeUndefined()
const gridData = Array.from({ length: ~~(Math.random() * 10) }).map((_, i) => ({ id: i }))
await wrapper.setProps({
gridOp: {
columns: [{ field: 'id', title: 'ID' }],
data: gridData
}
})

expect(wrapper.findComponent(Grid).vm.data).toStrictEqual(gridData)
})
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve test data generation for reliability.

The random data generation could lead to flaky tests. Consider using deterministic test data.

-    expect(wrapper.findComponent(Grid).vm.data).toBeUndefined()
-    const gridData = Array.from({ length: ~~(Math.random() * 10) }).map((_, i) => ({ id: i }))
+    expect(wrapper.findComponent(Grid).vm.data).toBeUndefined()
+    const gridData = Array.from({ length: 5 }).map((_, i) => ({ id: i + 1 }))
📝 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
test('grid data', async () => {
const wrapper = mount(DialogSelect, {
props: {
visible: true,
gridOp: {
columns: [{ field: 'id', title: 'ID' }]
}
}
})
expect(wrapper.findComponent(Grid).vm.data).toBeUndefined()
const gridData = Array.from({ length: ~~(Math.random() * 10) }).map((_, i) => ({ id: i }))
await wrapper.setProps({
gridOp: {
columns: [{ field: 'id', title: 'ID' }],
data: gridData
}
})
expect(wrapper.findComponent(Grid).vm.data).toStrictEqual(gridData)
})
test('grid data', async () => {
const wrapper = mount(DialogSelect, {
props: {
visible: true,
gridOp: {
columns: [{ field: 'id', title: 'ID' }]
}
}
})
expect(wrapper.findComponent(Grid).vm.data).toBeUndefined()
- const gridData = Array.from({ length: ~~(Math.random() * 10) }).map((_, i) => ({ id: i }))
+ const gridData = Array.from({ length: 5 }).map((_, i) => ({ id: i + 1 }))
await wrapper.setProps({
gridOp: {
columns: [{ field: 'id', title: 'ID' }],
data: gridData
}
})
expect(wrapper.findComponent(Grid).vm.data).toStrictEqual(gridData)
})
🤖 Prompt for AI Agents
In packages/vue/src/dialog-select/__tests__/dialog-select.test.tsx between lines
40 and 59, the test uses random data generation which can cause flaky tests.
Replace the random data generation with a fixed, deterministic array of objects
for gridData to ensure consistent and reliable test results.

Comment on lines +99 to +122
test('slot', async () => {
const geneSlot = (name: string) => {
const el = <div>this is a {name}</div>
const wrapper = mount(() => el)
return { el, wrapper }
}

const { el: footer, wrapper: footerWrapper } = geneSlot('footer')
const { el: title, wrapper: titleWrapper } = geneSlot('title')
const { el: footerButtons, wrapper: footerButtonsWrapper } = geneSlot('footer-buttons')

const wrapper = mount(DialogSelect, {
props: {
visible: true
},
slots: { title, 'footer-buttons': footerButtons }
})

expect(wrapper.find('.tiny-dialog-box').text()).contains(titleWrapper.text())
expect(wrapper.find('.tiny-dialog-box').text()).contains(footerButtonsWrapper.text())

await wrapper.setProps({ slots: { footer, footerButtons } })
expect(wrapper.find('.tiny-dialog-box').text()).contains(footerWrapper.text())
})
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Improve slot testing approach and fix potential issues.

The current slot testing has some issues with prop updates and could be more maintainable.

   test('slot', async () => {
-    const geneSlot = (name: string) => {
+    const generateSlot = (name: string) => {
       const el = <div>this is a {name}</div>
-      const wrapper = mount(() => el)
-      return { el, wrapper }
+      return el
     }

-    const { el: footer, wrapper: footerWrapper } = geneSlot('footer')
-    const { el: title, wrapper: titleWrapper } = geneSlot('title')
-    const { el: footerButtons, wrapper: footerButtonsWrapper } = geneSlot('footer-buttons')
+    const footer = generateSlot('footer')
+    const title = generateSlot('title')
+    const footerButtons = generateSlot('footer-buttons')

     const wrapper = mount(DialogSelect, {
       props: {
         visible: true
       },
       slots: { title, 'footer-buttons': footerButtons }
     })

-    expect(wrapper.find('.tiny-dialog-box').text()).contains(titleWrapper.text())
-    expect(wrapper.find('.tiny-dialog-box').text()).contains(footerButtonsWrapper.text())
+    expect(wrapper.find('.tiny-dialog-box').text()).toContain('this is a title')
+    expect(wrapper.find('.tiny-dialog-box').text()).toContain('this is a footer-buttons')

-    await wrapper.setProps({ slots: { footer, footerButtons } })
-    expect(wrapper.find('.tiny-dialog-box').text()).contains(footerWrapper.text())
+    // Test footer slot separately
+    const wrapperWithFooter = mount(DialogSelect, {
+      props: { visible: true },
+      slots: { footer }
+    })
+    expect(wrapperWithFooter.find('.tiny-dialog-box').text()).toContain('this is a footer')
   })
📝 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
test('slot', async () => {
const geneSlot = (name: string) => {
const el = <div>this is a {name}</div>
const wrapper = mount(() => el)
return { el, wrapper }
}
const { el: footer, wrapper: footerWrapper } = geneSlot('footer')
const { el: title, wrapper: titleWrapper } = geneSlot('title')
const { el: footerButtons, wrapper: footerButtonsWrapper } = geneSlot('footer-buttons')
const wrapper = mount(DialogSelect, {
props: {
visible: true
},
slots: { title, 'footer-buttons': footerButtons }
})
expect(wrapper.find('.tiny-dialog-box').text()).contains(titleWrapper.text())
expect(wrapper.find('.tiny-dialog-box').text()).contains(footerButtonsWrapper.text())
await wrapper.setProps({ slots: { footer, footerButtons } })
expect(wrapper.find('.tiny-dialog-box').text()).contains(footerWrapper.text())
})
test('slot', async () => {
const generateSlot = (name: string) => {
const el = <div>this is a {name}</div>
return el
}
const footer = generateSlot('footer')
const title = generateSlot('title')
const footerButtons = generateSlot('footer-buttons')
const wrapper = mount(DialogSelect, {
props: {
visible: true
},
slots: { title, 'footer-buttons': footerButtons }
})
expect(wrapper.find('.tiny-dialog-box').text()).toContain('this is a title')
expect(wrapper.find('.tiny-dialog-box').text()).toContain('this is a footer-buttons')
// Test footer slot separately
const wrapperWithFooter = mount(DialogSelect, {
props: { visible: true },
slots: { footer }
})
expect(wrapperWithFooter.find('.tiny-dialog-box').text()).toContain('this is a footer')
})
🤖 Prompt for AI Agents
In packages/vue/src/dialog-select/__tests__/dialog-select.test.tsx between lines
99 and 122, the test improperly updates slots by passing them as props, which is
not the correct way to update slots in Vue tests. Refactor the test to define
slots properly during mount and avoid trying to update slots via setProps.
Instead, remount the component with updated slots or use a reactive wrapper to
test slot changes. This will improve maintainability and correctness of the slot
testing.

@kagol kagol merged commit eaeb932 into dev Jul 28, 2025
9 of 11 checks passed
@kagol kagol deleted the zzc/sync-inner-to-out-0726 branch July 28, 2025 03:34
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.

3 participants