Skip to content

Conversation

@skiyee
Copy link
Owner

@skiyee skiyee commented Nov 4, 2025

#42

Summary by CodeRabbit

发布说明

  • 新功能
    • 新增 Steps 组件,支持水平/竖直方向显示
    • 支持自定义步骤状态(待处理、进行中、完成、错误)
    • 支持可点击步骤、自定义图标、描述文本和尺寸选项
    • 提供丰富的样式定制能力(颜色、类名等)
    • 包含完整示例文档展示各种使用场景

@coderabbitai
Copy link

coderabbitai bot commented Nov 4, 2025

Walkthrough

本次更改在 Skiyee Uni UI 组件库中引入了完整的Steps(步骤)组件系统,包括核心的 SkStepsSkStep 组件实现、相应的类型定义、样式配置以及八个展示示例文件,覆盖基础用法、垂直/水平布局、可点击状态、自定义样式和图标等场景。

Changes

Cohort / File(s) 变更摘要
示例展示文件
examples/uni/src/pages-info/steps/base.vue, clickable.vue, custom.vue, description.vue, icon.vue, size.vue, status.vue, vertical.vue
新增8个Vue单文件组件,分别展示Steps组件的基础用法、可点击交互、自定义样式、描述信息、自定义图标、尺寸变体和状态显示等不同特性
核心组件实现
packages/skiyee-uni-ui/src/components/sk-steps.vue, sk-step.vue
新增步骤容器组件和步骤项组件,实现步骤管理、状态追踪、事件派发、父子通信及响应式props的完整逻辑
类型定义
packages/skiyee-uni-ui/src/types/steps.ts, types/index.ts
新增步骤相关类型定义(StepStatus、StepsContext)并在主导出文件中重新导出
样式配置
packages/skiyee-uni-ui/src/styles/sk-step.ts, sk-steps.ts, styles/index.ts
新增UnoCSS样式组件定义,支持多维度变体(方向、尺寸、状态等)并在主导出文件中暴露类型和组件
常量导出
packages/skiyee-uni-ui/src/constants/steps.ts, constants/index.ts
新增steps模块常量文件定义inject key,并在主导出中添加模块重新导出

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant SkSteps
    participant SkStep as SkStep<br/>(Child)
    participant Parent as Parent Context

    User->>SkSteps: Mount component
    SkSteps->>Parent: provide(SK_STEPS_KEY, stepsContext)
    SkStep->>SkStep: Mount SkStep instance
    SkStep->>Parent: inject(SK_STEPS_KEY) to get context
    SkStep->>SkSteps: registerStep(uid) on mount
    SkSteps->>SkSteps: Track step in steps list

    User->>SkStep: Click step
    SkStep->>SkSteps: onStepClick(index)
    SkSteps->>SkSteps: Update active, emit events
    SkSteps->>SkSteps: emit('update:active', new index)<br/>emit('change', index)<br/>emit('clickStep', index)
    SkSteps->>SkStep: Reactive update via context
    SkStep->>User: Re-render with new status

    SkStep->>SkSteps: unregisterStep(uid) on unmount
    SkSteps->>SkSteps: Remove step from tracking
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • 关键审查区域:
    • sk-steps.vuesk-step.vue 中的父子通信逻辑(provide/inject、registerStep/unregisterStep、事件派发机制)
    • 样式组件 sk-step.ts 中的多维度变体定义是否完整正确(direction、size、status、clickable、disabled、isLast 等)
    • 步骤状态计算逻辑(如何根据active索引和父组件props推导每个步骤的status)
    • 示例文件的代表性和完整性覆盖

Poem

🐰✨ 步步为营新组件,横纵切换轻而易,

点击流转状态变,样式自定显风采,

八般示例齐展现,steps家族已完备!

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题清晰准确地反映了主要变更内容,即实现Steps步骤条组件,与所有文件变更(组件实现、示例演示和类型定义)高度相关。
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/steps

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

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@netlify
Copy link

netlify bot commented Nov 4, 2025

Deploy Preview for skiyee-ui ready!

Name Link
🔨 Latest commit 369209b
🔍 Latest deploy log https://app.netlify.com/projects/skiyee-ui/deploys/690a0b75ea4a0e0008b35510
😎 Deploy Preview https://deploy-preview-43--skiyee-ui.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@skiyee
Copy link
Owner Author

skiyee commented Nov 5, 2025

@coderabbitai review

@coderabbitai
Copy link

coderabbitai bot commented Nov 5, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

♻️ Duplicate comments (6)
examples/uni/src/pages-info/steps/vertical.vue (1)

44-70: 样式重复

description.vue 中的样式完全相同,请参考该文件中关于提取共享样式的建议。

examples/uni/src/pages-info/steps/icon.vue (1)

59-85: 样式重复

与其他步骤条示例文件中的样式相同,建议统一提取。

examples/uni/src/pages-info/steps/base.vue (1)

78-111: 样式重复

与其他步骤条示例文件中的样式相同,建议统一提取到共享样式文件。

examples/uni/src/pages-info/steps/clickable.vue (1)

72-108: 样式重复

与其他步骤条示例文件中的样式相同,建议统一提取。

examples/uni/src/pages-info/steps/size.vue (1)

145-189: 样式重复

虽然此文件包含额外的尺寸对比样式(.size-compare.size-item.size-label),但 .page.demo-section.demo-title.demo-desc 等通用样式仍与其他示例文件重复,建议提取共享部分。

examples/uni/src/pages-info/steps/status.vue (1)

100-126: 样式重复

与其他步骤条示例文件中的样式相同,建议统一提取到共享样式文件。

🧹 Nitpick comments (2)
examples/uni/src/pages-info/steps/description.vue (1)

123-149: 建议提取共享样式以减少重复代码

这些样式代码(.page.demo-section.demo-title.demo-desc)在所有步骤条示例文件中完全相同。建议将这些共享样式提取到公共样式文件或通过全局样式类复用,以提高可维护性。

examples/uni/src/pages-info/steps/base.vue (1)

6-9: 可选优化:避免硬编码的边界值

当前使用硬编码的 3 作为最大步骤索引。如果未来步骤数量发生变化,需要同步更新此处。建议从实际步骤数量动态计算最大值(例如:步骤总数 - 1)。

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a1d5cd3 and 369209b.

📒 Files selected for processing (17)
  • examples/uni/src/pages-info/steps/base.vue (1 hunks)
  • examples/uni/src/pages-info/steps/clickable.vue (1 hunks)
  • examples/uni/src/pages-info/steps/custom.vue (1 hunks)
  • examples/uni/src/pages-info/steps/description.vue (1 hunks)
  • examples/uni/src/pages-info/steps/icon.vue (1 hunks)
  • examples/uni/src/pages-info/steps/size.vue (1 hunks)
  • examples/uni/src/pages-info/steps/status.vue (1 hunks)
  • examples/uni/src/pages-info/steps/vertical.vue (1 hunks)
  • packages/skiyee-uni-ui/src/components/sk-step.vue (1 hunks)
  • packages/skiyee-uni-ui/src/components/sk-steps.vue (1 hunks)
  • packages/skiyee-uni-ui/src/constants/index.ts (1 hunks)
  • packages/skiyee-uni-ui/src/constants/steps.ts (1 hunks)
  • packages/skiyee-uni-ui/src/styles/index.ts (1 hunks)
  • packages/skiyee-uni-ui/src/styles/sk-step.ts (1 hunks)
  • packages/skiyee-uni-ui/src/styles/sk-steps.ts (1 hunks)
  • packages/skiyee-uni-ui/src/types/index.ts (1 hunks)
  • packages/skiyee-uni-ui/src/types/steps.ts (1 hunks)
🔇 Additional comments (5)
packages/skiyee-uni-ui/src/styles/sk-steps.ts (1)

1-33: 实现正确

样式组件定义结构清晰,正确使用了 UnoCSS 的 variants 机制来支持横向和纵向布局,TypeScript 类型定义完善。

examples/uni/src/pages-info/steps/clickable.vue (1)

7-9: 确认空函数是否为预期行为

handleStepClick 函数当前为空实现(仅包含注释)。如果这是示例代码的预期行为,建议添加注释说明这是演示占位符;如果需要实现具体逻辑(例如日志输出或状态更新),请补充相应代码。

packages/skiyee-uni-ui/src/types/steps.ts (1)

1-48: 类型定义清晰完整

类型定义结构合理,包含了步骤条所需的所有状态和上下文接口。文档注释完善,有助于开发者理解和使用。

packages/skiyee-uni-ui/src/components/sk-step.vue (1)

181-191: 检查点击处理的逻辑条件

Line 182 的条件判断逻辑可能存在问题:

if (isDisabled.value || (!props.clickable && !parent?.props.disabled))

这个条件的第二部分 (!props.clickable && !parent?.props.disabled) 表示"当不可点击且父组件未禁用时"就返回,这个逻辑看起来有些奇怪。

请确认预期的行为:

  1. 如果 props.clickablefalse,是否应该始终阻止点击?
  2. 还是说只有当 props.clickabletrue 时才允许点击?

建议的修正逻辑可能是:

-if (isDisabled.value || (!props.clickable && !parent?.props.disabled)) {
+if (isDisabled.value || !props.clickable) {
   return
 }

或者如果需要考虑父组件的禁用状态:

-if (isDisabled.value || (!props.clickable && !parent?.props.disabled)) {
+if (isDisabled.value || !props.clickable) {
   return
 }
examples/uni/src/pages-info/steps/custom.vue (1)

1-334: 示例页面展示完善

演示页面涵盖了步骤条组件的多种自定义方式,包括样式定制、图标插槽、标题描述插槽以及完全自定义的场景,有助于开发者理解组件的使用方法。

Comment on lines +106 to +112
const isLast = computed(() => {
if (!parent || !instance) {
return false
}
const allSteps = parent.getStepIndex.length
return currentIndex.value === allSteps - 1
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

修复 isLast 计算逻辑错误

Line 110 访问 parent.getStepIndex.length 存在错误,getStepIndex 是一个函数而不是数组,因此 .length 将返回函数的参数个数(始终为 1),而非步骤总数。这会导致 isLast 的判断始终不正确。

需要在父组件上下文中添加一个方法来获取步骤总数,或者直接暴露 stepUids 数组:

 const isLast = computed(() => {
   if (!parent || !instance) {
     return false
   }
-  const allSteps = parent.getStepIndex.length
-  return currentIndex.value === allSteps - 1
+  // 需要父组件提供获取步骤总数的方法
+  // 例如: return parent.getStepCount() - 1 === currentIndex.value
+  // 或者: return parent.isLastStep(instance.uid)
 })

建议在 StepsContext 中添加 getStepCount() 方法,或者 isLastStep(uid: number) 方法。

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

🤖 Prompt for AI Agents
In packages/skiyee-uni-ui/src/components/sk-step.vue around lines 106 to 112,
isLast wrongly reads parent.getStepIndex.length (getStepIndex is a function), so
replace that with a correct step count accessor: either call a new
parent.getStepCount() or use parent.stepUids.length (or add and call
parent.isLastStep(currentUid)). Update the StepsContext to expose getStepCount()
(returning stepUids.length) or isLastStep(uid) and then change the computed to
call that method (or compare currentIndex.value to parent.getStepCount() - 1);
ensure null checks for parent/instance remain.

Comment on lines +153 to +166
const stepsContext = readonly({
props: reactive(computed(() => ({
active: props.active,
direction: props.direction,
size: props.size,
activeColor: props.activeColor,
inactiveColor: props.inactiveColor,
disabled: props.disabled,
}))),
getStepIndex,
registerStep,
unregisterStep,
onStepClick,
})
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

添加获取步骤总数的方法

为了支持子组件正确判断是否为最后一个步骤(参见 sk-step.vueisLast 的问题),建议在 stepsContext 中添加一个获取步骤总数的方法。

+/**
+ * 获取步骤总数
+ */
+function getStepCount(): number {
+  return stepUids.value.length
+}
+
 // 提供给子组件的上下文
 const stepsContext = readonly({
   props: reactive(computed(() => ({
     active: props.active,
     direction: props.direction,
     size: props.size,
     activeColor: props.activeColor,
     inactiveColor: props.inactiveColor,
     disabled: props.disabled,
   }))),
   getStepIndex,
+  getStepCount,
   registerStep,
   unregisterStep,
   onStepClick,
 })

同时需要在 packages/skiyee-uni-ui/src/types/steps.tsStepsContext 接口中添加对应的类型定义:

export interface StepsContext {
  props: { ... };
  getStepIndex: (uid: number) => number;
  getStepCount: () => number;  // 新增
  registerStep: (uid: number) => void;
  unregisterStep: (uid: number) => void;
  onStepClick: (index: number) => void;
}
🤖 Prompt for AI Agents
In packages/skiyee-uni-ui/src/components/sk-steps.vue around lines 153 to 166,
add a getStepCount method to the stepsContext that returns the current number of
registered steps (e.g., returns steps.length or equivalent internal collection
size) and include that method in the readonly object alongside
getStepIndex/registerStep/unregisterStep/onStepClick; also update
packages/skiyee-uni-ui/src/types/steps.ts to add getStepCount: () => number to
the StepsContext interface so child components (like sk-step.vue) can determine
if they are the last step.

🛠️ Refactor suggestion | 🟠 Major

简化 stepsContext 的响应式包装

Line 154 使用了 reactive(computed(...)) 的模式,这是不必要且可能引起问题的:

  1. computed() 已经返回一个响应式引用
  2. 将其包装在 reactive() 中是多余的
  3. 这可能导致响应式追踪出现意外行为

建议直接使用 computed 或 reactive,而不是两者嵌套:

方案 1(推荐):直接使用对象,props 部分使用 toRefs

+import { computed, readonly, ref, toRefs } from 'vue'

 // 提供给子组件的上下文
 const stepsContext = readonly({
-  props: reactive(computed(() => ({
+  props: toRefs(props),
-    active: props.active,
-    direction: props.direction,
-    size: props.size,
-    activeColor: props.activeColor,
-    inactiveColor: props.inactiveColor,
-    disabled: props.disabled,
-  }))),
   getStepIndex,
   registerStep,
   unregisterStep,
   onStepClick,
 })

方案 2:如果需要精确控制,使用 computed 返回整个对象

 // 提供给子组件的上下文
-const stepsContext = readonly({
+const stepsContext = computed(() => readonly({
-  props: reactive(computed(() => ({
+  props: {
     active: props.active,
     direction: props.direction,
     size: props.size,
     activeColor: props.activeColor,
     inactiveColor: props.inactiveColor,
     disabled: props.disabled,
-  }))),
+  },
   getStepIndex,
   registerStep,
   unregisterStep,
   onStepClick,
-})
+}))
📝 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 stepsContext = readonly({
props: reactive(computed(() => ({
active: props.active,
direction: props.direction,
size: props.size,
activeColor: props.activeColor,
inactiveColor: props.inactiveColor,
disabled: props.disabled,
}))),
getStepIndex,
registerStep,
unregisterStep,
onStepClick,
})
const stepsContext = computed(() => readonly({
props: {
active: props.active,
direction: props.direction,
size: props.size,
activeColor: props.activeColor,
inactiveColor: props.inactiveColor,
disabled: props.disabled,
},
getStepIndex,
registerStep,
unregisterStep,
onStepClick,
}))

Comment on lines +33 to +41
horizontal: {
root: 'flex-col',
container: 'flex-col items-center',
content: 'sk-variant:mt-12 sk-variant:ml-0 items-center text-center',
line: 'sk-variant:left-1/2 sk-variant:translate-x-1/2 sk-variant:top-0 sk-variant:h-full sk-variant:w-2',
},
vertical: {
root: 'flex-row',
line: 'sk-variant:top-1/2 sk-variant:-translate-y-1/2 sk-variant:left-0 sk-variant:w-full sk-variant:h-2',
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

修复水平/垂直连线的方向与对齐
目前 direction.horizontal 下的 line 使用了竖向尺寸(h-full w-2 + translate-x-1/2),而 direction.vertical 则使用了横向尺寸(w-full h-2)。这会导致:

  1. 水平步骤的连线呈竖直方向,无法横向连接到下一步;
  2. 垂直步骤的连线呈水平方向,同样无法正确向下延展;
  3. 水平步骤中的 translate-x-1/2 还会把线条从中心向右偏移。
    请交换两种方向下的连线尺寸/定位并把水平步骤的平移改为 -translate-x-1/2,使两种布局都能按主轴正确对齐。
       horizontal: {
         root: 'flex-col',
         container: 'flex-col items-center',
         content: 'sk-variant:mt-12 sk-variant:ml-0 items-center text-center',
-        line: 'sk-variant:left-1/2 sk-variant:translate-x-1/2 sk-variant:top-0 sk-variant:h-full sk-variant:w-2',
+        line: 'sk-variant:top-1/2 sk-variant:-translate-y-1/2 sk-variant:left-0 sk-variant:w-full sk-variant:h-2',
       },
       vertical: {
         root: 'flex-row',
-        line: 'sk-variant:top-1/2 sk-variant:-translate-y-1/2 sk-variant:left-0 sk-variant:w-full sk-variant:h-2',
+        line: 'sk-variant:left-1/2 sk-variant:-translate-x-1/2 sk-variant:top-0 sk-variant:h-full sk-variant:w-2',
       },
📝 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
horizontal: {
root: 'flex-col',
container: 'flex-col items-center',
content: 'sk-variant:mt-12 sk-variant:ml-0 items-center text-center',
line: 'sk-variant:left-1/2 sk-variant:translate-x-1/2 sk-variant:top-0 sk-variant:h-full sk-variant:w-2',
},
vertical: {
root: 'flex-row',
line: 'sk-variant:top-1/2 sk-variant:-translate-y-1/2 sk-variant:left-0 sk-variant:w-full sk-variant:h-2',
horizontal: {
root: 'flex-col',
container: 'flex-col items-center',
content: 'sk-variant:mt-12 sk-variant:ml-0 items-center text-center',
line: 'sk-variant:top-1/2 sk-variant:-translate-y-1/2 sk-variant:left-0 sk-variant:w-full sk-variant:h-2',
},
vertical: {
root: 'flex-row',
line: 'sk-variant:left-1/2 sk-variant:-translate-x-1/2 sk-variant:top-0 sk-variant:h-full sk-variant:w-2',
🤖 Prompt for AI Agents
In packages/skiyee-uni-ui/src/styles/sk-step.ts around lines 33 to 41, the line
classes for horizontal and vertical directions are swapped and the horizontal
translate is wrong; swap the line size/position values between
direction.horizontal and direction.vertical so horizontal uses w-full h-2 and
horizontal positioning uses left-0 top-1/2 with -translate-y-1/2 (or equivalent
horizontal-centering), while vertical uses left-1/2 top-0 with -translate-x-1/2
removed/adjusted to center vertically; specifically exchange the width/height
and positioning class sets between the two blocks and change the horizontal
translate-x-1/2 to -translate-x-1/2 so the connector aligns along the main axis
for each direction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants