Command
command命令面板 · ⌘K 模态(复用 Dialog 引擎) + 实时过滤 + 分组 + 键盘漫游(零依赖)
用法
基础用法
Command 为受控模态:用 useState 持有 open,按钮触发打开。groups 提供分组命令,输入框实时跨组过滤(试输「订单」「dd」「主题」)。
tsx
const [open, setOpen] = useState(false);
const groups = [
{
heading: "快速跳转",
items: [
{ value: "go-dashboard", label: "仪表盘", description: "总览今日数据",
keywords: "dashboard 首页", icon: <LayoutDashboard /> },
{ value: "go-orders", label: "订单管理", keywords: "order 订单 dd",
icon: <ShoppingCart /> },
],
},
{
heading: "操作",
items: [
{ value: "new-order", label: "新建订单", icon: <Plus />, shortcut: "⌘N" },
{ value: "import", label: "导入数据", description: "上传 CSV / Excel",
icon: <Upload /> },
],
},
];
<Button variant="outline" onClick={() => setOpen(true)}>打开命令面板</Button>
<Command open={open} onOpenChange={setOpen} groups={groups} />内置 ⌘K 快捷键
shortcut 开启后,组件内置 ⌘K / Ctrl+K 全局监听切换开合,无需自行绑定。
tsx
<Button variant="outline" onClick={() => setOpen(true)}>
打开命令面板(或 ⌘K)
</Button>
<Command open={open} onOpenChange={setOpen} groups={groups} shortcut />选中后保持打开
closeOnSelect={false} 时执行命令后面板不关闭,适合连续多次操作的场景。
tsx
<Command
open={open}
onOpenChange={setOpen}
groups={groups}
closeOnSelect={false}
/>何时用
⌘K 召唤的命令面板:跨页跳转、操作触发、主题切换汇于一处,带实时过滤、分组与键盘漫游。需要常驻可见的一排按钮用 Toolbar;需要右键弹出的上下文动作用 ContextMenu;Command 是搜索式、模态、数据驱动的全局命令入口。
导入
ts
import { Command, useCommandShortcut } from "@hulianui/ui"Props
| 名称 | 类型 | 默认 | 说明 |
|---|---|---|---|
| open* | boolean | — | 受控开合。 |
| groups* | CommandGroupData[] | — | 命令分组(每组可带 heading)。 |
| placeholder | string | — | 搜索框占位符。 |
| filter | (item: CommandItemData, query: string) => boolean | 默认子串匹配 | 自定义过滤,返回 true 保留。默认大小写不敏感匹配 keywords + 字符串型 label + value。 |
| closeOnSelect | boolean | true | 执行项后是否自动关闭面板。 |
| shortcut | boolean | false | 内置 ⌘K / Ctrl+K 全局快捷键切换开合。 |
| className | string | — | — |
| aria-label | string | — | — |
Events
| 事件 | 类型 | 说明 |
|---|---|---|
| onOpenChange* | (open: boolean) => void | 开合变化回调。 |
| onSelectItem | (value: string) => void | 任意项执行后回调(在 item.onSelect 之后触发,拿到 value)。 |
Slots
| 插槽 | 类型 | 说明 |
|---|---|---|
| emptyMessage | ReactNode | 无匹配项时的空态文案。 |
CommandGroupData:heading?: ReactNode / items: CommandItemData[]。
CommandItemData
| 字段 | 类型 | 说明 |
|---|---|---|
| value* | string | 唯一值(回调入参 + key + 过滤兜底文本)。 |
| label* | ReactNode | 显示标题。 |
| keywords | string | 参与过滤的关键词(label 非字符串时建议补)。 |
| description | ReactNode | label 下方 muted 小字。 |
| icon | ReactNode | 行首图标插槽。 |
| shortcut | ReactNode | 行尾快捷键/标记插槽。 |
| disabled | boolean | — |
| onSelect | (value: string) => void | 该项被执行(Enter / 点击)时回调。 |
禁忌 / 坑
- 始终受控:必须同时提供
open+onOpenChange。 label不是字符串时默认过滤匹配不到它,需为该项补keywords(否则只能靠value命中)。- 内置快捷键用
shortcut一键开启;若想在面板外自绑触发逻辑,改用useCommandShortcut,别同时开shortcut。
相关
ContextMenu · Toolbar · Accordion · Collapsible · Link · AnimatedThemeToggler
Playground
const [open, setOpen] = useState(false);
<Button onClick={() => setOpen(true)}>打开命令面板</Button>
<Command
open={open}
onOpenChange={setOpen}
placeholder="输入命令或搜索…"
shortcut={false}
groups={[
{ heading: "常用", items: [{ value: "new", label: "新建文件", onSelect: (v) => {} }] },
]}
/>