knight-ui 1.0.2 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -423,19 +423,26 @@ import { Resizable } from "knight-ui";
423
423
  ```tsx
424
424
  import { Input } from "knight-ui";
425
425
 
426
+ // 非受控(浏览器原生管理输入,IME 无干扰)
426
427
  <Input placeholder="请输入" onChange={(v) => console.log(v)} />
427
428
  <Input showClear defaultValue="可清除" />
429
+
430
+ // 受控(通过 value 管理显示值,Form.Field 自动使用此模式)
431
+ <Input value={text} onChange={(v) => setText(v)} placeholder="受控输入" />
432
+
428
433
  <Input prefix={<IconSearch />} placeholder="搜索" />
429
434
  <Input addonBefore="https://" addonAfter=".com" placeholder="域名" />
430
435
  <Input type="password" placeholder="密码" />
431
436
  <Input size="large" placeholder="大尺寸" />
432
437
 
433
- // 多行文本
438
+ // 多行文本(同样支持 value / defaultValue)
434
439
  <Input.TextArea rows={4} placeholder="多行文本" onChange={(v) => console.log(v)} />
435
440
  ```
436
441
 
437
442
  | 属性 | 类型 | 默认值 | 说明 |
438
443
  |---|---|---|---|
444
+ | `value` | `string` | — | 受控值(提供后组件变为受控模式) |
445
+ | `defaultValue` | `string` | — | 非受控默认值 |
439
446
  | `type` | `"text" \| "password"` | `"text"` | 输入类型 |
440
447
  | `placeholder` | `string` | — | 占位符 |
441
448
  | `size` | `"small" \| "default" \| "large"` | `"default"` | 尺寸 |
@@ -838,33 +845,81 @@ import { PinCode } from "knight-ui";
838
845
  ```tsx
839
846
  import { Form, Input, Button } from "knight-ui";
840
847
 
848
+ // 基础用法
841
849
  <Form
842
850
  layout="horizontal"
843
851
  labelWidth={100}
844
852
  onSubmit={(values) => console.log(values)}
845
- onSubmitFail={(errors) => console.log(errors)}
853
+ onSubmitFail={(values) => console.log(values)}
846
854
  getFormApi={(api) => (window.formApi = api)}
847
855
  >
848
856
  <Form.Field field="name" label="姓名" rules={[{ required: true, message: "请输入姓名" }]}>
849
857
  <Input placeholder="请输入姓名" />
850
858
  </Form.Field>
851
- <Form.Field field="email" label="邮箱" rules={[{ required: true, type: "email" }]}>
859
+ <Form.Field field="email" label="邮箱"
860
+ rules={[{ required: true, message: "请输入邮箱" }, { pattern: /^\S+@\S+$/, message: "邮箱格式不正确" }]}>
852
861
  <Input placeholder="请输入邮箱" />
853
862
  </Form.Field>
854
863
  <Button type="primary" htmlType="submit">提交</Button>
855
864
  </Form>
865
+
866
+ // 动态字段(通过 FormApi 控制)
867
+ const formApiRef = useRef<FormApi>(null);
868
+ <Form getFormApi={(api) => (formApiRef.current = api)}>
869
+ <Form.Field field="name" label="名称"><Input /></Form.Field>
870
+ </Form>
871
+
872
+ // 动态添加/移除字段
873
+ formApiRef.current?.addField("dynamic_key", { label: "动态字段", value: "默认值" });
874
+ formApiRef.current?.removeField("dynamic_key");
875
+
876
+ // 程序化读写
877
+ formApiRef.current?.setFieldValue("name", "新值");
878
+ formApiRef.current?.setFieldsValue({ name: "A", email: "B" });
879
+ const allValues = formApiRef.current?.getValues();
880
+ const singleValue = formApiRef.current?.getFieldValue("name");
881
+
882
+ // 手动校验
883
+ const validValues = await formApiRef.current?.validate(); // 通过返回 values,失败返回 null
884
+ formApiRef.current?.reset(); // 重置所有字段
856
885
  ```
857
886
 
858
887
  | 属性 | 类型 | 默认值 | 说明 |
859
888
  |---|---|---|---|
860
- | `layout` | `"horizontal" \| "vertical"` | `"horizontal"` | 布局 |
861
- | `labelPosition` | `"left" \| "top"` | `"left"` | 标签位置 |
862
- | `labelWidth` | `number` | | 标签宽度 |
889
+ | `layout` | `"horizontal" \| "vertical"` | `"vertical"` | 布局 |
890
+ | `labelPosition` | `"left" \| "top"` | `"top"` | 标签位置 |
891
+ | `labelAlign` | `"left" \| "right" \| "center"` | `"left"` | 标签对齐 |
892
+ | `labelWidth` | `number` | `80` | 标签宽度 |
863
893
  | `getFormApi` | `(api: FormApi) => void` | — | 获取表单 API |
864
- | `onSubmit` | `(values) => void` | — | 提交回调 |
894
+ | `onSubmit` | `(values) => void` | — | 校验通过后回调 |
865
895
  | `onSubmitFail` | `(values) => void` | — | 校验失败回调 |
866
896
 
867
- **Form.Field**:`field`、`label`、`rules`、`trigger`
897
+ **FormApi 方法**:
898
+
899
+ | 方法 | 说明 |
900
+ |---|---|
901
+ | `getValues()` | 获取所有字段值 |
902
+ | `setValues(values)` | 批量设置字段值(合并) |
903
+ | `getFieldValue(field)` | 获取单个字段值 |
904
+ | `setFieldValue(field, value)` | 设置单个字段值 |
905
+ | `setFieldsValue(values)` | 批量设置(仅更新已注册字段) |
906
+ | `addField(field, meta?)` | 动态添加字段(已存在则更新) |
907
+ | `removeField(field)` | 动态移除字段 |
908
+ | `validate()` | 手动校验,通过返回 values,失败返回 null |
909
+ | `reset()` | 重置所有字段值为空 |
910
+ | `setError(field, error)` | 设置字段错误信息 |
911
+
912
+ **Form.Field**:`field`、`label`、`rules?: FormRule[]`、`value?: any`
913
+
914
+ **FormRule**:
915
+ | 属性 | 类型 | 说明 |
916
+ |---|---|---|
917
+ | `required` | `boolean` | 必填 |
918
+ | `message` | `string` | 错误提示 |
919
+ | `min / max` | `number` | 数值范围 |
920
+ | `minLength / maxLength` | `number` | 字符长度范围 |
921
+ | `pattern` | `RegExp` | 正则校验 |
922
+ | `validator` | `(value, values) => string \| null \| Promise<string \| null>` | 自定义校验 |
868
923
 
869
924
  ---
870
925
 
@@ -874,29 +929,44 @@ import { Form, Input, Button } from "knight-ui";
874
929
 
875
930
  ```tsx
876
931
  import { Navigation } from "knight-ui";
932
+ import { IconStar, IconInfoCircle, IconSetting } from "knight-ui";
877
933
 
878
934
  const items = [
879
- { key: "home", label: "首页" },
935
+ { key: "home", label: "首页", icon: <IconStar size="extraSmall" /> },
880
936
  {
881
- key: "docs", label: "文档",
937
+ key: "docs", label: "文档", icon: <IconInfoCircle size="extraSmall" />,
882
938
  children: [
883
939
  { key: "guide", label: "快速开始" },
884
940
  { key: "api", label: "API 参考" },
885
941
  ],
886
942
  },
887
- { key: "about", label: "关于" },
943
+ { key: "about", label: "关于", icon: <IconSetting size="extraSmall" /> },
888
944
  ];
889
945
 
890
- <Navigation items={items} mode="vertical" defaultSelectedKeys={["home"]} onSelect={(k) => console.log(k)} />
946
+ // 垂直模式 + 折叠切换
947
+ const [collapsed, setCollapsed] = useState(false);
948
+ <Navigation items={items} mode="vertical" isCollapsed={collapsed} onCollapseChange={setCollapsed}
949
+ defaultSelectedKeys={["home"]} onSelect={(k) => console.log(k)} />
950
+
951
+ // 水平模式
891
952
  <Navigation items={items} mode="horizontal" trigger="click" />
892
953
  ```
893
954
 
955
+ **NavItem**:`key`、`label`、`icon?: React.ReactNode`、`disabled?: boolean`、`children?: NavItem[]`
956
+
894
957
  | 属性 | 类型 | 默认值 | 说明 |
895
958
  |---|---|---|---|
896
959
  | `items` | `NavItem[]` | — | 菜单项 |
897
960
  | `mode` | `"horizontal" \| "vertical"` | `"vertical"` | 排列模式 |
898
961
  | `trigger` | `"hover" \| "click"` | `"hover"` | 子菜单触发方式 |
962
+ | `isCollapsed` | `boolean` | — | 折叠状态(受控) |
963
+ | `defaultIsCollapsed` | `boolean` | `false` | 默认折叠状态 |
964
+ | `onCollapseChange` | `(isCollapsed: boolean) => void` | — | 折叠切换回调 |
965
+ | `selectedKeys / defaultSelectedKeys` | `string[]` | — | 当前选中 |
966
+ | `openKeys / defaultOpenKeys` | `string[]` | — | 当前展开的子菜单 |
967
+ | `multiple` | `boolean` | `false` | 是否多选 |
899
968
  | `onSelect` | `(key: string) => void` | — | 选中回调 |
969
+ | `onOpenChange` | `(openKeys: string[]) => void` | — | 展开变化回调 |
900
970
 
901
971
  ### Tabs 标签页
902
972
 
@@ -55,6 +55,20 @@ export interface FormApi {
55
55
  validate: () => Promise<Record<string, any> | null>;
56
56
  reset: () => void;
57
57
  setError: (field: string, error: string | null) => void;
58
+ /** 动态添加字段(若已存在则更新) */
59
+ addField: (field: string, meta?: {
60
+ label?: React.ReactNode;
61
+ rules?: FormRule[];
62
+ value?: any;
63
+ }) => void;
64
+ /** 动态移除字段 */
65
+ removeField: (field: string) => void;
66
+ /** 获取单个字段值 */
67
+ getFieldValue: (field: string) => any;
68
+ /** 设置单个字段值 */
69
+ setFieldValue: (field: string, value: any) => void;
70
+ /** 批量设置字段值(合并, 仅更新已注册字段) */
71
+ setFieldsValue: (values: Record<string, any>) => void;
58
72
  }
59
73
  /**
60
74
  * 表单。
@@ -70,6 +84,11 @@ export declare class Form extends AbstractUI<FormProps, FormState> {
70
84
  private updateField;
71
85
  private getValues;
72
86
  private setValues;
87
+ private addField;
88
+ private removeField;
89
+ private getFieldValue;
90
+ private setFieldValue;
91
+ private setFieldsValue;
73
92
  private validate;
74
93
  private reset;
75
94
  private setError;
@@ -5,10 +5,13 @@ declare class TextArea extends AbstractUI<TextAreaProps, TextAreaState> {
5
5
  static displayName: string;
6
6
  private textareaRef;
7
7
  constructor(props: TextAreaProps);
8
+ componentDidUpdate(prevProps: Readonly<TextAreaProps>, _prevState: Readonly<TextAreaState>): void;
8
9
  focus(): void;
9
10
  protected OnRenderContent(): React.ReactElement;
10
11
  }
11
12
  export interface TextAreaProps extends UIProps {
13
+ /** 受控值(提供后组件变为受控模式) */
14
+ value?: string;
12
15
  defaultValue?: string;
13
16
  placeholder?: string;
14
17
  maxLength?: number;
@@ -28,12 +31,15 @@ export declare class Input extends AbstractUI<InputProps, InputState> {
28
31
  static TextArea: typeof TextArea;
29
32
  private inputRef;
30
33
  constructor(props: InputProps);
34
+ componentDidUpdate(prevProps: Readonly<InputProps>, _prevState: Readonly<InputState>): void;
31
35
  focus(): void;
32
36
  blur(): void;
33
37
  protected OnRenderContent(): React.ReactElement;
34
38
  }
35
39
  export interface InputProps extends UIProps {
36
40
  type?: "text" | "password";
41
+ /** 受控值(提供后组件变为受控模式) */
42
+ value?: string;
37
43
  defaultValue?: string;
38
44
  placeholder?: string;
39
45
  size?: "small" | "default" | "large";
@@ -9,7 +9,7 @@ export type { ColorPickerProps, ColorValue } from "./ColorPicker";
9
9
  export { DatePicker } from "./DatePicker";
10
10
  export type { DatePickerProps } from "./DatePicker";
11
11
  export { Form } from "./Form";
12
- export type { FormProps } from "./Form";
12
+ export type { FormProps, FormApi, FormRule } from "./Form";
13
13
  export { KeyValueEditor } from "./KeyValueEditor";
14
14
  export type { KeyValueEditorProps, KeyValueRow } from "./KeyValueEditor";
15
15
  export { Input } from "./Input";
package/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
1
  export * from "./base";
2
2
  export * from "./component";
3
- export * from "./test";