50 lines
2.1 KiB
Markdown
50 lines
2.1 KiB
Markdown
# 组件与样式
|
||
|
||
## 组件形状
|
||
|
||
React 模块使用具名函数组件,不使用无意义的 default export。`features/system/pages/system-status-page.tsx` 展示了页面组件如何组合 query、store 和 shared UI;`shared/ui/card.tsx` 展示了通过原生 HTML 属性扩展 primitive 的方式。
|
||
|
||
```tsx
|
||
export function Button({
|
||
className,
|
||
size,
|
||
type = "button",
|
||
variant,
|
||
...props
|
||
}: ButtonHTMLAttributes<HTMLButtonElement> &
|
||
VariantProps<typeof buttonVariants>) {
|
||
return (
|
||
<button
|
||
className={cn(buttonVariants({ size, variant }), className)}
|
||
type={type}
|
||
{...props}
|
||
/>
|
||
)
|
||
}
|
||
```
|
||
|
||
可复用组件应保留原生属性和 `className`,通过 `...props` 支持组合;只在确实需要时添加受限的 variant。
|
||
|
||
## 样式与组合
|
||
|
||
- 使用 Tailwind utility class;主题 token 和全局基础规则放在 `src/styles/globals.css`。
|
||
- 使用 `cn`(`shared/ui/utils.ts`)合并可选 class,使用 `class-variance-authority` 管理 Button、Badge 等有限变体。
|
||
- 复杂页面用 `Card`、`CardHeader`、`CardContent` 等 composition primitive,而不是复制一套容器样式。
|
||
- 新建 shared primitive 前先搜索是否已有 `Button`、`Badge`、`Card` 或 `cn`。
|
||
|
||
## 页面状态
|
||
|
||
页面应把加载、错误、成功状态转成用户可见的语义文本。`SystemStatusPage` 根据 query 状态显示“正在连接”“连接异常”“运行正常”,没有数据时使用安全的默认服务名。
|
||
|
||
## 可访问性
|
||
|
||
- 交互元素必须使用真实的 `<button>` 或其他语义元素;`Button` 默认 `type="button"` 以避免意外提交。
|
||
- 只有图形含义的 icon 使用 `aria-hidden="true"`;没有文字的主题切换按钮提供 `aria-label="切换主题"`,参照 `system-status-page.tsx`。
|
||
- 使用 `main`、标题、段落等语义结构,文本状态不能只靠颜色表达。
|
||
|
||
## 避免
|
||
|
||
- 不要在 shared UI 中请求数据、读取 feature hook 或写业务分支。
|
||
- 不要用 `dangerouslySetInnerHTML`、无理由的 `any` 或无语义的 `<div onClick>`。
|
||
- 不要把所有页面样式搬进新的全局 CSS;优先使用现有 token 和局部 utility class。
|