新组件提案:Choice 选择交互
📋 基本信息
| 字段 |
内容 |
| 组件名 |
Choice |
| 中文名 |
选择交互 |
| 所属分组 |
Wake(唤醒) |
| 优先级 |
P1 |
| 提案人 |
— |
| 状态 |
待评审 |
🎯 背景与动机
现状问题
在大模型对话场景中,模型经常需要向用户呈现一组选项让用户做出选择,例如:
- 意图确认:模型推测用户意图后,呈现多个可能理解让用户选择("您是想 A 还是 B?")
- 参数收集:工具调用前需要用户从预定义值中选择参数(如选择日期范围、数据类型)
- 方案推荐:模型生成多个方案,用户挑选其中一个继续
- 流程引导:多步对话中引导用户选择下一步操作
当前 antd 的 Select、Radio、Checkbox 是面向表单场景设计的静态控件,在 AI 对话上下文中存在以下不匹配:
| 维度 |
antd 表单控件 |
AI 对话场景诉求 |
| 上下文 |
嵌入表单,静态存在 |
嵌入对话气泡,随消息流出现 |
| 数据来源 |
开发者硬编码 |
LLM 动态生成,结构化输出 |
| 视觉层次 |
紧凑、功能导向 |
内容丰富,需要承载描述/图标/推荐标签 |
| 交互反馈 |
仅值变化 |
需要流式加载态、选中后反馈到对话流 |
| 差异化 |
统一表单风格 |
需要 AI 语义化视觉(推荐标记、禁用原因等) |
与现有组件的区别
| 现有组件 |
定位 |
与 Choice 的区别 |
Prompts |
展示预设提示词建议,引导用户发起对话 |
Choice 是模型响应中的选项,是模型→用户的交互,而非唤醒 |
Suggestion |
斜杠命令式级联选择,输入增强 |
Choice 是内容级选项,不是命令补全;不需要级联结构 |
Actions |
消息后操作(复制/反馈/重试) |
Actions 是操作按钮,Choice 是选择性内容卡片 |
Choice 填补的是「模型输出结构化选项 → 用户选择 → 结果回传对话流」这一核心交互链路的空白。
🧩 组件设计
名词定义
- Choice:组件名,代表一次选择交互
- ChoiceItem:单个选项,包含标识、展示内容与元数据
- 选择模式:单选(single)/ 多选(multiple),决定用户可选数量
- 布局模式:列表(list)/ 网格(grid)/ 卡片(card),决定视觉呈现
- 推荐标记:AI 对某选项的推荐度标记,差异化于普通选中态
核心 API
ChoiceProps
type SemanticType = 'root' | 'header' | 'list' | 'item' | 'itemContent' | 'indicator' | 'footer';
interface ChoiceProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'onSelect' | 'onChange'> {
/** 选项列表 */
items: ChoiceItemType[];
/** 选择模式 */
mode?: 'single' | 'multiple';
/** 布局模式 */
layout?: 'list' | 'grid' | 'card';
/** 当前选中值(受控) */
value?: ChoiceValueType | ChoiceValueType[];
/** 默认选中值 */
defaultValue?: ChoiceValueType | ChoiceValueType[];
/** 选中变化回调 */
onChange?: (value: ChoiceValueType | ChoiceValueType[], info: ChangeInfo) => void;
/** 选项点击回调(不改变选中状态) */
onItemClick?: (info: { data: ChoiceItemType; index: number }) => void;
/** 确认回调,用户完成选择后触发 */
onConfirm?: (value: ChoiceValueType | ChoiceValueType[], info: ChangeInfo) => void;
/** 标题 */
title?: React.ReactNode;
/** 描述文本,标题下方的辅助说明 */
description?: React.ReactNode;
/** 底部操作区(如确认按钮) */
footer?: React.ReactNode;
/** 是否禁用 */
disabled?: boolean;
/** 是否显示 loading 态 */
loading?: boolean;
/** 多选模式下最大可选数量 */
maxCount?: number;
/** 选择指示器类型 */
indicator?: 'check' | 'radio' | 'number' | 'none';
/** 是否显示确认按钮 */
confirmable?: boolean;
/** 确认按钮文案 */
confirmText?: React.ReactNode;
/** 渐入动画 */
fadeIn?: boolean;
/** 从左渐入动画 */
fadeInLeft?: boolean;
// 语义化样式
classNames?: Partial<Record<SemanticType, string>>;
styles?: Partial<Record<SemanticType, React.CSSProperties>>;
prefixCls?: string;
rootClassName?: string;
}
ChoiceItemType
type ChoiceValueType = string | number;
interface ChoiceItemType {
/** 唯一标识,同时作为选中值 */
key: ChoiceValueType;
/** 选项标签 */
label: React.ReactNode;
/** 选项描述,提供补充信息 */
description?: React.ReactNode;
/** 选项图标 */
icon?: React.ReactNode;
/** 是否禁用 */
disabled?: boolean;
/** 禁用原因提示 */
disabledReason?: React.ReactNode;
/** AI 推荐标记 */
recommended?: boolean | 'primary' | 'secondary';
/** 推荐原因 */
recommendedReason?: React.ReactNode;
/** 选项额外信息(如价格、标签等) */
extra?: React.ReactNode;
/** 选项附加元数据,用于 LLM 结构化数据透传 */
meta?: Record<string, any>;
/** 嵌套子选项(用于分组场景) */
children?: ChoiceItemType[];
}
interface ChangeInfo {
/** 变更后的值 */
value: ChoiceValueType | ChoiceValueType[];
/** 当前所有选项 */
items: ChoiceItemType[];
/** 本次变更涉及的选项 */
changedItems: ChoiceItemType[];
/** 变更类型 */
type: 'select' | 'deselect';
}
ChoiceRef
interface ChoiceRef {
nativeElement: HTMLDivElement;
/** 滚动到指定选项 */
scrollTo: (key: ChoiceValueType) => void;
/** 获取当前选中值 */
getValue: () => ChoiceValueType | ChoiceValueType[] | undefined;
}
与 LLM 数据结构的映射
Choice 组件的设计天然适配主流 LLM 结构化输出格式:
OpenAI Function Calling 路径
{
"tool_call": {
"function": {
"name": "present_choice",
"arguments": {
"title": "请选择数据分析维度",
"mode": "single",
"layout": "card",
"items": [
{ "key": "time", "label": "按时间", "description": "按时间趋势分析", "icon": "clock", "recommended": true },
{ "key": "region", "label": "按地区", "description": "按地域分布分析", "icon": "global" },
{ "key": "category", "label": "按品类", "description": "按商品类别分析", "icon": "tag" }
]
}
}
}
}
Structured Output 路径
{
"type": "choice_interaction",
"data": {
"mode": "multiple",
"maxCount": 3,
"items": [
{ "key": "opt_1", "label": "性能优化", "description": "提升系统响应速度和吞吐量", "recommended": "primary", "meta": { "score": 0.92 } },
{ "key": "opt_2", "label": "安全加固", "description": "修复已知漏洞,增强安全策略" },
{ "key": "opt_3", "label": "功能迭代", "description": "按需求优先级推进新功能", "recommended": "secondary" },
{ "key": "opt_4", "label": "技术债清理", "description": "重构遗留代码,改善可维护性", "disabled": true, "disabledReason": "当前冲刺无排期" }
]
}
}
自定义 Agent Tool 路径
{
"action": "user_choice",
"payload": {
"title": "下一步您希望如何继续?",
"description": "诊断完成,以下是建议的后续步骤",
"mode": "single",
"layout": "list",
"indicator": "number",
"items": [
{ "key": "detail", "label": "查看详细报告", "icon": "file-text" },
{ "key": "fix", "label": "立即修复", "icon": "tool", "recommended": true, "recommendedReason": "检测到 3 个高危问题" },
{ "key": "schedule", "label": "加入排期", "icon": "calendar" },
{ "key": "ignore", "label": "暂时忽略", "icon": "eye-off" }
]
}
}
🎨 视觉设计
布局模式
list(列表布局)
┌─────────────────────────────────────────────┐
│ 🤔 请选择数据分析维度 │
│ 选择最符合您需求的维度,或让 AI 为您推荐 │
├─────────────────────────────────────────────┤
│ ○ 🕐 按时间 │
│ 按时间趋势分析 ⭐ 推荐 │
├─────────────────────────────────────────────┤
│ ○ 🌍 按地区 │
│ 按地域分布分析 │
├─────────────────────────────────────────────┤
│ ○ 🏷️ 按品类 │
│ 按商品类别分析 │
├─────────────────────────────────────────────┤
│ ○ 📊 按渠道 🔒 暂不可用 │
│ 按销售渠道分析 │
├─────────────────────────────────────────────┤
│ [ 确认选择 ] │
└─────────────────────────────────────────────┘
grid(网格布局)
┌─────────────────────────────────────────────┐
│ 🤔 选择您感兴趣的方向 │
├──────────────────┬──────────────────────────┤
│ 🕐 │ 🌍 │
│ 按时间 │ 按地区 │
│ 趋势分析 │ 地域分布 │
│ ⭐ 推荐 │ │
├──────────────────┼──────────────────────────┤
│ 🏷️ │ 📊 │
│ 按品类 │ 按渠道 │
│ 类别分析 │ 🔒 暂不可用 │
└──────────────────┴──────────────────────────┘
card(卡片布局)
┌─────────────────────────────────────────────┐
│ 🎯 推荐方案 │
├─────────────────────────────────────────────┤
│ ┌──────────────┐ ┌──────────────┐ │
│ │ ⭐ 强烈推荐 │ │ │ │
│ │ 性能优化 │ │ 安全加固 │ │
│ │ │ │ │ │
│ │ 提升系统响应 │ │ 修复已知漏洞 │ │
│ │ 速度和吞吐量 │ │ 增强安全策略 │ │
│ │ │ │ │ │
│ │ AI 评分: 92 │ │ │ │
│ └──────────────┘ └──────────────┘ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ │ │ 🔒 暂不可用 │ │
│ │ 功能迭代 │ │ 技术债清理 │ │
│ │ │ │ │ │
│ │ 按需求优先级 │ │ 当前冲刺无 │ │
│ │ 推进新功能 │ │ 排期 │ │
│ └──────────────┘ └──────────────┘ │
├─────────────────────────────────────────────┤
│ ☑ 已选 2 项(最多 3 项) [ 确认选择 ] │
└─────────────────────────────────────────────┘
与 antd 的视觉差异
| 特性 |
antd Select/Radio/Checkbox |
Choice |
| 信息密度 |
紧凑,label 为主 |
宽松,icon + label + description + extra |
| 推荐标记 |
❌ 无 |
✅ 支持 primary/secondary 推荐标签 |
| 禁用原因 |
❌ 只有灰色态 |
✅ 禁用时展示原因提示 |
| 布局灵活性 |
固定布局 |
list/grid/card 三种布局 |
| 上下文适配 |
表单内嵌 |
对话气泡内嵌,圆角/间距适配对话流 |
| 加载态 |
❌ 无 |
✅ 骨架屏/渐入动画 |
| 确认操作 |
即时触发 |
支持确认按钮,延迟触发(适配对话流) |
| 指示器 |
固定(圆点/勾) |
可选(check/radio/number/none) |
Design Token
interface ComponentToken {
// 颜色
itemBg?: string; // 选项背景色
itemHoverBg?: string; // 选项悬停背景色
itemActiveBg?: string; // 选项激活背景色
itemSelectedBg?: string; // 选项选中背景色
itemDisabledBg?: string; // 选项禁用背景色
itemBorderColor?: string; // 选项边框色
itemSelectedBorderColor?: string; // 选项选中边框色
itemRecommendedBorderColor?: string;// 推荐选项边框色
itemDisabledBorderColor?: string; // 禁用选项边框色
// 文字
titleFontSize?: number; // 标题字号
titleLineHeight?: number; // 标题行高
labelFontSize?: number; // 标签字号
labelLineHeight?: number; // 标签行高
descFontSize?: number; // 描述字号
descLineHeight?: number; // 描述行高
// 间距
headerPadding?: number; // 头部区域内边距
itemPadding?: number; // 选项内边距
itemGap?: number; // 选项间距
listPadding?: number; // 列表区域内边距
footerPadding?: number; // 底部区域内边距
// 圆角
borderRadius?: number; // 整体圆角
itemBorderRadius?: number; // 选项圆角
// 尺寸
gridColumns?: number; // 网格布局列数
// 动画
motionDuration?: number; // 动画时长
}
📁 文件结构
components/choice/
├── index.tsx # 主组件,ChoiceRefs,forwardRef
├── interface.ts # ChoiceProps, ChoiceItemType, ChoiceRef, SemanticType
├── Item.tsx # ChoiceItem 子组件,选项渲染
├── context.ts # ChoiceContext,传递 prefixCls/classNames/styles/mode/disabled
├── hooks/
│ └── use-select.ts # 选择逻辑 hook(受控/非受控、单选/多选、maxCount)
├── style/
│ ├── index.ts # genStyleHooks + prepareComponentToken + 主样式
│ ├── item.ts # 选项样式(各布局、状态变体)
│ ├── header.ts # 头部样式
│ ├── footer.ts # 底部样式
│ ├── variant.ts # 布局变体样式(list/grid/card)
│ └── indicator.ts # 指示器样式
├── demo/
│ ├── basic.tsx # 基础单选
│ ├── basic.md
│ ├── multiple.tsx # 多选模式
│ ├── multiple.md
│ ├── card-layout.tsx # 卡片布局
│ ├── card-layout.md
│ ├── grid-layout.tsx # 网格布局
│ ├── grid-layout.md
│ ├── recommended.tsx # 推荐标记
│ ├── recommended.md
│ ├── disabled.tsx # 禁用与禁用原因
│ ├── disabled.md
│ ├── confirmable.tsx # 带确认按钮
│ ├── confirmable.md
│ ├── indicator.tsx # 指示器类型
│ ├── indicator.md
│ ├── loading.tsx # 加载态
│ ├── loading.md
│ ├── in-bubble.tsx # 在对话气泡中使用
│ ├── in-bubble.md
│ ├── _semantic.tsx # 语义化 DOM 结构预览
│ └── controlled.tsx # 受控模式
│ controlled.md
├── __tests__/
│ ├── index.test.tsx # 组件基础测试
│ ├── select.test.tsx # 选择逻辑测试
│ ├── demo-extend.test.ts
│ └── __snapshots__/
├── index.zh-CN.md # 中文文档
└── index.en-US.md # 英文文档
🔧 实现要点
1. 选择逻辑 Hook(useSelect)
// hooks/use-select.ts
interface UseSelectOptions {
mode: 'single' | 'multiple';
value?: ChoiceValueType | ChoiceValueType[];
defaultValue?: ChoiceValueType | ChoiceValueType[];
onChange?: (value: ChoiceValueType | ChoiceValueType[], info: ChangeInfo) => void;
maxCount?: number;
disabled?: boolean;
}
function useSelect(options: UseSelectOptions): {
/** 当前值 */
mergedValue: ChoiceValueType[];
/** 处理选项点击 */
onItemClick: (item: ChoiceItemType, index: number) => void;
/** 是否选中 */
isSelected: (key: ChoiceValueType) => boolean;
/** 是否达到上限 */
isMaxReached: boolean;
}
核心要点:
mode: 'single' 时值为单元素数组,点击已选项取消选中
mode: 'multiple' 时值为数组,受 maxCount 约束
- 使用
useControlledState(@rc-component/util)处理受控/非受控
- 单选模式下选中即触发
onChange,多选模式需配合 confirmable 确认
2. 联动 Bubble.List
Choice 作为 AI 消息内容嵌入 Bubble.List,需要:
- 与
Bubble.List 的 role 配置协调样式
- 选中结果通过
onChange 回调更新到对话状态管理(如 useXChat)
- 宽度自适应气泡容器
3. 推荐标记渲染
recommended 字段的渲染规则:
true / 'primary':使用主题色边框 + 高亮背景 + 推荐角标("AI 推荐")
'secondary':使用次级色边框 + 轻背景 + 轻角标
- 不影响选中逻辑,仅视觉标记
4. 禁用态与原因提示
disabled: true 时选项不可点击,视觉置灰
disabledReason 存在时,hover/tip 展示原因(使用 antd Tooltip)
- 禁用原因也作为行内文本展示(与 antd 纯灰色态的差异化)
5. 指示器
| indicator |
single 模式 |
multiple 模式 |
'radio' |
圆形单选指示器 |
圆形指示器(行为同 checkbox) |
'check' |
勾选框 |
勾选框(默认) |
'number' |
序号 ①②③ |
序号 + 勾选 |
'none' |
无指示器,选中态仅靠背景色区分 |
同左 |
- 默认值:
mode: 'single' → 'radio',mode: 'multiple' → 'check'
6. 动画
fadeIn / fadeInLeft:复用现有 @rc-component/motion 的 CSSMotion,与 Prompts 组件一致
- 选中态过渡:
transition 处理边框色、背景色变化
loading 态:使用 antd Skeleton 或自定义骨架占位
7. 语义化结构(Semantic DOM)
root
├── header # 标题 + 描述区域
│ ├── title
│ └── description
├── list # 选项列表容器
│ └── item * N # 单个选项
│ ├── indicator # 选择指示器
│ └── itemContent
│ ├── icon
│ ├── label
│ ├── description
│ ├── extra
│ └── recommended-badge
└── footer # 底部操作区
8. 国际化
// locale/zh_CN.ts
const locale = {
confirmText: '确认',
recommended: '推荐',
maxSelected: '已选 {count}/{max} 项',
disabledHint: '暂不可用',
};
// locale/en_US.ts
const locale = {
confirmText: 'Confirm',
recommended: 'Recommended',
maxSelected: '{count}/{max} selected',
disabledHint: 'Unavailable',
};
9. 无障碍(a11y)
role="radiogroup"(single)/ role="group"(multiple)
- 选项
role="radio" / role="checkbox"
aria-checked、aria-disabled、aria-label
- 键盘导航:
↑ ↓ 切换焦点,Space/Enter 选中,Tab 离开
- 遵循 WAI-ARIA APG 的 Radio Group / Checkbox Group 模式
🔗 依赖关系
项目内依赖
// 内部引用
import { useXProviderContext } from '../x-provider';
import useXComponentConfig from '../_util/hooks/use-x-component-config';
import useProxyImperativeHandle from '../_util/hooks/use-proxy-imperative-handle';
import { useControlledState } from '@rc-component/util';
外部依赖
| 依赖 |
用途 |
antd |
Tooltip(禁用原因提示)、Button(确认按钮)、Skeleton(加载态) |
@ant-design/icons |
CheckCircle/Radio 图标(指示器) |
@ant-design/cssinjs |
CSS-in-JS 样式方案 |
@rc-component/motion |
动画 |
clsx |
类名合并 |
@rc-component/util |
工具函数 |
✅ 验收标准
功能验收
质量验收
文档验收
📅 实施计划
| 阶段 |
内容 |
工期 |
| P0 |
核心组件:interface、index、Item、context、useSelect、style |
3 天 |
| P1 |
布局变体:list/grid/card 三种布局样式 |
2 天 |
| P2 |
增强特性:recommended、disabledReason、indicator、loading、confirmable |
2 天 |
| P3 |
Demo + 文档:所有 demo、中英文文档 |
2 天 |
| P4 |
测试 + 修复:单元测试、a11y、RTL、集成测试 |
2 天 |
| 合计 |
|
约 11 天 |
📎 补充说明
与 A2UI 协议的协同
@ant-design/x-card 的 A2UI 协议可扩展 choice 卡片类型,Choice 组件可作为 A2UI 的 choice 类型渲染器:
{
"type": "card",
"cardType": "choice",
"props": {
"mode": "single",
"layout": "card",
"items": [...]
}
}
这样 LLM 输出的 A2UI JSON 可直接驱动 Choice 组件渲染,实现端到端的结构化交互闭环。
与 useXChat 的集成
const [agent] = useXChat({
provider,
parser: (message) => {
if (message.type === 'choice_interaction') {
return {
content: (
<Choice
mode={message.data.mode}
items={message.data.items}
onChange={(value) => {
agent.send({ type: 'user_choice', value });
}}
/>
),
};
}
return { content: message.content };
},
});
命名考量
| 候选名 |
优点 |
缺点 |
结论 |
Choice |
语义清晰、简短、动词感强、「选择」直译 |
与 React Router 的 Choice 不冲突但需注意 |
✅ 采用 |
Picker |
antd 已有 Picker(日期选择) |
命名冲突 |
❌ |
Selector |
语义明确 |
与 antd Select 太相似,易混淆 |
❌ |
OptionList |
描述性 |
名字太长,不符合组件库命名惯例 |
❌ |
Selection |
名词感,沉稳 |
语义偏"已选结果"而非"选择交互" |
❌ |
新组件提案:Choice 选择交互
📋 基本信息
Choice🎯 背景与动机
现状问题
在大模型对话场景中,模型经常需要向用户呈现一组选项让用户做出选择,例如:
当前 antd 的
Select、Radio、Checkbox是面向表单场景设计的静态控件,在 AI 对话上下文中存在以下不匹配:与现有组件的区别
PromptsSuggestionActionsChoice 填补的是「模型输出结构化选项 → 用户选择 → 结果回传对话流」这一核心交互链路的空白。
🧩 组件设计
名词定义
核心 API
ChoiceProps
ChoiceItemType
ChoiceRef
与 LLM 数据结构的映射
Choice 组件的设计天然适配主流 LLM 结构化输出格式:
OpenAI Function Calling 路径
{ "tool_call": { "function": { "name": "present_choice", "arguments": { "title": "请选择数据分析维度", "mode": "single", "layout": "card", "items": [ { "key": "time", "label": "按时间", "description": "按时间趋势分析", "icon": "clock", "recommended": true }, { "key": "region", "label": "按地区", "description": "按地域分布分析", "icon": "global" }, { "key": "category", "label": "按品类", "description": "按商品类别分析", "icon": "tag" } ] } } } }Structured Output 路径
{ "type": "choice_interaction", "data": { "mode": "multiple", "maxCount": 3, "items": [ { "key": "opt_1", "label": "性能优化", "description": "提升系统响应速度和吞吐量", "recommended": "primary", "meta": { "score": 0.92 } }, { "key": "opt_2", "label": "安全加固", "description": "修复已知漏洞,增强安全策略" }, { "key": "opt_3", "label": "功能迭代", "description": "按需求优先级推进新功能", "recommended": "secondary" }, { "key": "opt_4", "label": "技术债清理", "description": "重构遗留代码,改善可维护性", "disabled": true, "disabledReason": "当前冲刺无排期" } ] } }自定义 Agent Tool 路径
{ "action": "user_choice", "payload": { "title": "下一步您希望如何继续?", "description": "诊断完成,以下是建议的后续步骤", "mode": "single", "layout": "list", "indicator": "number", "items": [ { "key": "detail", "label": "查看详细报告", "icon": "file-text" }, { "key": "fix", "label": "立即修复", "icon": "tool", "recommended": true, "recommendedReason": "检测到 3 个高危问题" }, { "key": "schedule", "label": "加入排期", "icon": "calendar" }, { "key": "ignore", "label": "暂时忽略", "icon": "eye-off" } ] } }🎨 视觉设计
布局模式
list(列表布局)
grid(网格布局)
card(卡片布局)
与 antd 的视觉差异
Design Token
📁 文件结构
🔧 实现要点
1. 选择逻辑 Hook(
useSelect)核心要点:
mode: 'single'时值为单元素数组,点击已选项取消选中mode: 'multiple'时值为数组,受maxCount约束useControlledState(@rc-component/util)处理受控/非受控onChange,多选模式需配合confirmable确认2. 联动 Bubble.List
Choice 作为 AI 消息内容嵌入
Bubble.List,需要:Bubble.List的role配置协调样式onChange回调更新到对话状态管理(如useXChat)3. 推荐标记渲染
recommended字段的渲染规则:true/'primary':使用主题色边框 + 高亮背景 + 推荐角标("AI 推荐")'secondary':使用次级色边框 + 轻背景 + 轻角标4. 禁用态与原因提示
disabled: true时选项不可点击,视觉置灰disabledReason存在时,hover/tip 展示原因(使用 antdTooltip)5. 指示器
'radio''check''number''none'mode: 'single'→'radio',mode: 'multiple'→'check'6. 动画
fadeIn/fadeInLeft:复用现有@rc-component/motion的CSSMotion,与 Prompts 组件一致transition处理边框色、背景色变化loading态:使用 antdSkeleton或自定义骨架占位7. 语义化结构(Semantic DOM)
8. 国际化
9. 无障碍(a11y)
role="radiogroup"(single)/role="group"(multiple)role="radio"/role="checkbox"aria-checked、aria-disabled、aria-label↑↓切换焦点,Space/Enter选中,Tab离开🔗 依赖关系
项目内依赖
外部依赖
antd@ant-design/icons@ant-design/cssinjs@rc-component/motionclsx@rc-component/util✅ 验收标准
功能验收
mode: 'single'单选:点击选中,再点取消mode: 'multiple'多选:点击切换选中,maxCount限制layout: 'list' | 'grid' | 'card'三种布局正确渲染indicator: 'check' | 'radio' | 'number' | 'none'四种指示器value+onChange)与非受控模式(defaultValue)recommended标记渲染(true/'primary'/'secondary')disabled+disabledReason禁用态与原因提示loading骨架屏态confirmable+confirmText确认按钮fadeIn/fadeInLeft动画children分组渲染title/description/footer区域渲染classNames/styles支持质量验收
any漏洞Bubble.List集成 Demo 验证文档验收
index.zh-CN.md/index.en-US.md)📅 实施计划
📎 补充说明
与 A2UI 协议的协同
@ant-design/x-card的 A2UI 协议可扩展choice卡片类型,Choice 组件可作为 A2UI 的 choice 类型渲染器:{ "type": "card", "cardType": "choice", "props": { "mode": "single", "layout": "card", "items": [...] } }这样 LLM 输出的 A2UI JSON 可直接驱动 Choice 组件渲染,实现端到端的结构化交互闭环。
与 useXChat 的集成
命名考量
ChoiceChoice不冲突但需注意PickerSelectorOptionListSelection