Command(命令面板)把搜索框放在一组动作之上,输入时列表保持展开并实时过滤。可以独立使用,也可以放进对话框做成 Cmd+K 式的全局命令面板。它执行的是动作而非选值;要选一个值并提交表单,用组合框。
组合
Command
├── CommandInput
├── CommandEmpty
└── CommandList
├── CommandItem
└── CommandItem给输入框一个无障碍名称,给每条命令唯一的 value;空态与状态消息放在列表外。onAction 上报运行的命令的 value。相关命令用 CommandGroup 与 CommandGroupLabel 分组,组间放 CommandSeparator;过滤后为空的组与分隔线自动隐藏。
用法
import {
Command,
CommandEmpty,
CommandInput,
CommandItem,
CommandList,
} from "@ui-sdk/react/command";
function Example() {
return (
<Command onAction={(value) => run(value)}>
<CommandInput aria-label="搜索命令" placeholder="输入命令…" />
<CommandEmpty>没有匹配的命令。</CommandEmpty>
<CommandList>
<CommandItem value="new-file">新建文件</CommandItem>
<CommandItem value="new-folder">新建文件夹</CommandItem>
</CommandList>
</Command>
);
}做成命令面板
把 Command 放进 Dialog:给对话框一个标题,触发器设 shortcut="mod+k",命令运行后关闭对话框。dismiss 与焦点归还由对话框负责。
const [open, setOpen] = React.useState(false);
<Dialog open={open} onOpenChange={setOpen}>
<DialogTrigger shortcut="mod+k">
搜索…
<DialogShortcut />
</DialogTrigger>
<DialogContent>
<DialogTitle>命令面板</DialogTitle>
<Command onAction={(value) => { run(value); setOpen(false); }}>
<CommandInput aria-label="搜索命令" />
<CommandEmpty>没有匹配的命令。</CommandEmpty>
<CommandList>{/* 命令与分组 */}</CommandList>
</Command>
</DialogContent>
</Dialog>;命令自身的 shortcut(如 "mod+p")在列表挂载期间随时可运行,即使被搜索过滤隐藏;CommandShortcut 显示当前平台的按键。
过滤与关键词
filter 默认 "fuzzy"(nf 能匹配「New file」),还可用 "contains"、"startsWith"、返回分数或布尔的自定义函数(0 隐藏,分数越高越靠前),或 false 保留服务端已过滤的结果。keywords 添加同义词而不改变标签;CommandItemText 会标记命中的文字片段。
<CommandItem value="delete" keywords={["remove", "trash"]}>
<CommandItemText>删除</CommandItemText>
</CommandItem>把命令作为 items 数据传入时按分数排序,并支持 { type: "group" }、{ type: "separator" } 与自带 items 的子页面;emptyItems 在首页搜索为空时显示最近或建议命令。超长列表可只渲染可见行,给每行传 index,过滤与键盘导航仍覆盖全部数据。
分页
给命令设 page 指向某个 CommandPage 的 value,选中即进入该页;不带 value 的 CommandPage 是首页。pages 数组记录页面栈,可受控。空搜索框里按 Backspace 返回上一页并恢复其搜索词;Escape 先清空搜索再返回。控制器的 push() / pop() 可编程导航。
<CommandList>
<CommandPage>
<CommandItem value="theme" page="theme">更改主题…</CommandItem>
</CommandPage>
<CommandPage value="theme">
<CommandItem value="light">浅色</CommandItem>
<CommandItem value="dark">深色</CommandItem>
</CommandPage>
</CommandList>异步与待决动作
服务端搜索用 useAsyncOptions(@ui-sdk/react/async-options):onQueryChange 里调 setQuery(),渲染返回的 items,传 status 并设 filter={false}。CommandStatus 描述加载与失败,加载中列表带 aria-busy;onLoadMore 在滚动或高亮到达末尾时请求下一页。
onAction 或命令的 onSelect 返回 Promise 时,命令进入待决态:带 data-pending、aria-busy、aria-disabled,重复按下不会再次运行;reject 会写入命令的 error 状态,下次运行时清除。onSelect 先于 onAction,对其事件 preventDefault() 可跳过动作。
样式与状态
各部件的 data-slot 为 command、command-input、command-list、command-item、command-empty、command-status 等:
- 命令:
data-highlighted(当前高亮,Enter 运行它)、data-disabled、data-pending、data-has-icon。 - 列表:内部有图标部件时带
data-has-icons,便于给无图标的命令留出对齐空间。 - 根与空态、状态:
status="loading"时带data-loading;空态无匹配时带data-empty。 - 文本:
CommandItemText命中搜索时带data-matched。
Command 不是弹出层,没有锚点变量;给列表限高并滚动即可,键盘导航会把高亮命令滚入视野:
[data-slot="command-list"] {
max-height: 320px;
overflow-y: auto;
}
[data-slot="command-item"][data-highlighted] {
background: var(--color-accent);
}
[data-slot="command-item"][data-disabled] {
opacity: 0.5;
}API
| Prop | 类型 | 说明 |
|---|---|---|
value / defaultValue |
string | null |
高亮命令的值,null 表示不高亮。 |
onValueChange |
(value, details) => void |
高亮变化;details.index 供虚拟列表滚动。 |
query / onQueryChange |
string / (query, details) => void |
搜索文本及其变更。 |
pages / onPagesChange |
string[] / (pages, details) => void |
页面栈及其变更。 |
onAction |
(value, details) => unknown |
命令运行时回调;返回 Promise 进入待决态。 |
items / emptyItems |
CommandData |
数据驱动的命令;搜索为空时显示 emptyItems。 |
filter |
SearchFilter<string> |
"fuzzy"、"contains"、"startsWith"、函数或 false。 |
autoHighlight |
boolean |
是否自动高亮首条 / 最佳匹配,默认开。 |
loop |
boolean |
方向键是否首尾循环。 |
status / onLoadMore |
AsyncOptionsStatus / () => void |
异步加载状态与加载下一页。 |
controller |
object |
用 createCommandController() 创建,run()、push()、pop()、focus() 等。 |
CommandItem 另有 label(搜索匹配的文本)、keywords、disabled、shortcut、page、index、onSelect。
键盘与无障碍
遵循 WAI-ARIA combobox 模式:输入框是 combobox,列表是始终展开的 listbox,焦点留在输入框,用 aria-activedescendant 指向高亮命令。
| 按键 | 行为 |
|---|---|
| 输入 | 过滤命令并高亮最佳匹配 |
ArrowDown / ArrowUp |
移动高亮,默认首尾循环(loop={false} 关闭) |
Enter |
运行高亮命令 |
Escape |
先清空搜索,再返回上一页 |
Backspace |
搜索为空时返回上一页并恢复其搜索词 |
| 命令的快捷键 | 列表挂载期间随时运行,即使被过滤隐藏 |
Home / End 留给输入框移动光标。默认高亮第一条可用命令,autoHighlight={false} 则等到方向键或指针移动。