Selection 搜索与选择
处理查询、即时开关和筛选条件,而不携带产品状态。
这个家族包含 SearchField、SwitchField、FilterChip 与 ChoiceContent。它们解决高频筛选和偏好编辑,原生复选框与单选行则使用 Field 家族的 ChoiceRow。
安装
pnpm dlx shadcn@4.22.1 add http://127.0.0.1:3040/r/v0.3.0/selection.json首次使用请先完成 Registry 与主题接入。
状态与组合
SearchField 区分即时输入 onValueChange 与去空格、防抖、去重后的 onSearch,输入法组合期间不提前搜索。SwitchField 表示即时生效的布尔值;FilterChip 将编辑和移除作为独立操作,支持只读与不可移除原因。
Props
| API / 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
SearchField.value / onValueChange | string / 回调 | 必填 | 受控查询 |
SearchField.label | string | 必填 | 输入框名称 |
SearchField.onSearch | (value: string) => void | — | 规范化查询提交 |
SearchField.debounceMs | number | 300 | 防抖毫秒 |
SearchField.clearLabel | string | 清除搜索 | 清空按钮名称 |
SwitchField.checked / onCheckedChange | boolean / 回调 | 必填 | 开关状态 |
SwitchField.label / description | ReactNode | 必填 / — | 解释当前偏好 |
FilterChip.label / value | string / ReactNode | 必填 | 条件名和值 |
FilterChip.onEdit / onRemove | () => void | — | 独立编辑与移除 |
FilterChip.readOnly | boolean | false | 隐藏编辑与移除操作 |
FilterChip.removeDisabledReason | string | — | 保留可理解的不可移除原因 |
ChoiceContent.title | ReactNode | 必填 | 选项主要内容 |
ChoiceContent 另支持 icon、description、status。FilterChip 的 editLabel、removeLabel 默认为“编辑某条件筛选”和“移除某条件筛选”,可传入更具体的名称;expanded、popup 描述外部浮层状态。
键盘与约束
SearchField 的 Enter 立即搜索,Escape 在有内容时清空;中文输入法确认不误触提交。SwitchField 使用原生 checkbox 与 switch 角色,Space 切换。FilterChip 的编辑与移除分别进入 Tab 顺序。
避免这样使用
不要同时在每次输入和防抖回调中发起同一次请求;不要用即时开关承载稍后统一保存的多选任务而不解释保存方式;不要将删除按钮嵌套在编辑按钮中。
来源与版本
0.1.0,呈现语言来自 Subtic apps/web/components/collection-filters.tsx、collection-search-control.tsx 与 ui/field.tsx。查询请求、过滤规则与持久化全部由调用方拥有。
查看由当前源码生成的类型参考
只展示 Kitseed 自身定义的属性,原生 HTML 与 Base UI 透传属性请参阅对应上游说明。
SearchField
| 属性 | 类型 | 默认值 |
|---|---|---|
value | string | — |
onValueChange | (value: string) => void | — |
onSearch? | (value: string) => void | — |
label | string | — |
clearLabel? | string | "清除搜索" |
debounceMs? | number | 300 |
containerClassName? | string | — |
unstyled? | boolean | false |
onClear? | () => void | — |
slotProps? | {
icon?: ComponentProps<typeof MagnifyingGlass>;
clearButton?: ComponentProps<"button">;
clearIcon?: ComponentProps<typeof X>;
} | {} |
SwitchField
| 属性 | 类型 | 默认值 |
|---|---|---|
checked | boolean | — |
onCheckedChange | (checked: boolean) => void | — |
label | ReactNode | — |
description? | ReactNode | — |
containerClassName? | string | — |
FilterChip
| 属性 | 类型 | 默认值 |
|---|---|---|
label | string | — |
value | ReactNode | — |
icon? | ReactNode | — |
valueIcon? | ReactNode | — |
operator? | ReactNode | — |
onEdit? | () => void | — |
onRemove? | () => void | — |
editLabel? | string | `编辑${label}筛选` |
removeLabel? | string | `移除${label}筛选` |
removeDisabledReason? | string | — |
expanded? | boolean | — |
popup? | "menu" | "dialog" | — |
readOnly? | boolean | false |
className? | string | — |
unstyled? | boolean | false |
removableWhenReadOnly? | boolean | false |
editable? | boolean | Boolean(onEdit) |
showOperator? | boolean | Boolean(operator) |
renderEdit? | (element: ReactElement) => ReactNode | (element) => element |
renderRemove? | (element: ReactElement) => ReactNode | (element) => element |
slotProps? | {
root?: SpanSlot;
label?: SpanSlot;
operator?: SpanSlot;
value?: SpanSlot;
valueText?: SpanSlot;
staticContent?: SpanSlot;
edit?: ComponentProps<"button">;
remove?: ComponentProps<"button">;
removeIcon?: ComponentProps<typeof X>;
lockedIcon?: ComponentProps<typeof LockSimple>;
disabledDescription?: SpanSlot;
} | {} |
ChoiceContent
| 属性 | 类型 | 默认值 |
|---|---|---|
icon? | ReactNode | — |
showIcon? | boolean | Boolean(icon) |
title | ReactNode | — |
description? | ReactNode | — |
status? | ReactNode | — |
unstyled? | boolean | false |
renderTitle? | (element: ReactElement) => ReactNode | (element) => element |
slotProps? | {
root?: SpanSlot;
icon?: SpanSlot;
content?: SpanSlot;
title?: SpanSlot;
description?: SpanSlot;
status?: SpanSlot;
} | {} |