Files
ycode/docs/界面基础组件规范-2026-10-18.md
xiaohan.yuan febb28aa6f docs: add base UI component contract
Define the P1 component APIs, token mappings, and settings-page pilot scope for parallel implementation.
2026-10-18 18:36:44 +08:00

8.2 KiB
Raw Permalink Blame History

YCode 界面基础组件规范(2026-10-18)

本文件是第一轮组件统一的接口契约。后续子代理按此实现,不得各写一套。

总则

  • YCode 自有界面只消费 --yc-*;--wb-* 只允许出现在恢复模块的兼容层。
  • 组件样式只能写 var(--yc-*),组件内部不得写裸 hex、裸 px、!important。
  • 组件不得带外部 margin;间距由调用方决定。
  • 每个组件顶层元素必须接受并合并 className。
  • 第一轮不引入第三方 UI 库,不引入 Tailwind,不引入 clsx。
  • 组件用显式 variant/size props,禁止调用方拼 wb-button--* 类名。

命名

--yc-<component>-<property>[-<state>][-<size>]

示例:

--yc-button-primary-bg
--yc-button-primary-bg-hover
--yc-button-height-md
--yc-input-height-md
--yc-switch-track-width-lg

组件 token 定义在 src/renderer/src/styles/tokens.css 或独立的 src/renderer/src/ui/tokens.css,二者只能有一处。页面作用域不得重定义。

需要补的 L0 基础色

现有 styles/tokens.css 缺少原版控件的部分透明度阶。第一轮组件需要补齐:

token 浅色 深色来源
--yc-black-90 rgba(0, 0, 0, 0.9) rgba(255, 255, 255, 0.9) 由组件层重映射
--yc-black-75 rgba(0, 0, 0, 0.75) rgba(255, 255, 255, 0.75) 由组件层重映射
--yc-white-90 rgba(255, 255, 255, 0.9) 同
--yc-white-75 rgba(255, 255, 255, 0.75) 同
--yc-white-30 rgba(255, 255, 255, 0.3) 同
--yc-white-20 rgba(255, 255, 255, 0.2) 同
--yc-white-10 rgba(255, 255, 255, 0.1) 同

这些值来自当前 --wb-palette-* 实际使用值,不是新设计。

P1 组件

Button

接口:

type ButtonVariant = 'primary' | 'secondary' | 'grey' | 'ghost' | 'link' | 'danger'
type ButtonSize = 'sm' | 'md' | 'lg'

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: ButtonVariant
  size?: ButtonSize
  iconOnly?: boolean
  loading?: boolean
  iconLeft?: React.ReactNode
  iconRight?: React.ReactNode
}

当前对应的 wb-button 类名到 props 的映射:

现类名 新写法
wb-button wb-button--primary wb-button--medium <Button variant="primary" size="md">
wb-button wb-button--secondary wb-button--medium <Button variant="secondary" size="md">
wb-button wb-button--ghost wb-button--medium wb-button--icon-only <Button variant="ghost" size="md" iconOnly>
wb-button wb-button--small <Button size="sm">

几何值来源(当前 --wb-button-*):

属性 sm md lg
height 24px 32px 48px
padding-x 8px 12px 32px
gap 2px 4px 8px
font-size 12px 14px 14px
line-height 20px 22px 22px
radius 6px 8px 12px
icon 12px 16px 16px

状态值来源:

状态 浅色来源 深色来源
primary bg black-90 white-90
primary bg hover black-75 white-75
primary fg white-100 black-90
secondary bg white-100 #262626
secondary bg hover gray-2 #f7f7f7 #2e2e2e
secondary border #dedede #3d3d3d
grey bg gray-4 #ebebeb #383838
grey bg hover gray-5 #e6e6e6 #404040
ghost hover #0000000f #ffffff14
link fg #1470b4 #46a8f0
danger bg red-7 #e85c5c #af191a
danger hover red-6 #ec7474 #a31717

深色值来自当前 capability-center-source.css 与 subagents/theme.css 的已验证闭包;实现时先取现有计算值,不得自创。

IconButton

IconButton 是 Button 的 iconOnly 语法糖,不单独维护尺寸表。

  • 必须有 aria-label 或 title。
  • 默认 size="md"、variant="ghost"。
  • 图标容器固定为对应 size 的 height/width。

Input

接口:

type InputSize = 'sm' | 'md' | 'lg'

interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> {
  size?: InputSize
  invalid?: boolean
  filled?: boolean
  prefix?: React.ReactNode
  suffix?: React.ReactNode
  wrapperClassName?: string
}

几何值来源:

属性 sm md lg
height 28px 32px 48px
padding-x 8px 8px 12px
radius 6px 8px 12px
font-size 12px 14px 14px

状态值:

状态 浅色 深色
bg white-100 #242424
border gray-5 #e6e6e6 #454545
border hover/focus black-30 #0000004d white-30 #ffffff4d
filled bg gray-3 #f2f2f2 #242424
disabled bg gray-2 #f7f7f7 #171717
placeholder black-30 white-30

Switch

接口:

interface SwitchProps {
  checked: boolean
  onCheckedChange?(checked: boolean): void
  disabled?: boolean
  readOnly?: boolean
  size?: 'sm' | 'md' | 'lg'
  'aria-label': string
  className?: string
}

几何值来源:

属性 sm md lg
track width 24px 26px 34px
track height 14px 16px 20px
thumb 10px 12px 16px
thumb translate 8px 8px 12px

状态值:

状态 来源
track bg gray-5 #e6e6e6
track bg checked brand #00c29a
track bg checked hover brand-7 #40d1b3
thumb bg white-100
focus outline 2px / offset 2px
disabled 保持几何,降低不透明度

Select

第一轮不重写行为,只统一外观壳。

  • 复用 src/renderer/src/components/source-select/SourceSelect.tsx 与 RecoveredSelect。
  • 闭合态必须支持 value、placeholder、invalid、disabled、size、loading。
  • 几何沿用 --wb-select-*:height 32 / radius 8 / font-size 14 / caret 16。
  • 设置页不可用行里的“假 Select”也必须走同一视觉壳,禁止再手写 wb-select。

Dialog / ConfirmDialog

第一轮先统一壳,不改业务流程。

  • Dialog:标题、内容、footer actions、关闭按钮、遮罩。
  • ConfirmDialog:title、description、confirmLabel、cancelLabel、danger、busy。
  • 几何来源:radius 24、max-width 480/640/960、遮罩 #00000026 浅色 / #0006 深色。
  • 已存在 task-confirm-dialog.tsx 与 wb-modal 结构,优先抽壳而不是重写。

Popover / Menu

第一轮统一:

  • Popover:定位、边界收敛、关闭策略、role。
  • Menu / MenuItem / MenuSeparator:键盘导航、选中态、危险态。
  • 几何来源:radius 16、padding 8、shadow 沿用当前 --wb-popover-shadow。

Segmented / Tabs

  • Segmented:track padding 2、item gap 4、item radius 6、height 32、active weight 600。
  • Tabs 用于设置导航、能力中心一级导航;选中态只改颜色与字重,不跳尺寸。

设置页试点范围

试点只迁移设置页里由 YCode 自己渲染的控件,不改恢复面板的布局规则。

第一批替换点:

文件 当前 目标
GeneralSettingsPanel.tsx 本地 Switch / UnavailableSwitch ui/Switch
GeneralSettingsPanel.tsx UnavailableSelect 手写 wb-select ui/Select 的只读/禁用态
GeneralSettingsPanel.tsx wb-button 打开目录/更改/前往系统设置 ui/Button
GeneralSettingsPanel.tsx wb-input 路径输入 ui/Input
SettingsDialog.tsx 本地 .btn 工作空间按钮 ui/Button
ModelSettingsPanel.tsx 本地 Button / Field 包装 ui/Button + ui/Input

不允许改动的部分:

  • source-*-recovered.css 与任何 REA 生成文件。
  • .general-settings-panel__* 布局类名,迁移后仍保留外层结构。
  • 已确认的 1:1 几何、文案、禁用态与 aria-disabled 语义。

验收

每个组件落地时必须提供:

  1. npm run typecheck 通过。
  2. 组件自身的最小回归或渲染 fixture。
  3. 设置页浅色/深色截图对比,差异必须可解释。
  4. npm run check:tokens 不因新增文件失败。
  5. 报告修改文件、映射了哪些旧类名、未迁移的调用点、剩余风险。

在 scripts/verify-ui.mjs 假桥修复前,渲染断言可以由主上下文代跑;组件实现者不得改用其它采集渠道查看 WorkBuddy 原版。