knight-ui 1.1.9 → 1.2.3

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
@@ -1474,14 +1474,58 @@ const treeData = [
1474
1474
  <Tree treeData={treeData} multiple />
1475
1475
  ```
1476
1476
 
1477
+ **勾选是三态。** 父节点自己不存勾选,它**只是子孙的汇总**:子孙全勾 = 已勾,一个没勾 = 未勾,只勾一部分 = **第三态**(实底 + 横杠)。所以"父节点勾了、子节点却没勾"这种脏状态在结构上就不可能出现。
1478
+
1479
+ ```tsx
1480
+ <Tree
1481
+ treeData={treeData}
1482
+ checkable
1483
+ onCheck={(checkedKeys, { halfCheckedKeys, checked, node }) =>
1484
+ {
1485
+ // checkedKeys: 全部已勾的键(含自动补上的父节点)
1486
+ // halfCheckedKeys: 处于第三态的父节点键
1487
+ console.log(checkedKeys, halfCheckedKeys);
1488
+ }}
1489
+ />
1490
+ ```
1491
+
1492
+ 几条要知道的:
1493
+
1494
+ - **只勾一个子节点,父节点立刻变第三态**,不需要自己维护中间态。
1495
+ - **子节点全勾时父节点自动变成已勾** —— 自下而上的收口是父节点勾选的唯一来源。
1496
+ - **点第三态的父节点是"补齐"(半勾 → 全勾),不是"清空"**;只有已勾的节点点一下才是取消。
1497
+ - **禁用节点不参与父节点的汇总**,否则一个不可点的子节点会把父节点永远卡在第三态(用户勾不上它,父节点也就永远到不了已勾)。禁用节点自己仍按传入的值显示,可以是被勾上的。
1498
+ - **传入的 `checkedKeys` 会向下补全**:给一个父节点等价于给它的整棵非禁用子树。父节点的显示完全由子孙推出来,不补的话 `checkedKeys={["1"]}` 会渲染成"父节点没勾"。
1499
+
1500
+ **`TreeNodeData.checkable` 是一道闸门。** 不写时继承 `TreeProps.checkable`;写 `false` 的节点不只是"自己少一个勾选框",它同时切断了上下:祖先的级联不穿过它,它的子树也不参与它上面父节点的汇总(理由同上一条 —— 一个勾不上的节点若能参与汇总,它上面的父节点就永远到不了已勾)。
1501
+
1502
+ ```tsx
1503
+ const treeData = [
1504
+ { key: "1", title: "节点 1", checkable: false, children: [
1505
+ { key: "1-1", title: "节点 1-1" }, // 照样有勾选框、照样能点
1506
+ ]},
1507
+ ];
1508
+ ```
1509
+
1510
+ 闸门只切"上下",不管自己下面:子节点照样有勾选框,只是它的变化传不到闸门上面去。整条支路都不想让人勾,就在闸门这一层把子节点也标上。
1511
+
1512
+ **TreeNodeData**:`key`、`title`、`children`、`disabled`、`icon`、`checkable`
1513
+
1477
1514
  | 属性 | 类型 | 默认值 | 说明 |
1478
1515
  |---|---|---|---|
1479
1516
  | `treeData` | `TreeNodeData[]` | — | 树数据 |
1480
- | `checkable` | `boolean` | `false` | 可复选 |
1481
- | `multiple` | `boolean` | `false` | 多选 |
1517
+ | `checkable` | `boolean` | `false` | 显示勾选框(三态) |
1518
+ | `multiple` | `boolean` | `false` | 多选,`onSelect` 可累积 |
1482
1519
  | `defaultExpandAll` | `boolean` | `false` | 默认全部展开 |
1520
+ | `expandedKeys` | `string[]` | — | 受控展开项 |
1521
+ | `defaultExpandedKeys` | `string[]` | `[]` | 默认展开项 |
1522
+ | `selectedKeys` | `string[]` | — | 受控选中项 |
1523
+ | `defaultSelectedKeys` | `string[]` | `[]` | 默认选中项 |
1524
+ | `checkedKeys` | `string[]` | — | 受控勾选项;传入的父节点键会向下补全 |
1525
+ | `defaultCheckedKeys` | `string[]` | `[]` | 默认勾选项 |
1483
1526
  | `onSelect` | `(keys, selected, node) => void` | — | 选中回调 |
1484
- | `onCheck` | `(keys, state) => void` | — | 勾选回调 |
1527
+ | `onExpand` | `(keys, { expanded, node }) => void` | — | 展开回调 |
1528
+ | `onCheck` | `(keys, { checked, halfCheckedKeys, node }) => void` | — | 勾选回调 |
1485
1529
 
1486
1530
  ### Breadcrumb 面包屑
1487
1531
 
@@ -40,6 +40,8 @@ export interface AIChatInputProps extends UIProps {
40
40
  minRows?: number;
41
41
  /** 最大行数,超出后滚动 @default 4 */
42
42
  maxRows?: number;
43
+ /** 底部工具条内容(输入框内、textarea 下方、发送键左侧) —— 库不关心放什么,由调用方组装;不传则保留 20px 空白垫高 */
44
+ bottomBar?: React.ReactNode;
43
45
  }
44
46
  interface AIChatInputState extends UIState {
45
47
  value: string;
@@ -2,12 +2,15 @@ import React from "react";
2
2
  import { AbstractUI, type UIProps, type UIState } from "../../base";
3
3
  /**
4
4
  * 键值编辑器 — 动态 key/value 行,支持增删. 用法: <KeyValueEditor value={obj} onChange={setObj} />
5
+ * - disabled 时输入框置灰、增删按钮不渲染,四个 handler 也各自挡一道(防程序侧调用)
5
6
  */
6
7
  export declare class KeyValueEditor extends AbstractUI<KeyValueEditorProps, KeyValueEditorState> {
7
8
  private seed;
8
9
  /** 标记内部编辑操作,阻止 componentDidUpdate 覆盖状态 */
9
10
  private internalEdit;
10
11
  constructor(props: KeyValueEditorProps);
12
+ /** 是否禁用 — 输入与增删一律不响应 */
13
+ private get isDisabled();
11
14
  componentDidUpdate(prevProps: Readonly<KeyValueEditorProps>): void;
12
15
  private static rowsEqual;
13
16
  static objectToRows(obj: Record<string, any>): KeyValueRow[];
@@ -6,6 +6,16 @@ export interface TreeNodeData {
6
6
  children?: TreeNodeData[];
7
7
  disabled?: boolean;
8
8
  icon?: React.ReactNode;
9
+ /**
10
+ * 这个节点有没有勾选框。不写时继承 `TreeProps.checkable`。
11
+ *
12
+ * 写 `false` 的节点是一道**闸门**, 不只是"自己少一个框": 祖先的级联不穿过它, 它的子树也不参与
13
+ * 它上面父节点的汇总。理由与禁用节点同源 —— 一个勾不上的节点若能参与汇总, 它上面的父节点就
14
+ * 永远到不了"全勾"。
15
+ *
16
+ * 但闸门只切"上下", 不管自己下面: 子节点写 `checkable` 的照样有勾选框、照样能点, 只是它的
17
+ * 变化传不到闸门上面去。整条支路都不想让人勾, 就在闸门这一层给子节点也标上。
18
+ */
9
19
  checkable?: boolean;
10
20
  }
11
21
  declare class TreeNodeComp extends AbstractUI<TreeNodeCompProps, UIState> {
@@ -31,9 +41,53 @@ export declare class Tree extends AbstractUI<TreeProps, TreeState> {
31
41
  private renderCheckbox;
32
42
  private toggleExpand;
33
43
  private handleSelect;
44
+ /**
45
+ * 勾/取消一个节点。两步, 顺序不能反:
46
+ * ① 向下级联 —— 整棵子树跟着变;
47
+ * ② 向上收口 —— 祖先按"子节点是不是全勾了"重算。这一步是父节点勾选的**唯一来源**,
48
+ * 少了它, 子节点全勾了父节点也不会亮。
49
+ */
34
50
  private handleCheck;
35
- private addDescendantKeys;
36
- private removeDescendantKeys;
51
+ /**
52
+ * 这个节点有没有勾选框 —— 只看自己和 `TreeProps.checkable`, **不看祖先**。
53
+ * 闸门是单向的(见 TreeNodeData.checkable): 祖先没有勾选框不代表它下面的子节点也没有。
54
+ */
55
+ private isCheckable;
56
+ /**
57
+ * 一次后序遍历算出整棵树的勾选态(含第三态)。渲染与 halfCheckedKeys 共用这一张表。
58
+ *
59
+ * 父节点**不看自己在集合里有没有**, 只看子孙的汇总 —— 因为第三态没有地方存: 它既不是
60
+ * "在集合里"也不是"不在集合里", 是子孙的一种分布, 只能算出来。
61
+ * 必须后序: 父节点要问"我所有子孙都勾了吗", 而这正是子树的返回值, 先得把子树算完。
62
+ *
63
+ * 汇总只数**有勾选框且没禁用**的子节点。两者理由同源: 一个用户点不到的框(禁用的)或压根不存在的
64
+ * 框(没勾选框的)若能参与汇总, 它上面的父节点就永远到不了"全勾" —— 用户没有任何办法把它凑齐。
65
+ */
66
+ private buildCheckStates;
67
+ /**
68
+ * 把一个节点连同它的子树一起勾上/取消。**跳过禁用节点与没有勾选框的节点(闸门)** ——
69
+ * 不跳的话, 勾父节点会顺手把用户点不到的框也勾上(禁用), 或者穿过一道本该切断的闸门。
70
+ */
71
+ private markSubtree;
72
+ /**
73
+ * 自下而上把祖先收口: 子节点(有勾选框且没禁用)全勾 → 祖先补进集合; 只要有一个没勾 → 从集合里去掉。
74
+ *
75
+ * 返回值是"这一层是不是全勾了", 供上一层判断 —— 父节点的答案只能是子树的答案, 没有别的来源。
76
+ * 也是后序, 且必须在 ① 之后跑: 拿半截状态判断会得出错的祖先。
77
+ *
78
+ * 禁用节点分两头看: **仍要重算它自己的归属**(否则它会被画成已勾、却不在集合里, 画的和报的
79
+ * 对不上), 但**不参与它父节点的判断**。没有勾选框的节点连归属都不用重算 —— 它压根不显示。
80
+ */
81
+ private syncAncestors;
82
+ /**
83
+ * 补全外部传进来的 checkedKeys: 给一个父节点, 等价于给它的整棵子树(禁用与闸门以下不算)。
84
+ *
85
+ * 不补的话 `checkedKeys={["1"]}` 会渲染成"父节点没勾" —— 父节点的显示完全由子孙推出来
86
+ * (见 buildCheckStates), 而它的子孙一个都不在集合里。这是从"父节点自己存勾选"换成
87
+ * "父节点由子孙决定"之后必须补上的一环。
88
+ * 显式列出的键一律保留(哪怕禁用或没有勾选框 —— 消费方说了算), 但不再往下级联。
89
+ */
90
+ private expandCheckedKeys;
37
91
  private collectAllKeys;
38
92
  private static buildTreeData;
39
93
  private findNode;