WS-04 · Web System · Subsystem 04 / 11 · WCN.NETWORK · 2026

核心组件

VS-10 组件库的 Web 实例化。每个原子组件给出变体 · 尺寸 · 状态 · 无障碍 · 令牌消费,并把项目里两套并存的 button/badge 实现(shadcn 与手写)收敛到同一份契约。组件是证据对象,不是通用 SaaS 控件。

shadcn ⇄ bespoke 统一全状态focus-visible44px 触达Radix 浮层
№ 01 — Philosophy

证据对象,不是控件

按钮不"好看",按钮可信。它的状态、焦点、触达都可被机器验证。
— WCN Web System
① 一份契约同一组件无论用 shadcn 还是手写 CSS,变体名/尺寸名/状态都一致。调用者无需关心实现。
② 状态先行每个交互组件必须定义 hover/focus/disabled/loading/error/active——而非只画默认态。
③ 令牌消费颜色/圆角/间距全走语义令牌(WS-01),禁裸 hex、禁 primitive 直引。
№ 02 — Two Impls, One Contract

shadcn 与 bespoke 并存

项目里组件有两套实现,本规范不强制合并,而是统一契约:

实现位置令牌方式用在
shadcn/uicomponents/ui/*Tailwind 语义类 + CVA 变体新组件 / theme-toggle
bespokeglobals.css .button/.badgevar() 直引营销 / dashboard / 表单
Decision · 统一变体名

两套都必须暴露相同枚举:button variant = default · secondary · ghost · destructive · outline · link,size = sm · default · lg · icon;badge intent = neutral · success · warning · danger · info · authority。新可复用组件优先进 components/ui/

№ 03 — Button

Button · 全变体全状态

主操作 = 墨黑实底(Decision A);权威描边带 data-authority;销毁 = crimson。
尺寸 sm/default/lg/icon;disabled 用 aria-disabled + opacity;loading 带 aria-busy 与 spinner。
状态表现令牌
hoveraccent → accent-hover--accent-hover
focus-visible古铜环var(--focus)
disabledopacity .5 + 不可点aria-disabled
loadingspinner + aria-busyaria-busy="true"
№ 04 — Badge & Status

六意图,两实现合一

Neutral Success Warning Danger Info ★ Authority
状态徽章带符号+文字,不只靠颜色(色盲/单色安全)。

StatusBadge 把 40+ 状态枚举映射到这六意图。shadcn Badge 与 bespoke .badge-* 都落到同一组意图。

意图语义令牌典型状态枚举
success--signal-successcleared · settled · active · approved
warning--signal-warningpending · review · expiring
danger--signal-dangerflagged · failed · suspended
info--signal-infodraft · queued · info
authority--authorityverified · sealed(带 data-authority)
№ 05 — Input & Form Fields

Input · 字段全状态

⚠ 请填写有效值
字段 = label + control + (错误信息)。最小高 44px;error 用 aria-invalid + 文字,不只红框。
Gap · 字段级错误组件

当前只有表单级 .form-error,缺字段级 <FieldError>。规则:错误信息与字段用 aria-describedby 关联,屏幕阅读器随焦点播报。

全局 input/textarea/select 样式在 globals.css(高风险区,改动全站生效)。新增字段优先用既有类,勿覆盖全局。

№ 06 — Card

Card · 默认线条,权威古铜

NODE-CTRY-SG-001
普通卡片

默认顶条 = line。绝大多数卡片用这个。

NODE-CTRY-SG-001
证明卡片 ★ Sealed

仅当承载已验证/封存证明,顶条才是古铜。

Rule · 古铜条 = 证明

卡片默认顶条是 --line,不是古铜。只有带 data-authority(verified/sealed)的证明卡才用 --authority 古铜条。每个视觉组古铜 ≤1。

结构:Card · CardHeader · CardTitle · CardDescription · CardContent · CardFooter(shadcn)或 .card(bespoke)。

№ 07 — Overlays

模态 · 抽屉 · 下拉 · 提示

全部基于 Radix(components/ui/),已用逻辑属性(start/end · ps/pe)支持 RTL。

确认对话框

此操作不可撤销。

焦点陷阱 + Esc 关闭 + 关闭后焦点归位触发元素。
组件关键 a11y / RTL
Dialog / AlertDialogrole=dialog · aria-modal · 焦点陷阱;start-[50%] 居中
Sheetside top/bottom/left/right;border-s/-e 逻辑边
DropdownMenups-8/pe-2/start-2 逻辑内距;方向键 + Esc
Tooltip / Popover悬浮/聚焦触发;align start/center/end
Rule · 浮层圆角与高度

浮层用 --radius-lg/-xl + --shadow-lg;AlertDialog 的动作按钮复用 buttonVariants(),保持与 §03 同契约。

№ 08 — Avatar / Toast / Gaps

头像 · 提示 · 待补组件

SCw3 Toast · 已保存
头像三处尺寸(36/32/28)。当前靠 inline style 覆写——应改尺寸修饰类或 size prop。
缺口现状 / 规则
Toastersonner 已存在但未挂载 → layout 需渲染 <Toaster/>
Select / Combobox仅原生 <select> → 需共享组件
PaginationDataTable 有 footer 槽但无分页 → 需共享
Skeleton只有 spinner → 需骨架占位
avatar sizeinline style 覆写 → 改修饰类 .ava-sm/-lg
Rule · 优先复用

填补缺口时优先加进 components/ui/(shadcn 风格)并落到统一契约,而非又在 globals.css 追加一套。详见 WS-05(模式)与 WS-11(治理)。

№ 09 — Lint & Checklist

组件的机器可执行

规则说明可检查
comp.semantic-tokens只用语义令牌,无裸 hex✓ grep
comp.variants-unifiedbutton/badge 变体名两实现一致✓ types
comp.focus-visible每个交互元素有焦点环✓ DOM
comp.touch触达 ≥44px✓ DOM
comp.stateshover/focus/disabled/loading/error 齐✓ review
comp.status-symbol状态带符号,不只颜色✓ review
comp.card-rail古铜条仅 data-authority 卡✓ DOM
$ component-lint semantic tokens only ............. pass button/badge variants unified .... contract ok focus-visible on interactive ..... all touch targets >=44px ............. pass empty / loading / error defined .. pass <Toaster/> mounted ............... missing shared Select / Pagination ....... gap

发布前自检

WS-04 完成度

组件哲学 + 双实现契约 + Button + Badge + Input + Card + 浮层 + 头像/缺口 + Lint 九项齐全。WS-04 ✓ 完成。