docs: ai 协作文档体系重构与多 ai 仲裁结果落地

1.AI 协作文档体系重构(objections/worklines/contracts+matrix.md)

2.coord 仲裁文档(final-decisions/cross-review/final-rulings/orchestration)

3.各服务 01/02 文档补全

4.共享包初始化(shared-ts/shared-go/hooks/ui-components/ui-tokens)

5.Proto 契约补全

6.004 架构影响地图更新

7.端口分配表

8.设计规格文档
This commit is contained in:
SpecialX
2026-07-10 12:58:22 +08:00
parent 2a2a56f541
commit faaaf29f67
120 changed files with 23201 additions and 2 deletions

View File

@@ -0,0 +1,119 @@
import { useMemo, useState } from "react";
/**
* useA11yId - 唯一 ARIA ID 生成器
*
* 用途:为表单元素生成 aria-labelledby / aria-describedby 关联的唯一 ID。
* 迁移自 CICD 项目 A11y 工具集。
*
* @example
* const id = useA11yId("email-input");
* <input id={id} aria-describedby={`${id}-error`} />
* <span id={`${id}-error`}>{errorMessage}</span>
*/
let idCounter = 0;
/**
* 生成唯一 ID带可选前缀
* 使用计数器 + 随机数,避免 SSR/CSR hydration mismatch。
*/
export function useA11yId(prefix?: string): string {
const [id] = useState(() => {
idCounter += 1;
const random = Math.random().toString(36).slice(2, 8);
const base = prefix
? `${prefix}-${idCounter}-${random}`
: `a11y-${idCounter}-${random}`;
return base;
});
return id;
}
/**
* 批量生成关联 ID用于表单 input + label + error + description 关联)
*
* @example
* const ids = useA11yIds("email");
* // ids = { input: "email-input-1-xxx", label: "email-label-1-xxx", error: "email-error-1-xxx", description: "email-description-1-xxx" }
*/
export function useA11yIds(prefix: string): {
input: string;
label: string;
error: string;
description: string;
} {
const inputId = useA11yId(`${prefix}-input`);
const labelId = useA11yId(`${prefix}-label`);
const errorId = useA11yId(`${prefix}-error`);
const descriptionId = useA11yId(`${prefix}-description`);
return useMemo(
() => ({
input: inputId,
label: labelId,
error: errorId,
description: descriptionId,
}),
[inputId, labelId, errorId, descriptionId],
);
}
/**
* 合并 ARIA 属性(覆盖优先级:后者覆盖前者)
*
* @example
* mergeA11yProps({ "aria-label": "默认" }, { "aria-label": "自定义" })
* // => { "aria-label": "自定义" }
*/
export function mergeA11yProps(
...props: Array<Record<string, unknown> | undefined>
): Record<string, unknown> {
const result: Record<string, unknown> = {};
for (const prop of props) {
if (prop) {
Object.assign(result, prop);
}
}
return result;
}
/**
* 描述输入框的 ARIA 属性
*
* @example
* const a11y = describeInput({ label: "邮箱", required: true, error: "邮箱格式错误", description: "请输入工作邮箱" });
* <input {...a11y} />
*/
export function describeInput(options: {
label: string;
required?: boolean;
error?: string;
description?: string;
invalid?: boolean;
}): Record<string, unknown> {
const { label, required, error, description, invalid } = options;
const props: Record<string, unknown> = {
"aria-label": label,
};
if (required) {
props["aria-required"] = true;
}
if (invalid || error) {
props["aria-invalid"] = true;
}
// aria-describedby 由调用方拼接(需关联 error/description 的 ID
const describedBy: string[] = [];
if (description) describedBy.push("description");
if (error) describedBy.push("error");
if (describedBy.length > 0) {
props["aria-describedby"] = describedBy.join(" ");
}
return props;
}