-
Notifications
You must be signed in to change notification settings - Fork 330
feat: modify the resource file loading mode and add postcss plugin configuration. #3615
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis 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
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
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
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
examples/sites/demos/apis/numeric.jsOops! 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: 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.jsOops! 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: 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.jsOops! 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: 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.
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this 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
changeColormethod is no longer used since the color picker now handles color changes directly viav-model. Additionally, the codethis.params.color = '#666'would not work correctly sinceparamsis 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-circlefor specificity instead
Writing the selector as&.is-circle.is-circleonly inflates the rule’s weight while harming readability; the second.is-circleprovides 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-testidattributes 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:
- Use English test name for international teams:
-test('dialogSelect 设置多选状态', async ({ page }) => { +test('dialogSelect multi-selection state management', async ({ page }) => {
- 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()andgetByRole()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
--colorand--sizecould 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
📒 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 中定义 huiChartOption 或 option,而是应该依赖 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-core 的 huiChartOption 来管理图表选项,不要在 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 中定义 huiChartOption 或 option,而是应该依赖 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 中定义 huiChartOption 或 option,而是应该依赖 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 中定义 huiChartOption 或 option,而是应该依赖 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-core 的 huiChartOption 来管理图表选项,不要在 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 中定义 huiChartOption 或 option,而是应该依赖 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 中定义 huiChartOption 或 option,而是应该依赖 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-core 的 huiChartOption 来管理图表选项,不要在 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 中定义 huiChartOption 或 option,而是应该依赖 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 中定义 huiChartOption 或 option,而是应该依赖 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 中定义 huiChartOption 或 option,而是应该依赖 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 中定义 huiChartOption 或 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-core 的 huiChartOption 来管理图表选项,不要在 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 中定义 huiChartOption 或 option,而是应该依赖 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
TinyColorPickerbound viav-modeltoparams.colorprovides 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
TinyButtonwithTinyColorPicker.examples/sites/demos/pc/app/qr-code/icon-composition-api.vue (4)
4-4: LGTM! Smart constraint logic for icon size.The
iconSizeconstraint 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
reactiveimport andTinyNumericcomponent import correctly supports the new interactive functionality.
14-21: LGTM! Appropriate use of reactive() for interactive controls.Converting
paramsfromref()toreactive()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: centerandgap: 20pxprovides 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
TinyColorPickerwithv-model="color"provides much better user experience compared to the previous button-based approach.
22-30: LGTM! Proper reactive pattern with computed property.Converting
paramsto a computed property that referencesthis.coloris 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
iconSizestays within 30% of the QR codesizeis 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
TinyNumericto the existing import follows the established pattern and is properly structured.
16-16: LGTM! Proper component registration.The
TinyNumericcomponent 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
paramscomputed property correctly leverages Vue's reactivity system to dynamically update QR code parameters wheniconSizeorsizechanges. 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-nestingis added as a devDependency.
If the library is referenced by the production Vite/PostCSS pipeline (e.g.,packages/themebuild), 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 goodSwitching to
type PropTypefrom@opentiny/vue-commonavoids 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 – OKSame consolidation as other components; keeps treeshaking clean.
packages/vue/src/pager/src/index.ts (1)
1-1: Consolidated PropType source – OKNo behavioural change; compile-time only.
packages/vue/src/button-group/src/index.ts (1)
12-12: Uniform PropType import – OKMatches 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:reportscript 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
PropTypeimport into the existing@opentiny/vue-commonimport 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
PropTypeto use@opentiny/vue-commonmaintains 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
PropTypeimport to@opentiny/vue-commonwith proper type annotation maintains consistency across the codebase.
134-136: LGTM! Well-typed onClose callback prop.The new
onCloseprop provides a clean callback mechanism for dialog close events. The typing as() => voidis 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-simpleproperty 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/nestingplugin mapping topostcss-nestingis 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
InputEventinstead of genericFunction- 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
falsestate and the dynamic update totrueprovides 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 explicitquery: '?raw', import: 'default'improves clarity and aligns with the parallel change inresourceMobileFirst.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
inputevent 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-positionprop 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
defaultslot 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.
| 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() |
There was a problem hiding this comment.
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.
| 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.
| 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() |
There was a problem hiding this comment.
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.
| 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() |
There was a problem hiding this comment.
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.
| 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.
| const onInput = (event: InputEvent) => { | ||
| const currentValue = (event.target as HTMLInputElement).value | ||
| TinyModal.message({ | ||
| message: `新值: ${currentValue}`, | ||
| status: 'info' | ||
| }) | ||
| inputCount.value++ | ||
| } |
There was a problem hiding this comment.
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.
| 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.
| 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: '完成' } | ||
| ] |
There was a problem hiding this comment.
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.
| 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.
| div { | ||
| position: relative; | ||
| color: var(--active-color); | ||
| &:not(:first-of-type) { | ||
| margin: 5px 0; | ||
| display: flex; | ||
| justify-content: center; | ||
| } | ||
| } |
There was a problem hiding this comment.
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.
| 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.
| ol { | ||
| display: flex; | ||
| } |
There was a problem hiding this comment.
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.
| 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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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.
| 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) | ||
| }) |
There was a problem hiding this comment.
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.
| 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.
| 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()) | ||
| }) |
There was a problem hiding this comment.
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.
| 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.
同步内部代码
PR
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
Issue Number: N/A
What is the new behavior?
Does this PR introduce a breaking change?
Other information
Summary by CodeRabbit
New Features
trigger-simplefor split,text-positionand a default slot for time-line, and anonCloseprop for dialog box.Bug Fixes
Tests
Chores
Style
Refactor