npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

knight-ui

v1.1.3

Published

基于React的Knight-ui前端UI组件库

Readme

Knight-UI

基于 React 18+ 的企业级前端 UI 组件库,提供 80+ 高质量组件。

目录

安装

npm install knight-ui

快速开始

import React from "react";
import { createRoot } from "react-dom/client";
import { Button, ConfigProvider } from "knight-ui";

const App = () => (
  <ConfigProvider componentSize="default">
    <Button type="primary" onClick={() => alert("Hello Knight-UI")}>
      点击按钮
    </Button>
  </ConfigProvider>
);

createRoot(document.getElementById("root")!).render(<App />);

同时引入样式 Token(CSS 变量):

import "knight-ui/tokens.css";

主题定制

Knight-UI 通过 CSS 自定义属性(CSS Variables)实现主题系统。在 <html> 上设置 data-ku-theme 属性切换暗亮模式:

<html data-ku-theme="dark"><!-- 暗色模式 --></html>
<html data-ku-theme="light"><!-- 亮色模式 --></html>

常用 Token 变量:

| 变量名 | 说明 | |---|---| | --ku-color-primary | 主色 | | --ku-color-text-0 | 主要文本色 | | --ku-color-text-1 | 次要文本色 | | --ku-color-bg-0 | 主背景色 | | --ku-color-bg-1 | 次背景色 | | --ku-color-bg-2 | 三级背景色 | | --ku-color-border | 边框色 | | --ku-font-family | 全局字体 |

通用 Props(UIProps)

所有组件继承以下通用属性:

| 属性 | 类型 | 说明 | |---|---|---| | style | React.CSSProperties | 内联样式 | | className | string | 自定义类名 | | disabled | boolean | 是否禁用 | | visible | boolean | 是否可见 | | id | string | DOM id | | theme | string | 主题变体 | | cssVars | Record<string, string> | CSS 变量覆盖 |


Basic 基础

Button 按钮

import { Button } from "knight-ui";

// 基础用法
<Button type="primary" onClick={() => console.log("clicked")}>主要按钮</Button>
<Button type="secondary">次要按钮</Button>
<Button type="danger">危险按钮</Button>

// 带图标 + 加载
<Button type="primary" icon={<IconSearch />} loading>搜索中</Button>

// 按钮组
<Button.Group>
  <Button type="secondary" theme="light">左</Button>
  <Button type="primary" theme="light">中</Button>
  <Button type="secondary" theme="light">右</Button>
</Button.Group>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | type | "primary" \| "secondary" \| "tertiary" \| "warning" \| "danger" | "primary" | 按钮类型 | | theme | "solid" \| "borderless" \| "light" | "solid" | 按钮主题 | | size | "small" \| "default" \| "large" | "default" | 按钮尺寸 | | shape | "circle" \| "round" | — | 按钮形状 | | icon | React.ReactNode | — | 图标 | | iconPosition | "left" \| "right" | "left" | 图标位置 | | loading | boolean | false | 加载中 | | block | boolean | false | 通栏 100% 宽度 | | htmlType | "button" \| "submit" \| "reset" | "button" | 原生 type | | onClick | (e: MouseEvent) => void | — | 点击回调 |

FloatButton 悬浮按钮

import { FloatButton } from "knight-ui";

<FloatButton icon={<IconPlus />} size={40} onClick={() => console.log("clicked")} />

// 按钮组
<FloatButton.Group icon={<IconPlus />} size={40} direction="vertical">
  <IconEdit />
  <IconStar />
  <IconSetting />
</FloatButton.Group>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | icon | React.ReactNode | — | 图标 | | size | number | — | 尺寸(px) | | position | { right?, bottom?, left?, top? } | — | 定位偏移 | | onClick | (e: MouseEvent) => void | — | 点击回调 |

FloatButton.Group 额外支持 direction: "vertical" | "horizontal"

Icon 图标

import { Icon, IconStar, IconDelete, IconRefresh } from "knight-ui";

// 通用 Icon 组件
<Icon type="IconStar" size="large" color="#f59e0b" />

// 独立组件(推荐,支持 tree-shaking)
<IconStar size="large" color="#f59e0b" />
<IconDelete size="large" color="#ef4444" onClick={() => console.log("delete")} />
<IconRefresh spin size="large" />
<IconArrowRight rotate={90} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | type | IconType | — | 图标类型(200+) | | size | "extraSmall" \| "small" \| "default" \| "large" \| "extraLarge" | "default" | 尺寸 | | color | string | — | 颜色 | | spin | boolean | false | 旋转动画 | | rotate | number | — | 固定旋转角度 | | onClick | (e: MouseEvent) => void | — | 点击回调 |

Typography 排版

import { Title, Text, Paragraph } from "knight-ui";

<Title heading={1}>H1 标题</Title>
<Text type="secondary" strong>加粗次要文本</Text>
<Text mark>高亮文本</Text>
<Text code>const x = 1;</Text>
<Text delete>已删除文本</Text>
<Text ellipsis>超长文本溢出省略...</Text>

<Paragraph spacing="extended">
  段落内容,spacing 控制段落间距。
</Paragraph>

Titleheading: 1-6ellipsis

Texttype"primary" | "secondary" | "tertiary" | "quaternary" | "warning" | "danger" | "success")、strongunderlinedeletemarkcodeellipsis

Paragraphspacing: "normal" | "extended"ellipsis

Divider 分割线

import { Divider } from "knight-ui";

// 水平
<Divider />
<Divider align="left">左侧文字</Divider>
<Divider dashed />
<Divider color="#a78bfa" margin={24}>紫色分割线</Divider>

// 垂直
<div style={{ display: "flex", alignItems: "center", height: 60 }}>
  <Text>左</Text>
  <Divider layout="vertical" />
  <Text>右</Text>
</div>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | layout | "horizontal" \| "vertical" | "horizontal" | 方向 | | dashed | boolean | false | 虚线 | | align | "left" \| "center" \| "right" | "center" | 文字对齐 | | margin | string \| number | — | 间距 | | color | string | — | 颜色 |

Space 间距

import { Space, Button } from "knight-ui";

// 水平排列
<Space spacing="medium">
  <Button>A</Button>
  <Button>B</Button>
  <Button>C</Button>
</Space>

// 垂直 + 自动换行
<Space vertical spacing={16} wrap align="start">
  <Button>第一行</Button>
  <Button>第二行</Button>
</Space>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | spacing | "tight" \| "medium" \| "loose" \| "extraLoose" \| number | "medium" | 间距 | | align | "start" \| "center" \| "end" \| "baseline" | "center" | 对齐方式 | | vertical | boolean | false | 垂直排列 | | wrap | boolean | false | 自动换行 |

Layout 布局

import { Layout, Text } from "knight-ui";

<Layout style={{ height: 400 }}>
  <Layout.Header style={{ padding: 16, background: "#1e1e2e" }}>
    <Text strong>Header</Text>
  </Layout.Header>
  <div style={{ display: "flex", flex: 1 }}>
    <Layout.Sider width={200} style={{ background: "#16162a", padding: 16 }}>
      <Text>Sider</Text>
    </Layout.Sider>
    <Layout.Content style={{ padding: 16 }}>
      <Text>Content</Text>
    </Layout.Content>
  </div>
  <Layout.Footer style={{ padding: 8, background: "#1e1e2e", textAlign: "center" }}>
    <Text>Footer</Text>
  </Layout.Footer>
</Layout>

子组件:Layout.HeaderLayout.SiderLayout.ContentLayout.Footer

Layout.SiderwidthcollapsedWidthdefaultCollapsedtrigger

Grid 栅格

import { Row, Col } from "knight-ui";

<Row gutter={16} justify="center">
  <Col span={8}><div>col-8</div></Col>
  <Col span={8}><div>col-8</div></Col>
  <Col span={8}><div>col-8</div></Col>
</Row>

<Row gutter={[16, 24]}>
  <Col span={12} offset={6}><div>col-12 offset-6</div></Col>
</Row>

Rowgutterjustify"start" | "end" | "center" | "space-around" | "space-between")、align"top" | "middle" | "bottom"

Colspan(24 等分)、offsetxs/sm/md/lg/xl/xxl

Resizable 可调整尺寸

import { Resizable } from "knight-ui";

<Resizable
  defaultWidth={400}
  defaultHeight={300}
  minWidth={200}
  minHeight={150}
  maxWidth={800}
  maxHeight={600}
  onResize={(w, h) => console.log(w, h)}
>
  <div>拖拽边缘或角落调整尺寸</div>
</Resizable>

// 仅右侧可拖拽
<Resizable defaultWidth={300} resizeEdge={["right"]} minWidth={150}>
  <div>拖拽右边缘</div>
</Resizable>

// 等比缩放
<Resizable defaultWidth={400} defaultHeight={300} lockAspectRatio>
  <div>锁定宽高比</div>
</Resizable>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | defaultWidth / defaultHeight | number | — | 默认尺寸 | | minWidth / minHeight | number | — | 最小尺寸 | | maxWidth / maxHeight | number | — | 最大尺寸 | | resizeEdge | ResizeEdge[] | 全部 | 可拖拽边缘 | | lockAspectRatio | boolean | false | 锁定宽高比 | | onResize | (w, h) => void | — | 尺寸变化回调 |


Input 输入

Input 输入框

import { Input } from "knight-ui";

// 非受控(浏览器原生管理输入,IME 无干扰)
<Input placeholder="请输入" onChange={(v) => console.log(v)} />
<Input showClear defaultValue="可清除" />

// 受控(通过 value 管理显示值,Form.Field 自动使用此模式)
<Input value={text} onChange={(v) => setText(v)} placeholder="受控输入" />

<Input prefix={<IconSearch />} placeholder="搜索" />
<Input addonBefore="https://" addonAfter=".com" placeholder="域名" />
<Input type="password" placeholder="密码" />
<Input size="large" placeholder="大尺寸" />

// 多行文本(同样支持 value / defaultValue)
<Input.TextArea rows={4} placeholder="多行文本" onChange={(v) => console.log(v)} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | value | string | — | 受控值(提供后组件变为受控模式) | | defaultValue | string | — | 非受控默认值 | | type | "text" \| "password" | "text" | 输入类型 | | placeholder | string | — | 占位符 | | size | "small" \| "default" \| "large" | "default" | 尺寸 | | prefix / suffix | React.ReactNode | — | 前/后缀图标 | | addonBefore / addonAfter | React.ReactNode | — | 前/后置标签 | | showClear | boolean | false | 清除按钮 | | validateStatus | "warning" \| "error" \| "success" | — | 校验状态 | | onChange | (value: string) => void | — | 变更回调 |

InputNumber 数字输入

import { InputNumber } from "knight-ui";

<InputNumber defaultValue={50} min={0} max={100} onChange={(v) => console.log(v)} />
<InputNumber defaultValue={10} step={0.1} min={0} max={1} />
<InputNumber prefix="¥" defaultValue={99} />
<InputNumber suffix="px" defaultValue={16} />
<InputNumber defaultValue={50} innerButtons />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | min / max | number | — | 最小/最大值 | | step | number | 1 | 步长 | | innerButtons | boolean | false | 内部步进按钮 | | hideButtons | boolean | false | 隐藏步进按钮 | | onChange | (value: number) => void | — | 变更回调 |

Select 选择器

import { Select } from "knight-ui";

const options = [
  { label: "选项一", value: "1" },
  { label: "选项二", value: "2" },
  { label: "选项三", value: "3" },
];

<Select optionList={options} defaultValue="1" onChange={(v) => console.log(v)} />
<Select optionList={options} multiple defaultValue={["1", "2"]} max={3} />
<Select optionList={options} filter placeholder="搜索选择" />
<Select optionList={options} loading />

// 设置下拉可见选项数量(按每项约 30px 推算下拉高度,超出滚动)
<Select optionList={options} dropdownVisibleCount={6} />

子组件:Select.OptionSelect.OptGroup

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | optionList | SelectOption[] | — | 选项列表 | | multiple | boolean | false | 多选 | | filter | boolean | false | 可搜索 | | max | number | — | 多选最大数量 | | maxTagCount | number | — | 最多显示标签数 | | dropdownVisibleCount | number | — | 下拉可见选项数量(按每项约 30px 推算高度,默认 200px) | | onChange | (value) => void | — | 变更回调 |

Cascader 级联选择

import { Cascader } from "knight-ui";

const treeData = [
  {
    label: "浙江", value: "zj",
    children: [
      { label: "杭州", value: "hz" },
      { label: "宁波", value: "nb" },
    ],
  },
  { label: "江苏", value: "js", children: [{ label: "南京", value: "nj" }] },
];

<Cascader treeData={treeData} onChange={(v) => console.log(v)} />
<Cascader treeData={treeData} multiple filter placeholder="搜索" />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | treeData | CascaderOption[] | — | 级联数据 | | multiple | boolean | false | 多选 | | filter | boolean | false | 可搜索 | | changeOnSelect | boolean | false | 任意选中即改变 | | onChange | (value: string[]) => void | — | 变更回调 |

DatePicker 日期选择

import { DatePicker } from "knight-ui";

<DatePicker onChange={(date, dateStr) => console.log(date, dateStr)} />
<DatePicker type="dateRange" defaultValue={[new Date(), new Date()]} />
<DatePicker type="dateTime" showClear />
<DatePicker format="yyyy-MM-dd" presets={[{ label: "今天", value: new Date() }]} />
<DatePicker disabledDate={(d) => d.getTime() < Date.now()} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | type | "date" \| "dateRange" \| "dateTime" \| "dateTimeRange" \| "month" | "date" | 类型 | | format | string | — | 显示格式 | | presets | DatePickerPreset[] | — | 预设快捷选项 | | disabledDate | (date: Date) => boolean | — | 禁用日期 | | onChange | (date, dateString) => void | — | 变更回调 |

TimePicker 时间选择

import { TimePicker } from "knight-ui";

<TimePicker onChange={(v) => console.log(v)} />
<TimePicker format="HH:mm:ss" defaultValue="14:30:00" />
<TimePicker hourStep={2} minuteStep={15} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | value / defaultValue | string | — | 值(HH:mm 或 HH:mm:ss) | | format | "HH:mm" \| "HH:mm:ss" | "HH:mm" | 格式 | | hourStep / minuteStep / secondStep | number | 1 | 步长 | | onChange | (value: string) => void | — | 变更回调 |

Checkbox 复选框

import { Checkbox } from "knight-ui";

// 单个
<Checkbox defaultChecked onChange={(checked) => console.log(checked)}>同意协议</Checkbox>
<Checkbox indeterminate>半选状态</Checkbox>

// 组合
<Checkbox.Group defaultValue={["a", "c"]} onChange={(v) => console.log(v)}>
  <Checkbox value="a">选项 A</Checkbox>
  <Checkbox value="b">选项 B</Checkbox>
  <Checkbox value="c">选项 C</Checkbox>
</Checkbox.Group>

// 垂直排列
<Checkbox.Group direction="vertical" disabled>
  <Checkbox value="1">禁用的选项</Checkbox>
</Checkbox.Group>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | checked / defaultChecked | boolean | — | 选中状态 | | indeterminate | boolean | false | 半选状态 | | onChange | (checked: boolean) => void | — | 变更回调 |

Checkbox.Groupvalue/defaultValuedirectiondisabledonChange

Radio 单选框

import { Radio } from "knight-ui";

<Radio.Group defaultValue="b" onChange={(v) => console.log(v)}>
  <Radio value="a">选项 A</Radio>
  <Radio value="b">选项 B</Radio>
  <Radio value="c">选项 C</Radio>
</Radio.Group>

// 按钮样式
<Radio.Group type="button" defaultValue="a">
  <Radio value="a">A</Radio>
  <Radio value="b">B</Radio>
</Radio.Group>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | checked | boolean | — | 选中状态 | | type | "default" \| "button" \| "card" | "default" | 样式类型 |

Radio.Groupvalue/defaultValuedirectiontypedisabledonChange

Switch 开关

import { Switch } from "knight-ui";

<Switch defaultChecked onChange={(v) => console.log(v)} />
<Switch checkedText="开" uncheckedText="关" defaultChecked />
<Switch size="large" loading />
<Switch disabled />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | checked / defaultChecked | boolean | — | 开关状态 | | size | "small" \| "default" \| "large" | "default" | 尺寸 | | loading | boolean | false | 加载中 | | checkedText / uncheckedText | React.ReactNode | — | 开关文字 | | onChange | (checked: boolean) => void | — | 变更回调 |

Slider 滑块

import { Slider } from "knight-ui";

<Slider defaultValue={30} onChange={(v) => console.log(v)} />

// 范围滑块
<Slider range defaultValue={[20, 60]} showMinMax />

// 带刻度
<Slider defaultValue={50} step={10} tooltipVisible showMinMax />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | value / defaultValue | number \| [number, number] | — | 值 | | min / max | number | 0 / 100 | 范围 | | step | number | 1 | 步长 | | range | boolean | false | 范围选择 | | tooltipVisible | boolean | false | 显示提示 | | showMinMax | boolean | false | 显示最值标签 | | marks | Record<number, string> | — | 刻度标记 | | onChange | (value) => void | — | 变更回调 |

Rating 评分

import { Rating } from "knight-ui";

<Rating defaultValue={3} onChange={(v) => console.log(v)} />
<Rating defaultValue={3.5} allowHalf />
<Rating defaultValue={7} count={10} />
<Rating size="large" disabled defaultValue={4} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | count | number | 5 | 星星数量 | | allowHalf | boolean | false | 允许半星 | | size | "small" \| "default" \| "large" | "default" | 尺寸 | | character | React.ReactNode | — | 自定义图标 | | tooltips | string[] | — | 提示文字 | | onChange | (value: number) => void | — | 变更回调 |

TagInput 标签输入

import { TagInput } from "knight-ui";

<TagInput defaultValue={["React", "TypeScript"]} onChange={(v) => console.log(v)} />

<TagInput placeholder="按回车添加" max={5} maxTagCount={3} />

<TagInput separator="," placeholder="逗号分隔" />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | value / defaultValue | string[] | — | 标签列表 | | max | number | — | 最大标签数 | | maxTagCount | number | — | 最多显示数 | | separator | string | — | 分隔符 | | onChange | (value: string[]) => void | — | 变更回调 |

ColorPicker 颜色选择器

import { ColorPicker } from "knight-ui";

<ColorPicker defaultValue="#8b5cf6" onChange={(v) => console.log(v)} />
<ColorPicker alpha defaultFormat="rgba" />
<ColorPicker eyeDropper />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | value / defaultValue | ColorValue | — | 颜色值 | | defaultFormat | "hex" \| "rgba" \| "hsva" | "hex" | 格式 | | alpha | boolean | false | 透明度通道 | | eyeDropper | boolean | false | 取色器 | | onChange | (value: ColorValue) => void | — | 变更回调 |

Upload 上传

import { Upload, Button } from "knight-ui";

<Upload action="/api/upload" accept=".jpg,.png" onChange={(files) => console.log(files)}>
  <Button type="primary">上传文件</Button>
</Upload>

<Upload listType="pictureCard" limit={3} multiple>
  <span>+ 上传图片</span>
</Upload>

<Upload
  customRequest={async (options) => {
    const formData = new FormData();
    formData.append("file", options.file);
    await fetch("/api/upload", { method: "POST", body: formData });
    options.onSuccess();
  }}
>
  <Button>自定义上传</Button>
</Upload>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | action | string | — | 上传地址 | | accept | string | — | 文件类型 | | listType | "picture" \| "list" \| "pictureCard" | "list" | 列表类型 | | limit | number | — | 最大数量 | | multiple | boolean | false | 多文件 | | beforeUpload | (file) => boolean | — | 上传前校验 | | customRequest | (options) => Promise<void> | — | 自定义上传 | | onChange | (fileList) => void | — | 变更回调 |

AutoComplete 自动完成

import { AutoComplete } from "knight-ui";

const data = ["Apple", "Banana", "Orange", "Grape"];

<AutoComplete data={data} onSelect={(opt) => console.log(opt)} />

<AutoComplete
  data={data}
  filter
  onSearch={(keyword) => console.log(keyword)}
  placeholder="输入搜索"
/>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | data | (string \| AutoCompleteOption)[] | — | 数据源 | | filter | boolean | — | 本地过滤 | | onSearch | (inputValue) => void | — | 搜索回调 | | onSelect | (option) => void | — | 选中回调 |

Transfer 穿梭框

import { Transfer } from "knight-ui";

const data = [
  { key: "1", title: "选项一" },
  { key: "2", title: "选项二" },
  { key: "3", title: "选项三" },
];

<Transfer dataSource={data} defaultValue={["1"]} titles={["待选", "已选"]} onChange={(keys) => console.log(keys)} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | dataSource | TransferItem[] | — | 数据源 | | titles | [string, string] | — | 左右标题 | | filter | boolean | — | 可搜索 | | onChange | (targetKeys: string[]) => void | — | 变更回调 |

TreeSelect 树选择

import { TreeSelect } from "knight-ui";

const treeData = [
  { label: "Node 1", value: "1", children: [{ label: "Node 1-1", value: "1-1" }] },
  { label: "Node 2", value: "2" },
];

<TreeSelect treeData={treeData} onChange={(v) => console.log(v)} />
<TreeSelect treeData={treeData} multiple filter placeholder="搜索" />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | treeData | TreeSelectNode[] | — | 树数据 | | multiple | boolean | false | 多选 | | filter | boolean | false | 可搜索 | | onChange | (value) => void | — | 变更回调 |

PinCode 验证码输入

import { PinCode } from "knight-ui";

<PinCode count={6} onComplete={(v) => console.log("complete:", v)} />
<PinCode count={4} format="number" autoFocus size="large" />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | count | number | — | 位数 | | format | "number" \| "mixed" \| RegExp | — | 字符格式 | | autoFocus | boolean | false | 自动聚焦 | | onComplete | (value: string) => void | — | 输入完成回调 |

Form 表单

import { Form, Input, Button } from "knight-ui";

// 基础用法
<Form
  layout="horizontal"
  labelWidth={100}
  onSubmit={(values) => console.log(values)}
  onSubmitFail={(values) => console.log(values)}
  getFormApi={(api) => (window.formApi = api)}
>
  <Form.Field field="name" label="姓名" rules={[{ required: true, message: "请输入姓名" }]}>
    <Input placeholder="请输入姓名" />
  </Form.Field>
  <Form.Field field="email" label="邮箱"
    rules={[{ required: true, message: "请输入邮箱" }, { pattern: /^\S+@\S+$/, message: "邮箱格式不正确" }]}>
    <Input placeholder="请输入邮箱" />
  </Form.Field>
  <Button type="primary" htmlType="submit">提交</Button>
</Form>

// 动态字段(通过 FormApi 控制)
const formApiRef = useRef<FormApi>(null);
<Form getFormApi={(api) => (formApiRef.current = api)}>
  <Form.Field field="name" label="名称"><Input /></Form.Field>
</Form>

// 动态添加/移除字段
formApiRef.current?.addField("dynamic_key", { label: "动态字段", value: "默认值" });
formApiRef.current?.removeField("dynamic_key");

// 程序化读写
formApiRef.current?.setFieldValue("name", "新值");
formApiRef.current?.setFieldsValue({ name: "A", email: "B" });
const allValues = formApiRef.current?.getValues();
const singleValue = formApiRef.current?.getFieldValue("name");

// 手动校验
const validValues = await formApiRef.current?.validate(); // 通过返回 values,失败返回 null
formApiRef.current?.reset(); // 重置所有字段

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | layout | "horizontal" \| "vertical" | "vertical" | 布局 | | labelPosition | "left" \| "top" | "top" | 标签位置 | | labelAlign | "left" \| "right" \| "center" | "left" | 标签对齐 | | labelWidth | number | 80 | 标签宽度 | | getFormApi | (api: FormApi) => void | — | 获取表单 API | | onSubmit | (values) => void | — | 校验通过后回调 | | onSubmitFail | (values) => void | — | 校验失败回调 |

FormApi 方法

| 方法 | 说明 | |---|---| | getValues() | 获取所有字段值 | | setValues(values) | 批量设置字段值(合并) | | getFieldValue(field) | 获取单个字段值 | | setFieldValue(field, value) | 设置单个字段值 | | setFieldsValue(values) | 批量设置(仅更新已注册字段) | | addField(field, meta?) | 动态添加字段(已存在则更新) | | removeField(field) | 动态移除字段 | | validate() | 手动校验,通过返回 values,失败返回 null | | reset() | 重置所有字段值为空 | | setError(field, error) | 设置字段错误信息 |

Form.Fieldfieldlabelrules?: FormRule[]value?: any

FormRule: | 属性 | 类型 | 说明 | |---|---|---| | required | boolean | 必填 | | message | string | 错误提示 | | min / max | number | 数值范围 | | minLength / maxLength | number | 字符长度范围 | | pattern | RegExp | 正则校验 | | validator | (value, values) => string \| null \| Promise<string \| null> | 自定义校验 |


Navigation 导航

Navigation 导航菜单

import { Navigation } from "knight-ui";
import { IconStar, IconInfoCircle, IconSetting } from "knight-ui";

const items = [
  { key: "home", label: "首页", icon: <IconStar size="extraSmall" /> },
  {
    key: "docs", label: "文档", icon: <IconInfoCircle size="extraSmall" />,
    children: [
      { key: "guide", label: "快速开始" },
      { key: "api", label: "API 参考" },
    ],
  },
  { key: "about", label: "关于", icon: <IconSetting size="extraSmall" /> },
];

// 垂直模式 + 折叠切换
const [collapsed, setCollapsed] = useState(false);
<Navigation items={items} mode="vertical" isCollapsed={collapsed} onCollapseChange={setCollapsed}
  defaultSelectedKeys={["home"]} onSelect={(k) => console.log(k)} />

// 水平模式
<Navigation items={items} mode="horizontal" trigger="click" />

NavItemkeylabelicon?: React.ReactNodedisabled?: booleanchildren?: NavItem[]

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | items | NavItem[] | — | 菜单项 | | mode | "horizontal" \| "vertical" | "vertical" | 排列模式 | | trigger | "hover" \| "click" | "hover" | 子菜单触发方式 | | isCollapsed | boolean | — | 折叠状态(受控) | | defaultIsCollapsed | boolean | false | 默认折叠状态 | | onCollapseChange | (isCollapsed: boolean) => void | — | 折叠切换回调 | | selectedKeys / defaultSelectedKeys | string[] | — | 当前选中 | | openKeys / defaultOpenKeys | string[] | — | 当前展开的子菜单 | | multiple | boolean | false | 是否多选 | | onSelect | (key: string) => void | — | 选中回调 | | onOpenChange | (openKeys: string[]) => void | — | 展开变化回调 |

Tabs 标签页

import { Tabs } from "knight-ui";

const items = [
  { key: "a", label: "标签 A", content: <div>内容 A</div> },
  { key: "b", label: "标签 B", content: <div>内容 B</div> },
  { key: "c", label: "标签 C", content: <div>内容 C</div>, closable: true },
];

<Tabs items={items} defaultActiveKey="a" onChange={(k) => console.log(k)} />
<Tabs items={items} type="card" />
<Tabs items={items} type="button" />
<Tabs items={items} collapsible addable onTabClose={(k) => console.log("close", k)} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | items | TabItem[] | — | 标签项 | | activeKey / defaultActiveKey | string | — | 当前选中 | | type | "line" \| "card" \| "button" | "line" | 样式类型 | | tabPosition | "top" \| "left" \| "right" \| "bottom" | "top" | 位置 | | collapsible | boolean | false | 折叠模式 | | addable | boolean | false | 可新增标签 | | onChange | (key: string) => void | — | 切换回调 | | onTabClose | (key: string) => void | — | 关闭回调 |

Tree 树

import { Tree } from "knight-ui";

const treeData = [
  {
    key: "1", title: "节点 1",
    children: [
      { key: "1-1", title: "节点 1-1" },
      { key: "1-2", title: "节点 1-2" },
    ],
  },
  { key: "2", title: "节点 2" },
];

<Tree treeData={treeData} defaultExpandAll onSelect={(keys) => console.log(keys)} />
<Tree treeData={treeData} checkable onCheck={(keys) => console.log(keys)} />
<Tree treeData={treeData} multiple />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | treeData | TreeNodeData[] | — | 树数据 | | checkable | boolean | false | 可复选 | | multiple | boolean | false | 多选 | | defaultExpandAll | boolean | false | 默认全部展开 | | onSelect | (keys, selected, node) => void | — | 选中回调 | | onCheck | (keys, state) => void | — | 勾选回调 |

Breadcrumb 面包屑

import { Breadcrumb } from "knight-ui";

<Breadcrumb>
  <Breadcrumb.Item onClick={() => console.log("Home")}>Home</Breadcrumb.Item>
  <Breadcrumb.Item href="/products">Products</Breadcrumb.Item>
  <Breadcrumb.Item>Detail</Breadcrumb.Item>
</Breadcrumb>

// 路由模式
<Breadcrumb routes={[
  { name: "首页", path: "/" },
  { name: "列表", path: "/list" },
  { name: "详情" },
]} />

// 自定义分隔符
<Breadcrumb separator=">">
  <Breadcrumb.Item>Home</Breadcrumb.Item>
  <Breadcrumb.Item>Detail</Breadcrumb.Item>
</Breadcrumb>

Breadcrumb.ItemhrefonClickicon

Steps 步骤条

import { Steps } from "knight-ui";

<Steps current={1}>
  <Steps.Step title="步骤一" description="填写基本信息" />
  <Steps.Step title="步骤二" description="验证身份信息" />
  <Steps.Step title="步骤三" description="完成注册" />
</Steps>

// 垂直方向
<Steps direction="vertical" current={1}>
  <Steps.Step title="填写信息" />
  <Steps.Step title="确认提交" />
  <Steps.Step title="完成" />
</Steps>

// Fill 样式
<Steps type="primary" current={1} status="error">
  <Steps.Step title="步骤一" />
  <Steps.Step title="步骤二" description="出错了" />
</Steps>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | current | number | — | 当前步骤 | | status | "wait" \| "process" \| "finish" \| "error" \| "warning" | — | 状态 | | direction | "horizontal" \| "vertical" | "horizontal" | 方向 | | type | "primary" \| "basic" \| "nav" | "basic" | 样式类型 | | onChange | (index: number) => void | — | 步骤切换 |

Pagination 分页

import { Pagination } from "knight-ui";

<Pagination total={200} defaultCurrent={3} onChange={(page, size) => console.log(page, size)} />
<Pagination total={500} showSizeChanger showQuickJumper />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | total | number | 必填 | 数据总数 | | current / defaultCurrent | number | 1 | 当前页 | | pageSize / defaultPageSize | number | — | 每页条数 | | showSizeChanger | boolean | false | 条数切换 | | showQuickJumper | boolean | false | 快速跳转 | | onChange | (page, pageSize) => void | — | 页码变化回调 |

Anchor 锚点

import { Anchor } from "knight-ui";

<Anchor onChange={(key) => console.log(key)}>
  <Anchor.Link href="#section-1" title="基本介绍" />
  <Anchor.Link href="#section-2" title="API 参考" />
</Anchor>

BackTop 回到顶部

import { BackTop } from "knight-ui";

<BackTop visibilityHeight={200} onClick={() => console.log("back to top")} />

// 指定目标容器
<BackTop target={() => document.getElementById("scroll-container")!} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | visibilityHeight | number | — | 显示阈值 | | duration | number | — | 滚动时长(ms) | | target | () => HTMLElement \| Window | window | 目标容器 |


Display 展示

Avatar 头像

import { Avatar } from "knight-ui";

<Avatar size="medium">Alice</Avatar>
<Avatar size="large" src="https://picsum.photos/80" alt="avatar" />
<Avatar shape="square" color="#ec4899">S</Avatar>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | size | "extra-small" \| "small" \| "default" \| "medium" \| "large" \| number | "default" | 尺寸 | | shape | "circle" \| "square" | "circle" | 形状 | | src | string | — | 图片地址 | | color | string | — | 自定义颜色 |

Badge 角标

import { Badge, Button } from "knight-ui";

<Badge count={5}><Button>消息</Button></Badge>
<Badge count={120} overflowCount={99}><Button>通知</Button></Badge>
<Badge dot><span>新消息</span></Badge>
<Badge dot type="success" position="leftTop"><span>在线</span></Badge>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | count | number \| React.ReactNode | — | 角标内容 | | dot | boolean | false | 圆点模式 | | overflowCount | number | 99 | 溢出显示值 | | type | "primary" \| "success" \| "warning" \| "danger" | "primary" | 类型 | | position | "leftTop" \| "leftBottom" \| "rightTop" \| "rightBottom" | "rightTop" | 位置 |

Card 卡片

import { Card, Text, Button, Avatar } from "knight-ui";

<Card style={{ width: 360 }}
  cover={<div style={{ height: 140, background: "linear-gradient(135deg, #8b5cf6, #ec4899)" }} />}
  header="卡片标题"
  actions={[<Button key="1" type="tertiary" size="small">操作</Button>]}
  footer="底部信息"
>
  <Card.Meta title="Meta 标题" description="Meta 描述" avatar={<Avatar size="small">A</Avatar>} />
</Card>

<Card bordered={false} shadows="always">
  <Text>无边框阴影卡片</Text>
</Card>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | cover | React.ReactNode | — | 封面 | | header / footer | React.ReactNode | — | 头部/底部 | | actions | React.ReactNode[] | — | 操作区 | | bordered | boolean | true | 边框 | | shadows | "hover" \| "always" \| "none" | "hover" | 阴影 |

Tag 标签

import { Tag } from "knight-ui";

<Tag color="blue">蓝色标签</Tag>
<Tag type="solid" color="green">实心绿色</Tag>
<Tag type="ghost" color="orange">幽灵橙色</Tag>
<Tag closable onClose={() => console.log("closed")}>可关闭</Tag>
<Tag size="large" color="#ec4899">粉色</Tag>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | type | "ghost" \| "solid" \| "light" | "light" | 样式 | | color | string | — | 颜色 | | size | "small" \| "default" \| "large" | "default" | 尺寸 | | closable | boolean | false | 可关闭 | | avatar | React.ReactNode | — | 头像 |

Collapse 折叠面板

import { Collapse, Text } from "knight-ui";

<Collapse defaultActiveKey={["1"]}>
  <Collapse.Panel header="面板一" itemKey="1">
    <Text>面板一的内容</Text>
  </Collapse.Panel>
  <Collapse.Panel header="面板二" itemKey="2">
    <Text>面板二的内容</Text>
  </Collapse.Panel>
  <Collapse.Panel header="禁用面板" itemKey="3" disabled>
    <Text>不可见</Text>
  </Collapse.Panel>
</Collapse>

// 手风琴模式
<Collapse accordion>
  <Collapse.Panel header="面板 A" itemKey="a"><Text>内容 A</Text></Collapse.Panel>
  <Collapse.Panel header="面板 B" itemKey="b"><Text>内容 B</Text></Collapse.Panel>
</Collapse>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | activeKey / defaultActiveKey | string \| string[] | — | 展开面板 | | accordion | boolean | false | 手风琴模式 | | onChange | (activeKey) => void | — | 切换回调 |

Collapsible 轻量折叠

import { Collapsible, Button } from "knight-ui";

const [collapsed, setCollapsed] = useState(false);

<Button onClick={() => setCollapsed(!collapsed)}>{collapsed ? "展开" : "折叠"}</Button>
<Collapsible collapsed={collapsed}>
  <div style={{ padding: 16, background: "#f0f0f0" }}>可折叠内容区域</div>
</Collapsible>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | collapsed | boolean | — | 折叠状态 | | motion | boolean | true | 动画过渡 | | keepDOM | boolean | false | 保留 DOM |

Descriptions 描述列表

import { Descriptions } from "knight-ui";

const data = [
  { key: "姓名", value: "张三" },
  { key: "手机号", value: "138****8888" },
  { key: "地址", value: "北京市朝阳区", span: 2 },
];

<Descriptions layout="horizontal" column={2} data={data} bordered />

// Item 子组件
<Descriptions column={2}>
  <Descriptions.Item itemKey="创建人">李四</Descriptions.Item>
  <Descriptions.Item itemKey="状态">
    <Tag color="green">已完成</Tag>
  </Descriptions.Item>
</Descriptions>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | data | DescriptionsData[] | — | 数据 | | layout | "horizontal" \| "vertical" | "vertical" | 布局 | | column | number | 3 | 列数 | | size | "small" \| "medium" \| "large" | "medium" | 尺寸 | | row | boolean | false | 双行模式 | | bordered | boolean | false | 边框 |

Empty 空状态

import { Empty } from "knight-ui";

<Empty />
<Empty title="暂无数据" description="当前列表为空,请先添加数据" />
<Empty image={<IconAlertTriangle size="extraLarge" />} description="加载失败" />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | image | React.ReactNode | — | 自定义图片 | | title | React.ReactNode | — | 标题 | | description | React.ReactNode | — | 描述 |

Image 图片

import { Image } from "knight-ui";

<Image src="https://picsum.photos/400/300" width={200} height={150} />
<Image src="https://picsum.photos/400/300" preview />
<Image src="/not-exist.jpg" fallback="https://picsum.photos/200/150" />
<Image src="/large.jpg" lazy width={300} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | src | string | — | 图片地址 | | preview | boolean | false | 可预览 | | fallback | string | — | 加载失败回退 | | lazy | boolean | — | 懒加载 | | width / height | number \| string | — | 宽高 |

List 列表

import { List, Text } from "knight-ui";

const data = ["列表项 A", "列表项 B", "列表项 C"];

<List
  dataSource={data}
  renderItem={(item) => <Text>{item}</Text>}
  header="列表标题"
  footer="底部"
  bordered
/>

// 加载 / 空状态
<List dataSource={[]} loading />
<List dataSource={[]} empty={<Empty description="暂无数据" />} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | dataSource | any[] | — | 数据源 | | renderItem | (item, index) => ReactNode | — | 渲染函数 | | header / footer | React.ReactNode | — | 头部/底部 | | loading | boolean | false | 加载中 | | bordered | boolean | false | 边框 |

Table 表格

import { Table } from "knight-ui";

const columns = [
  { key: "name", title: "名称", dataIndex: "name", width: 120 },
  { key: "age", title: "年龄", dataIndex: "age", width: 80, sorter: (a, b) => a - b },
  { key: "city", title: "城市", dataIndex: "city" },
];
const data = [
  { name: "张三", age: 28, city: "北京" },
  { name: "李四", age: 32, city: "上海" },
];

<Table columns={columns} dataSource={data} rowKey="name" bordered />
<Table columns={columns} dataSource={data} pagination={{ total: 100 }} loading />
<Table columns={columns} dataSource={data} rowSelection selectedRowKeys={["张三"]} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | columns | TableColumn[] | — | 列定义 | | dataSource | Record<string, any>[] | — | 数据源 | | rowKey | string | — | 行唯一 key | | pagination | boolean \| PaginationConfig | — | 分页 | | loading | boolean | false | 加载中 | | bordered | boolean | false | 边框 | | striped | boolean | false | 斑马纹 | | rowSelection | boolean | — | 行选择 |

Modal 模态框

import { Modal, Button } from "knight-ui";

const [visible, setVisible] = useState(false);

<Button type="primary" onClick={() => setVisible(true)}>打开 Modal</Button>

<Modal
  title="确认操作"
  visible={visible}
  onOk={() => { setVisible(false); console.log("ok"); }}
  onCancel={() => setVisible(false)}
>
  <Text>确定要执行此操作吗?</Text>
</Modal>

// 大型 + 自定义按钮
<Modal
  title="大型模态框"
  visible={visible}
  size="large"
  okText="确认"
  cancelText="取消"
  centered
  onOk={() => setVisible(false)}
  onCancel={() => setVisible(false)}
>
  <div>大型模态框内容区域</div>
</Modal>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | visible | boolean | — | 显示状态 | | title | React.ReactNode | — | 标题 | | size | "small" \| "medium" \| "large" | "medium" | 尺寸 | | okText / cancelText | string | — | 按钮文字 | | maskClosable | boolean | true | 点击遮罩关闭 | | centered | boolean | false | 居中 | | onOk | () => void \| Promise<void> | — | 确认回调 | | onCancel | () => void | — | 取消回调 |

SideSheet 侧边面板

import { SideSheet, Button } from "knight-ui";

const [visible, setVisible] = useState(false);

<Button onClick={() => setVisible(true)}>打开侧边面板</Button>

<SideSheet
  title="详情面板"
  visible={visible}
  placement="right"
  size="medium"
  onCancel={() => setVisible(false)}
>
  <div style={{ padding: 16 }}>面板内容</div>
</SideSheet>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | visible | boolean | — | 显示状态 | | title | React.ReactNode | — | 标题 | | placement | "left" \| "right" | "right" | 滑出方向 | | size | "small" \| "medium" \| "large" | "medium" | 尺寸 | | maskClosable | boolean | true | 点击遮罩关闭 | | onCancel | () => void | — | 关闭回调 |

Dropdown 下拉菜单

import { Dropdown, Button } from "knight-ui";

const menu = [
  { key: "1", label: "选项一" },
  { key: "2", label: "选项二" },
  { key: "div", label: "", divider: true },
  { key: "3", label: "删除", danger: true },
];

<Dropdown trigger="click" menu={menu} onClickItem={(key) => console.log(key)}>
  <Button>点击展开菜单</Button>
</Dropdown>

<Dropdown trigger="hover" menu={menu} position="bottomLeft">
  <Button type="secondary">悬停展开</Button>
</Dropdown>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | menu | DropdownItem[] | — | 菜单项 | | trigger | "click" \| "hover" | "click" | 触发方式 | | position | Position | "bottom" | 弹出位置 | | onClickItem | (key: string) => void | — | 菜单项点击 |

Popover 气泡卡片

import { Popover, Button } from "knight-ui";

<Popover trigger="click" content="这是气泡提示内容" position="bottom">
  <Button>点击弹出</Button>
</Popover>

<Popover trigger="hover" title="提示标题" content={<Text>丰富的气泡内容</Text>} position="top">
  <Text style={{ borderBottom: "1px dashed", cursor: "help" }}>悬停查看</Text>
</Popover>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | content | React.ReactNode | — | 内容 | | title | React.ReactNode | — | 标题 | | position | "top" \| "bottom" \| "left" \| "right" | "bottom" | 位置 | | trigger | "hover" \| "click" \| "focus" \| "custom" | "hover" | 触发方式 | | showArrow | boolean | — | 显示箭头 |

Tooltip 文字提示

import { Tooltip, Button } from "knight-ui";

<Tooltip content="这是一段提示文字" position="top">
  <Button>悬停查看提示</Button>
</Tooltip>

<Tooltip content="左侧提示" position="left" theme="light">
  <span>悬停文本</span>
</Tooltip>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | content | React.ReactNode | — | 提示内容 | | position | Position | "top" | 位置 | | trigger | "hover" \| "click" \| "focus" \| "custom" | "hover" | 触发方式 | | theme | "dark" \| "light" | "dark" | 主题 |

Popconfirm 气泡确认框

import { Popconfirm, Button } from "knight-ui";
import { IconAlertTriangle } from "knight-ui";

// 基础用法 (默认 position="bottom", trigger="click")
<Popconfirm
  title="确定删除?"
  content="删除后不可恢复"
  onConfirm={() => console.log("confirmed")}
  onCancel={() => console.log("cancelled")}
>
  <Button type="danger">删除</Button>
</Popconfirm>

// 自定义按钮文字 + 图标
<Popconfirm title="确定保存?" content="保存后覆盖原有数据"
  icon={<IconAlertTriangle size="extraLarge" color="var(--ku-color-warning)" />}
  okText="保存" cancelText="取消"
  onConfirm={() => console.log("saved")}>
  <Button type="warning">保存</Button>
</Popconfirm>

// 8 方向弹出 (position)
<Popconfirm title="确认?" position="leftTop" onConfirm={() => {}}>
  <Button>左上弹出</Button>
</Popconfirm>
<Popconfirm title="确认?" position="rightBottom" onConfirm={() => {}}>
  <Button>右下弹出</Button>
</Popconfirm>

// hover 触发 + 带箭头
<Popconfirm title="提示" content="悬停即可查看" trigger="hover" showArrow position="top"
  onConfirm={() => {}}>
  <Button type="secondary">悬停触发</Button>
</Popconfirm>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | title | React.ReactNode | — | 标题 | | content | React.ReactNode | — | 内容 | | position | "top" \| "bottom" \| "left" \| "right" \| "leftTop" \| "rightTop" \| "leftBottom" \| "rightBottom" | "bottom" | 弹出位置(命名规则: 第一个词=左右, 第二个词=上下) | | trigger | "click" \| "hover" \| "focus" \| "custom" | "click" | 触发方式 | | icon | React.ReactNode | — | 自定义图标 | | showArrow | boolean | false | 显示箭头 | | okText / cancelText | string | "确认" / "取消" | 按钮文字 | | okButtonProps / cancelButtonProps | ButtonHTMLAttributes | — | 按钮额外属性 | | visible / defaultVisible | boolean | — | 受控/非受控显示 | | offset | number | 4 | 弹出偏移距离 | | onConfirm | (e) => void | — | 确认回调 | | onCancel | (e) => void | — | 取消回调 | | onVisibleChange | (visible: boolean) => void | — | 显示状态变化回调 |

Calendar 日历

import { Calendar } from "knight-ui";

<Calendar onChange={(date) => console.log(date)} />
<Calendar disabledDate={(d) => d.getTime() < Date.now() - 86400000} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | mode | "month" \| "year" \| "day" | "month" | 视图模式 | | disabledDate | (date) => boolean | — | 禁用日期 | | onChange | (date: Date) => void | — | 变更回调 |

Carousel 轮播

import { Carousel } from "knight-ui";

<Carousel style={{ width: 500, height: 200 }} autoPlay interval={3000}>
  <div style={{ height: 200, background: "#8b5cf6", color: "#fff" }}>Slide 1</div>
  <div style={{ height: 200, background: "#22c55e", color: "#fff" }}>Slide 2</div>
  <div style={{ height: 200, background: "#3b82f6", color: "#fff" }}>Slide 3</div>
</Carousel>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | autoPlay | boolean | false | 自动播放 | | interval | number | 3000 | 间隔(ms) | | effect | "slide" \| "fade" | "slide" | 切换效果 | | showDots | boolean | true | 指示器 | | showArrow | boolean | true | 箭头 |

Timeline 时间轴

import { Timeline } from "knight-ui";

<Timeline>
  <Timeline.Item time="2024-01-01" type="success">项目启动</Timeline.Item>
  <Timeline.Item time="2024-03-15" color="#8b5cf6">版本 v1.0 发布</Timeline.Item>
  <Timeline.Item time="2024-06-01" type="warning">迭代中</Timeline.Item>
</Timeline>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | mode | "left" \| "alternate" \| "right" | "left" | 排列模式 | | pending | React.ReactNode | — | 加载节点 |

Timeline.Itemtimedotcolortype"default" | "success" | "warning" | "danger"

ScrollList 滚动列表

import { ScrollList } from "knight-ui";

const hours = Array.from({ length: 24 }, (_, i) => ({ value: i, text: String(i).padStart(2, "0") }));

<ScrollList header="选择小时" bodyHeight={200}>
  <ScrollList.Item
    list={hours}
    mode="wheel"
    selectedIndex={12}
    onSelect={(data) => console.log(data.value)}
  />
</ScrollList>

ScrollList.Itemlistmode"normal" | "wheel")、cycledselectedIndexonSelect

Highlight 高亮

import { Highlight } from "knight-ui";

<Highlight sourceString="React 是一个用于构建用户界面的 JavaScript 库"
  searchWords={["React", "JavaScript"]} />

<Highlight sourceString="Hello World" searchWords={["hello"]}
  highlightStyle={{ color: "#f59e0b", background: "rgba(245,158,11,0.15)" }} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | sourceString | string | — | 源文本 | | searchWords | string[] | — | 关键词 | | highlightStyle | React.CSSProperties | — | 高亮样式 |

Cropper 裁剪

import { Cropper } from "knight-ui";

<Cropper src="https://picsum.photos/600/400" cropShape="rect" aspectRatio={16 / 9}
  onCrop={(result) => console.log(result)} />

<Cropper src="/avatar.jpg" cropShape="round" aspectRatio={1} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | src | string | — | 图片地址 | | cropShape | "rect" \| "round" | "rect" | 裁剪形状 | | aspectRatio | number | — | 裁剪比例 | | onCrop | (result: CropResult) => void | — | 裁剪回调 |

UserGuide 用户引导

import { UserGuide } from "knight-ui";

const steps = [
  { target: "#step-1", title: "第一步", content: "这是第一个引导步骤", placement: "bottom" },
  { target: "#step-2", title: "第二步", content: "这是第二个引导步骤", placement: "right" },
];

<UserGuide steps={steps} visible currentStep={0}
  onChange={(s) => console.log(s)}
  onSkip={() => console.log("skip")}
  onFinish={() => console.log("finish")}
/>

VChart 图表

import { VChart } from "knight-ui";

const data = [
  { label: "一月", value: 30 },
  { label: "二月", value: 50 },
  { label: "三月", value: 40 },
];

<VChart type="line" data={data} width={400} height={300} />
<VChart type="bar" data={data} colors={["#8b5cf6", "#22c55e", "#f59e0b"]} />
<VChart type="pie" data={data} width={300} height={300} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | type | "line" \| "bar" \| "pie" \| "area" \| "scatter" | — | 图表类型 | | data | { label: string; value: number }[] | — | 数据 | | width / height | number | — | 宽高 | | colors | string[] | — | 颜色数组 |

OverflowList 溢出列表

import { OverflowList, Tag } from "knight-ui";

const items = ["Item A", "Item B", "Item C", "Item D", "Item E", "Item F"];

<OverflowList
  items={items}
  minVisibleItems={3}
  collapseFrom="end"
  renderItem={(item) => <Tag type="light">{item}</Tag>}
  overflowRender={(overflow) => <Tag type="light">+{overflow.length} 更多</Tag>}
/>

// 开头折叠
<OverflowList items={items} minVisibleItems={3} collapseFrom="start"
  renderItem={(item) => <Tag color="blue">{item}</Tag>}
  overflowRender={(o) => <Tag>+{o.length}</Tag>}
/>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | items | any[] | — | 数据 | | collapseFrom | "start" \| "end" | "end" | 折叠方向 | | minVisibleItems | number | — | 最小可见数 | | renderItem | (item, index) => ReactNode | — | 渲染项 | | overflowRender | (overflow) => ReactNode | — | 溢出渲染 |


Feedback 反馈

Toast 轻提示(命令式)

import { Toast } from "knight-ui";

// 快捷方法
Toast.success("操作成功");
Toast.info("提示信息");
Toast.warning("警告信息", 3000);
Toast.error("错误信息");

// 通用方法
const id = Toast.open({
  content: "自定义内容",
  duration: 3000,
  type: "success",
  position: "top",
});
Toast.close(id);
Toast.destroyAll();

// Hook 用法
const { success, error } = Toast.useToast();
success("保存成功");

Notification 通知(命令式)

import { Notification } from "knight-ui";

Notification.success({ title: "成功", content: "操作已完成" });
Notification.info({ title: "提示", content: "这是一条通知" });
Notification.warning({ title: "警告", content: "请注意检查" });
Notification.error({ title: "错误", content: "操作失败" });

Notification.open({
  title: "自定义",
  content: "通知内容",
  duration: 5000,
  position: "topRight",
});
Notification.close(id);
Notification.destroyAll();

Banner 横幅

import { Banner } from "knight-ui";

<Banner
  visible
  type="warning"
  title="系统维护通知"
  description="系统将于今晚 22:00-02:00 进行维护升级"
  onClose={() => console.log("closed")}
/>

<Banner visible type="success" title="操作成功" fullMode bordered
  actions={<Button type="primary" size="small">查看详情</Button>}
/>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | type | "info" \| "success" \| "warning" \| "danger" | "info" | 类型 | | title | React.ReactNode | — | 标题 | | description | React.ReactNode | — | 描述 | | fullMode | boolean | — | 通栏模式 | | bordered | boolean | — | 边框 | | actions | React.ReactNode | — | 操作区 |

Progress 进度条

import { Progress } from "knight-ui";

<Progress percent={60} />
<Progress type="circle" percent={75} />
<Progress percent={80} strokeColor="#22c55e" status="success" />
<Progress percent={50} strokeColor={[{ percent: 30, color: "#ef4444" }, { percent: 100, color: "#f59e0b" }]} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | type | "line" \| "circle" | "line" | 类型 | | percent | number | — | 进度百分比 | | strokeWidth | number | — | 线条宽度 | | strokeColor | string \| Array | — | 颜色 | | status | "normal" \| "success" \| "exception" | "normal" | 状态 | | direction | "horizontal" \| "vertical" | "horizontal" | 方向 |

Skeleton 骨架屏

import { Skeleton } from "knight-ui";

// 组合使用
<Skeleton loading={isLoading} placeholder={<div>实际内容</div>}>
  <Skeleton.Title />
  <Skeleton.Paragraph rows={3} />
</Skeleton>

// 单独组件
<Skeleton.Avatar size="large" />
<Skeleton.Button />
<Skeleton.Image style={{ width: 200, height: 150 }} />

子组件:Skeleton.AvatarSkeleton.TitleSkeleton.ParagraphSkeleton.ButtonSkeleton.Image

Spin 加载中

import { Spin } from "knight-ui";

<Spin spinning={loading}>
  <div>包裹的内容区域</div>
</Spin>

<Spin size="large" tip="加载中..." />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | spinning | boolean | true | 加载状态 | | size | "small" \| "middle" \| "large" | "middle" | 尺寸 | | tip | React.ReactNode | — | 提示文字 | | delay | number | — | 延迟显示(ms) |

Feedback 反馈组件

import { Feedback } from "knight-ui";

<Feedback
  type="emoji"
  title="这次体验如何?"
  visible
  onOk={(result) => console.log(result)}
  onCancel={() => setVisible(false)}
/>

<Feedback
  type="radio"
  title="请选择原因"
  options={[
    { value: "bug", text: "有 Bug" },
    { value: "slow", text: "加载慢" },
  ]}
  onOk={(result) => console.log(result)}
/>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | type | "emoji" \| "text" \| "radio" \| "checkbox" \| "custom" | — | 类型 | | title | React.ReactNode | — | 标题 | | options | FeedbackOption[] | — | 选项 | | onOk | (result) => void | — | 确认回调 |


Plus 增强

Markdown

import { Markdown } from "knight-ui";

const md = `# 标题
这是一段 **Markdown** 文本。

- 列表项 1
- 列表项 2

\`\`\`js
console.log("hello");
\`\`\`
`;

<Markdown source={md} />
<Markdown source={md} renderMode="preview" />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | source | string | — | Markdown 文本 | | renderMode | "default" \| "preview" \| "raw" | "default" | 渲染模式 | | rows | number | — | raw 模式行数 |

CodeEditor 代码编辑器

import { CodeEditor } from "knight-ui";

<CodeEditor
  defaultValue="console.log('hello');"
  language="javascript"
  height={300}
  theme="vs-dark"
  onChange={(value) => console.log(value)}
/>

<CodeEditor language="typescript" readOnly showCopyBtn showFormatBtn />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | language | string | — | 语言 | | theme | "vs-dark" \| "light" \| "hc-black" | "vs-dark" | 主题 | | readOnly | boolean | false | 只读 | | height / minHeight | number | — | 高度 | | showCopyBtn / showFormatBtn | boolean | true | 复制/格式化按钮 | | fontSize | number | — | 字号 | | onChange | (value: string) => void | — | 变更回调 |

CodeHighlight 代码高亮

import { CodeHighlight } from "knight-ui";

const code = `function hello() {
  console.log("Hello World");
}`;

<CodeHighlight code={code} language="javascript" />
<CodeHighlight code={code} language="typescript" showLineNumbers copyable />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | code | string | — | 代码文本 | | language | string | — | 语言 | | theme | "vs-dark" \| "light" \| "hc-black" | "vs-dark" | 主题 | | showLineNumbers | boolean | — | 行号 | | copyable | boolean | true | 可复制 |

JsonViewer JSON 查看器

import { JsonViewer } from "knight-ui";

<JsonViewer value={{ name: "Knight", version: "1.0.0" }} />

<JsonViewer value='{"key": "value"}' theme="light" readOnly height={300} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | value | string \| object | — | JSON 内容 | | readOnly | boolean | false | 只读 | | height | number | — | 高度 | | theme | "vs-dark" \| "light" | "vs-dark" | 主题 | | onChange | (value: string) => void | — | 变更回调 |

Chat 聊天

import { Chat } from "knight-ui";

const messages = [
  { id: "1", content: "你好!", role: "user", timestamp: Date.now() },
  { id: "2", content: "你好,有什么可以帮助你的?", role: "assistant", timestamp: Date.now() },
];

<Chat
  dataSource={messages}
  onSend={(content) => console.log("send:", content)}
  placeholder="输入消息..."
/>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | dataSource | ChatMessage[] | — | 消息列表 | | loading | boolean | false | 加载中 | | showInput | boolean | true | 显示输入框 | | onSend | (content: string) => void | — | 发送回调 |

AudioPlayer 音频播放器

import { AudioPlayer } from "knight-ui";

<AudioPlayer src="/audio.mp3" theme="dark" />
<AudioPlayer src="/audio.mp3" autoPlay loop volume={0.5} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | src | string | — | 音频地址 | | autoPlay | boolean | false | 自动播放 | | loop | boolean | false | 循环 | | theme | "dark" \| "light" | "dark" | 主题 | | volume | number | — | 音量 0-1 |

VideoPlayer 视频播放器

import { VideoPlayer } from "knight-ui";

<VideoPlayer src="/video.mp4" poster="/poster.jpg" width={640} />
<VideoPlayer src="/video.mp4" autoPlay muted loop />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | src | string | — | 视频地址 | | poster | string | — | 封面图 | | autoPlay | boolean | false | 自动播放 | | loop | boolean | false | 循环 | | muted | boolean | — | 静音 |

DragMove 拖拽移动

import { DragMove } from "knight-ui";

<DragMove
  initialPosition={{ x: 100, y: 100 }}
  bounds={{ left: 0, top: 0, right: 500, bottom: 500 }}
  onDragEnd={(pos) => console.log(pos)}
>
  <div style={{ width: 100, height: 100, background: "#8b5cf6", cursor: "move" }}>
    拖拽我
  </div>
</DragMove>

// 限制 X 轴
<DragMove axis="x">
  <div>只能水平拖拽</div>
</DragMove>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | initialPosition | { x, y } | — | 初始位置 | | bounds | { top?, left?, right?, bottom? } | — | 边界 | | axis | "x" \| "y" | — | 限制方向 | | onDragStart / onDrag / onDragEnd | (pos) => void | — | 拖拽回调 |

HotKeys 快捷键

import { HotKeys } from "knight-ui";

<HotKeys
  keys={["ctrl+s", "ctrl+shift+f"]}
  onKeyDown={(e) => console.log("keydown:", e.keys)}
  onKeyUp={(e) => console.log("keyup:", e.keys)}
/>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | keys | string[] | — | 快捷键组合 | | attach | HTMLElement \| Document | document | 挂载节点 | | onKeyDown / onKeyUp | (e) => void | — | 按键回调 |

Lottie 动画

import { Lottie } from "knight-ui";

// 需要宿主应用注入 lottie-web 实例
<Lottie lottie={lottieWeb} src="/animation.json" autoPlay loop width={200} height={200} />
<Lottie lottie={lottieWeb} src={animationData} speed={1.5} onComplete={() => console.log("done")} />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | lottie | any | — | lottie-web 实例(由宿主注入) | | src | string \| object | — | 动画数据或 URL | | autoPlay | boolean | true | 自动播放 | | loop | boolean | true | 循环 | | speed | number | 1 | 播放速度 | | onComplete | () => void | — | 播放完成回调 |


AI 智能

AIChatInput AI 对话输入

import { AIChatInput } from "knight-ui";

<AIChatInput
  placeholder="输入你的问题..."
  onSend={(value, attachments) => console.log(value, attachments)}
  onChange={(value) => console.log(value)}
/>

<AIChatInput loading disabled placeholder="AI 正在回复..." />

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | value / defaultValue | string | — | 输入值 | | placeholder | string | — | 占位符 | | loading | boolean | false | 加载中 | | minRows / maxRows | number | — | 行数范围 | | attachments | Attachment[] | — | 附件列表 | | onSend | (value, attachments) => void | — | 发送回调 |

AIChatDialogue AI 对话展示

import { AIChatDialogue } from "knight-ui";

const messages = [
  { id: "1", role: "user", content: "这段代码有什么问题?" },
  { id: "2", role: "assistant", content: "我来帮你分析一下..." },
];

<AIChatDialogue
  dataSource={messages}
  typing
  userNickname="User"
  assistantNickname="AI Assistant"
  onCopy={(msg) => navigator.clipboard.writeText(msg.content)}
/>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | dataSource | AIMessage[] | — | 消息列表 | | typing | boolean | false | 打字效果 | | userAvatar / assistantAvatar | string | — | 头像 | | userNickname / assistantNickname | string | — | 昵称 | | maxHeight | number | — | 最大高度 | | showThinking | boolean | true | 是否显示"思考过程"块 | | thinkingTitle | React.ReactNode | "思考过程" | 思考块标题 | | thinkingDefaultCollapsed | boolean | false | 思考块默认是否收起 | | thinkingBodyMaxHeight | number | 320 | 思考正文最大高度(px),超出内部滚动 | | onCopy | (msg) => void | — | 复制回调 | | onRetry | (msg, index) => void | — | 重试回调 |

AIMessage 思考内容支持(assistant 专用)thinkingContent?: React.ReactNode 思考/推理内容(Markdown 字符串或节点),展示为消息上方可折叠的灰色思考块;thinkingTokens?: number 真实 token 数(缺省按 ~3.5 字符/token 估算);thinkingDurationMs?: number 思考耗时(ms),完整消息可传,流式思考期间由组件自动计时无需传入。 流式阶段约定:仅思考时消息为 { role:"assistant", thinkingContent: 增量, status:"streaming" }(正文留空、与 content 互斥增长);结束后替换为带 content(与可选 thinkingDurationMs)的完整消息。

<AIChatDialogue
  dataSource={[{ id: "2", role: "assistant", content: "回答正文",
    thinkingContent: "先分析…", thinkingTokens: 86, thinkingDurationMs: 12400 }]}
  thinkingTitle="思考过程"
/>

Sidebar AI 侧栏

import { Sidebar } from "knight-ui";

const items = [
  { key: "chat1", label: "对话 1", icon: <span>💬</span> },
  { key: "chat2", label: "对话 2", icon: <span>💬</span> },
];

<Sidebar
  items={items}
  defaultActiveKey="chat1"
  header={<Text strong>AI 对话列表</Text>}
  onChange={(key) => console.log(key)}
/>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | items | SidebarItem[] | — | 菜单项 | | activeKey / defaultActiveKey | string | — | 当前选中 | | collapsed | boolean | — | 折叠 | | width / collapsedWidth | number | — | 宽度/折叠宽度 | | header / footer | React.ReactNode | — | 头部/底部 |


Other 其他

ConfigProvider 全局配置

import { ConfigProvider } from "knight-ui";

<ConfigProvider componentSize="large" getPopupContainer={() => document.body}>
  <App />
</ConfigProvider>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | componentSize | "small" \| "middle" \| "large" | — | 组件尺寸 | | getPopupContainer | () => HTMLElement | — | 弹出层容器 | | direction | "ltr" \| "rtl" | "ltr" | 文本方向 |

LocaleProvider 国际化

import { LocaleProvider } from "knight-ui";

<LocaleProvider locale={{
  okText: "确认",
  cancelText: "取消",
  emptyText: "暂无数据",
  placeholder: "请选择",
}}>
  <App />
</LocaleProvider>

| 属性 | 类型 | 默认值 | 说明 | |---|---|---|---| | locale | Partial<Locale> | — | 语言包 |


Peer 依赖

| 包 | 版本 | |---|---| | react | >=18.0.0 | | react-dom | >=18.0.0 |

License

MIT