@manohub/ui 0.7.1 → 0.8.1

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.
Files changed (39) hide show
  1. package/README.md +1 -1
  2. package/dist/components/button/index.d.ts +6 -0
  3. package/dist/components/card/index.d.ts +21 -19
  4. package/dist/components/card/index.js +12 -4
  5. package/dist/components/form/index.d.ts +28 -46
  6. package/dist/components/form/index.js +3 -21
  7. package/dist/components/input/index.d.ts +74 -6
  8. package/dist/components/input/index.js +13 -1
  9. package/dist/components/list-view/index.d.ts +1 -1
  10. package/dist/components/pagination/index.d.ts +2 -2
  11. package/dist/components/pagination/index.js +1 -1
  12. package/dist/components/query-state/index.d.ts +18 -2
  13. package/dist/components/select/index.d.ts +32 -30
  14. package/dist/components/select/index.js +46 -82
  15. package/dist/components/select/select-list.d.ts +125 -0
  16. package/dist/components/select/select-list.js +95 -0
  17. package/dist/components/select/select-panel.d.ts +106 -0
  18. package/dist/components/select/select-panel.js +72 -0
  19. package/dist/components/select/select-shared.d.ts +64 -0
  20. package/dist/components/select/select-shared.js +24 -0
  21. package/dist/components/select/select-tree-filter.d.ts +61 -0
  22. package/dist/components/select/select-tree-filter.js +63 -0
  23. package/dist/components/select/select-tree.d.ts +274 -0
  24. package/dist/components/select/select-tree.js +263 -0
  25. package/dist/components/select/select-trigger.d.ts +132 -0
  26. package/dist/components/select/select-trigger.js +101 -0
  27. package/dist/components/steps/index.d.ts +1 -1
  28. package/dist/components/table/index.d.ts +25 -4
  29. package/dist/components/text/index.d.ts +7 -2
  30. package/dist/components/tree/index.d.ts +28 -2
  31. package/dist/components/tree/index.js +14 -1
  32. package/dist/index.d.ts +1 -1
  33. package/dist/index.js +2 -0
  34. package/dist/styles/components/card.css +7 -1
  35. package/dist/styles/components/form.css +0 -21
  36. package/dist/styles/components/input.css +25 -0
  37. package/dist/styles/components/select.css +21 -0
  38. package/dist/styles/components/select.tokens.css +3 -0
  39. package/package.json +2 -2
@@ -0,0 +1,106 @@
1
+ /**
2
+ * SelectPanel —— 选择器族的**面板壳内件**(`Select` 与 `SelectTree` 共用,不对外导出)。
3
+ *
4
+ * 它只拥有三样东西:**原生 popover 元素**(开合 / Esc / 点外部关闭 / 顶层渲染 / 定位全归浏览器)、
5
+ * **搜索行**(面板顶部那一个输入框)、以及**内容槽**(列表体或树体)。
6
+ * 「面板里装什么」不在本件 —— 这正是让列表与树共用同一份面板皮肤的原因。
7
+ *
8
+ * 组合类名与服务端三条属性都是**操作层的组合**,不是本件新造的浮层:
9
+ * `class="mh-popup mh-select__panel mh-popup--anchored"`(状态根 + 本族皮肤 + 显式锚档)、
10
+ * `data-side` / `data-align`(`popup.css` 的定位档)、`popover="auto"`(原生轻 dismiss)。
11
+ * 面板宽度跟触发器走:`select.css` 的 `.mh-select__panel` 用 `anchor-size(width)` 取锚点宽,
12
+ * 锚是挂在**表壳**上的 `.mh-popup-anchor`(触发器进壳后隐式锚会缩成壳内控件,故走显式锚档)。
13
+ *
14
+ * `elementRef` 是**由消费方持有的 ref**(不是本件自己的):开面板(触发器 ↑↓)、收起面板(选中后)、
15
+ * 以及列表形态的 `.mh-select__option` 焦点遍历都要在父层拿到这个 DOM 元素。
16
+ */
17
+ import { type PropType, type SlotsType, type VNodeChild } from 'vue';
18
+ import type { ElementRef } from './select-shared';
19
+ export declare const SelectPanel: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
20
+ /** 面板 id(必须与触发器的 `popovertarget` 成对) */
21
+ id: {
22
+ type: StringConstructor;
23
+ required: true;
24
+ };
25
+ /** 面板元素的 ref,由消费方持有(父层要用它开合与遍历选项) */
26
+ elementRef: {
27
+ type: PropType<ElementRef>;
28
+ default: undefined;
29
+ };
30
+ /** 是否渲染搜索行(列表形态:`searchable` 或选项多于 8 条;树形态同口径) */
31
+ searchable: {
32
+ type: BooleanConstructor;
33
+ default: boolean;
34
+ };
35
+ keyword: {
36
+ type: StringConstructor;
37
+ default: string;
38
+ };
39
+ searchPlaceholder: {
40
+ type: StringConstructor;
41
+ default: string;
42
+ };
43
+ /** 搜索词变化(消费方负责写回 keyword,并自行决定要不要上抛 `onSearch`) */
44
+ onKeyword: {
45
+ type: PropType<(keyword: string) => void>;
46
+ default: undefined;
47
+ };
48
+ /**
49
+ * 面板上的键盘契约。
50
+ *
51
+ * 列表形态给 `↑↓` 移动高亮行(选项是真实 `<button>`,焦点即高亮);树形态不给 ——
52
+ * 树的行是 `div`、没有 tabindex,焦点无处可落(与 `Tree` 自身不做键盘导航同口径)。
53
+ */
54
+ onKeydown: {
55
+ type: PropType<(event: KeyboardEvent) => void>;
56
+ default: undefined;
57
+ };
58
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
59
+ /** 面板 id(必须与触发器的 `popovertarget` 成对) */
60
+ id: {
61
+ type: StringConstructor;
62
+ required: true;
63
+ };
64
+ /** 面板元素的 ref,由消费方持有(父层要用它开合与遍历选项) */
65
+ elementRef: {
66
+ type: PropType<ElementRef>;
67
+ default: undefined;
68
+ };
69
+ /** 是否渲染搜索行(列表形态:`searchable` 或选项多于 8 条;树形态同口径) */
70
+ searchable: {
71
+ type: BooleanConstructor;
72
+ default: boolean;
73
+ };
74
+ keyword: {
75
+ type: StringConstructor;
76
+ default: string;
77
+ };
78
+ searchPlaceholder: {
79
+ type: StringConstructor;
80
+ default: string;
81
+ };
82
+ /** 搜索词变化(消费方负责写回 keyword,并自行决定要不要上抛 `onSearch`) */
83
+ onKeyword: {
84
+ type: PropType<(keyword: string) => void>;
85
+ default: undefined;
86
+ };
87
+ /**
88
+ * 面板上的键盘契约。
89
+ *
90
+ * 列表形态给 `↑↓` 移动高亮行(选项是真实 `<button>`,焦点即高亮);树形态不给 ——
91
+ * 树的行是 `div`、没有 tabindex,焦点无处可落(与 `Tree` 自身不做键盘导航同口径)。
92
+ */
93
+ onKeydown: {
94
+ type: PropType<(event: KeyboardEvent) => void>;
95
+ default: undefined;
96
+ };
97
+ }>> & Readonly<{}>, {
98
+ onKeydown: (event: KeyboardEvent) => void;
99
+ keyword: string;
100
+ elementRef: ElementRef;
101
+ searchable: boolean;
102
+ searchPlaceholder: string;
103
+ onKeyword: (keyword: string) => void;
104
+ }, SlotsType<{
105
+ default?: () => VNodeChild;
106
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
@@ -0,0 +1,72 @@
1
+ import { defineComponent, createVNode, mergeProps } from "vue";
2
+ const SelectPanel = /* @__PURE__ */ defineComponent({
3
+ name: "SelectPanel",
4
+ inheritAttrs: false,
5
+ props: {
6
+ /** 面板 id(必须与触发器的 `popovertarget` 成对) */
7
+ id: {
8
+ type: String,
9
+ required: true
10
+ },
11
+ /** 面板元素的 ref,由消费方持有(父层要用它开合与遍历选项) */
12
+ elementRef: {
13
+ type: Object,
14
+ default: void 0
15
+ },
16
+ /** 是否渲染搜索行(列表形态:`searchable` 或选项多于 8 条;树形态同口径) */
17
+ searchable: {
18
+ type: Boolean,
19
+ default: false
20
+ },
21
+ keyword: {
22
+ type: String,
23
+ default: ""
24
+ },
25
+ searchPlaceholder: {
26
+ type: String,
27
+ default: "搜索"
28
+ },
29
+ /** 搜索词变化(消费方负责写回 keyword,并自行决定要不要上抛 `onSearch`) */
30
+ onKeyword: {
31
+ type: Function,
32
+ default: void 0
33
+ },
34
+ /**
35
+ * 面板上的键盘契约。
36
+ *
37
+ * 列表形态给 `↑↓` 移动高亮行(选项是真实 `<button>`,焦点即高亮);树形态不给 ——
38
+ * 树的行是 `div`、没有 tabindex,焦点无处可落(与 `Tree` 自身不做键盘导航同口径)。
39
+ */
40
+ onKeydown: {
41
+ type: Function,
42
+ default: void 0
43
+ }
44
+ },
45
+ slots: Object,
46
+ setup(props, {
47
+ slots
48
+ }) {
49
+ return () => createVNode("div", mergeProps({
50
+ "ref": props.elementRef,
51
+ "id": props.id
52
+ }, {
53
+ popover: "auto"
54
+ }, {
55
+ "class": "mh-popup mh-select__panel mh-popup--anchored",
56
+ "data-side": "bottom",
57
+ "data-align": "start",
58
+ "role": "listbox",
59
+ "onKeydown": props.onKeydown
60
+ }), [props.searchable ? createVNode("div", {
61
+ "class": "mh-select__search"
62
+ }, [createVNode("input", {
63
+ "class": "mh-input",
64
+ "value": props.keyword,
65
+ "placeholder": props.searchPlaceholder,
66
+ "onInput": (event) => props.onKeyword?.(event.target.value)
67
+ }, null)]) : null, slots.default?.()]);
68
+ }
69
+ });
70
+ export {
71
+ SelectPanel
72
+ };
@@ -0,0 +1,64 @@
1
+ /**
2
+ * 选择器族的**共用原子**(类型、面板 id、popover 开合、触发器键盘契约)。
3
+ *
4
+ * 这是 `select/` 目录里的**叶子模块**:它不 import 同目录任何其它文件,因此触发器 / 面板壳 /
5
+ * 列表体 / 树体四件可以自由地互相组合而不产生环。内件一律**不对外导出**(`src/index.ts` 只出
6
+ * `Select` 与 `SelectTree`),故本文件的导出面是「族内契约」,改它要同时看那四件。
7
+ *
8
+ * 为什么单独一份而不是各自写一遍:这四样都是**跨两件以上**的东西 ——
9
+ * 类型(列表体与树体都要)、面板 id 生成器(两件的面板都得全页唯一)、
10
+ * popover 开合(两件都要收起面板)、触发器键盘契约(两件的触发器是同一个形态)。
11
+ */
12
+ import type { Ref } from 'vue';
13
+ /** 选项(平铺项与分组内选项同构) */
14
+ export interface SelectOption {
15
+ label: string;
16
+ value: string | number;
17
+ disabled?: boolean;
18
+ /** 分组标题用的标记(内部判别用,消费方不必写) */
19
+ options?: never;
20
+ }
21
+ /** 分组选项(`{ label: '进行中', options: [...] }`,组内选项与平铺选项同构) */
22
+ export interface SelectOptionGroup {
23
+ label: string;
24
+ options: SelectOption[];
25
+ }
26
+ export type SelectItem = SelectOption | SelectOptionGroup;
27
+ export type SelectValue = string | number | Array<string | number>;
28
+ /** 判别:带 `options` 数组的是分组 */
29
+ export declare const isGroup: (item: SelectItem) => item is SelectOptionGroup;
30
+ /** 生成全页唯一的面板 id(随机段与全库其它随机 id 同法) */
31
+ export declare const createSelectPanelId: () => string;
32
+ /**
33
+ * 开 / 收面板 —— 调的是**原生** `showPopover()` / `hidePopover()`,不是自建浮层逻辑
34
+ * (面板的开合、Esc、点外部关闭、顶层渲染全归浏览器与 `styles/operations/popup.css`)。
35
+ *
36
+ * 先探存在性再调用:jsdom 至今没实现这套 API,直接 `?.()` 会在测试里抛「不是函数」。
37
+ */
38
+ export declare const showPanel: (element: HTMLElement | null) => void;
39
+ export declare const hidePanel: (element: HTMLElement | null) => void;
40
+ /** 触发器键盘契约的输入 */
41
+ export interface TriggerKeydownOptions {
42
+ /** 有清除位时才接 `Delete` 清值(与输入框的键盘清除同款) */
43
+ clearable: boolean;
44
+ disabled: boolean;
45
+ clear: () => void;
46
+ openPanel: () => void;
47
+ /**
48
+ * 面板打开后把焦点落到某一项上(**可选**)。
49
+ *
50
+ * 列表形态给上它(选项是真实 `<button>`,焦点即高亮);树形态不给 ——
51
+ * 树的行是 `div`、没有 tabindex,焦点无处可落。
52
+ */
53
+ focusFirst?: (direction: 1 | -1) => void;
54
+ }
55
+ /**
56
+ * 触发器上的键盘契约(`Select` 与 `SelectTree` 共用一份)。
57
+ *
58
+ * `Delete` 清值、`↑` / `↓` 开面板(并可选聚焦首 / 末项)—— 这一对是**触发器形态**的通用操作,
59
+ * 与「面板里装的是列表还是树」无关,故两件同源。`focusFirst` 的入参是**方向**而不是下标:
60
+ * 列表侧据此在「尚未聚焦任何项」时落到首项(向下)或末项(向上)。
61
+ */
62
+ export declare function createTriggerKeydown(options: TriggerKeydownOptions): (event: KeyboardEvent) => void;
63
+ /** 供内件声明 ref 属性用的类型别名(面板壳的 elementRef 入参) */
64
+ export type ElementRef = Ref<HTMLElement | null>;
@@ -0,0 +1,24 @@
1
+ const isGroup = (item) => Array.isArray(item.options);
2
+ const PANEL_ID_PREFIX = "mh-select-";
3
+ const createSelectPanelId = () => `${PANEL_ID_PREFIX}${Math.random().toString(36).slice(2, 10)}`;
4
+ const showPanel = (element) => element?.showPopover?.();
5
+ const hidePanel = (element) => element?.hidePopover?.();
6
+ function createTriggerKeydown(options) {
7
+ return (event) => {
8
+ if (event.key === "Delete" && options.clearable) options.clear();
9
+ if (event.key === "ArrowDown" || event.key === "ArrowUp") {
10
+ event.preventDefault();
11
+ if (options.disabled) return;
12
+ options.openPanel();
13
+ const direction = event.key === "ArrowDown" ? 1 : -1;
14
+ if (options.focusFirst) requestAnimationFrame(() => options.focusFirst?.(direction));
15
+ }
16
+ };
17
+ }
18
+ export {
19
+ createSelectPanelId,
20
+ createTriggerKeydown,
21
+ hidePanel,
22
+ isGroup,
23
+ showPanel
24
+ };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * 选择器族 · 树形态的**纯函数层**(过滤、命中切分、按值找节点)。
3
+ *
4
+ * 为什么单独一层:这三件事都是**数据变换**,与渲染无关,却最容易写错(祖先链要不要留、
5
+ * 父命中要不要连整支、多次命中怎么切)。抽成不依赖 DOM 的函数后可以直接单测 ——
6
+ * 用例是 `__tests__/select-tree-filter.spec.ts`,不必挂组件、也不必造 DOM。
7
+ *
8
+ * 本文件不 import 任何 Vue 运行时代码(只有类型),也不产出类名 ——
9
+ * 它是 `select/` 目录里的叶子模块之一。
10
+ */
11
+ import type { TreeNode } from '../tree';
12
+ /** 树的三条取值口径(与 `Tree` 的同名 prop 同义,故整包传同一个对象即可) */
13
+ export interface TreeAccessors {
14
+ /** 节点主键:字段名或取值函数 */
15
+ rowKey: string | ((node: TreeNode) => string);
16
+ /** 子节点字段名 */
17
+ childrenKey: string;
18
+ /** 标签字段名 */
19
+ labelKey: string;
20
+ }
21
+ /** 取节点主键(与 `Tree` 内部的 `String()` 口径一致:值一律以字符串参与比较) */
22
+ export declare const treeNodeKey: (node: TreeNode, rowKey: TreeAccessors["rowKey"]) => string;
23
+ /** 取子节点(字段不是数组一律当没有子节点,与 `Tree` 同款宽容) */
24
+ export declare const treeChildren: (node: TreeNode, childrenKey: string) => TreeNode[];
25
+ /** 取标签文本 */
26
+ export declare const treeLabel: (node: TreeNode, labelKey: string) => string;
27
+ /** 按主键在整棵树里找节点(触发器要显示选中节点的名称;找不到时由消费方回退显示原值) */
28
+ export declare function findTreeNode(nodes: TreeNode[], key: string, accessors: Pick<TreeAccessors, 'rowKey' | 'childrenKey'>): TreeNode | undefined;
29
+ export interface TreeFilterOptions extends TreeAccessors {
30
+ /** 关键词(调用方保证非空;空串走「不过滤」那条路,不进本函数) */
31
+ keyword: string;
32
+ /** 自定义命中判定(缺省:标签**区分大小写**地包含关键词 —— 与 `Select` 的缺省过滤同口径) */
33
+ match?: (node: TreeNode, keyword: string) => boolean;
34
+ }
35
+ export interface TreeFilterResult {
36
+ /** 过滤后的树(命中项 + 它们的祖先链;被剪掉的分支不在其中) */
37
+ nodes: TreeNode[];
38
+ /** 结果里出现的**全部**节点 key(含祖先)—— 消费方用它做「过滤态强制全展」 */
39
+ keys: string[];
40
+ }
41
+ /**
42
+ * 过滤树。三条规则(**父命中即整支可见**,与「搜到的域要连带其下所有条目」的直觉一致):
43
+ *
44
+ * 1. 节点**自身命中** → 保留它**及其整棵子树**(子树原引用,不改数据);
45
+ * 2. 自身未命中但**后代有命中** → 保留该节点 + 递归过滤后的子树(即**保留祖先链**);
46
+ * 3. 整支无命中 → 剪掉。
47
+ *
48
+ * 复杂度 O(N)(每个节点只看一次),只在关键词或数据变化时由 `computed` 触发。
49
+ */
50
+ export declare function filterTreeNodes(nodes: TreeNode[], options: TreeFilterOptions): TreeFilterResult;
51
+ /** 命中切分的一段:`hit` 为真时由面层给底色(`.mh-select__hit`) */
52
+ export interface HitSegment {
53
+ text: string;
54
+ hit: boolean;
55
+ }
56
+ /**
57
+ * 把标签文本按关键词切成「命中 / 未命中」交替的片段(**全部**出现位置都切,不只第一处)。
58
+ *
59
+ * 关键词为空、或压根没命中时返回**一整段未命中**(消费方据此仍能渲染出原文,不必分情况)。
60
+ */
61
+ export declare function splitHighlight(text: string, keyword: string): HitSegment[];
@@ -0,0 +1,63 @@
1
+ const treeNodeKey = (node, rowKey) => typeof rowKey === "function" ? rowKey(node) : String(node[rowKey] ?? "");
2
+ const treeChildren = (node, childrenKey) => {
3
+ const children = node[childrenKey];
4
+ return Array.isArray(children) ? children : [];
5
+ };
6
+ const treeLabel = (node, labelKey) => String(node[labelKey] ?? "");
7
+ function findTreeNode(nodes, key, accessors) {
8
+ for (const node of nodes) {
9
+ if (treeNodeKey(node, accessors.rowKey) === key) return node;
10
+ const found = findTreeNode(treeChildren(node, accessors.childrenKey), key, accessors);
11
+ if (found) return found;
12
+ }
13
+ return void 0;
14
+ }
15
+ function filterTreeNodes(nodes, options) {
16
+ const hit = (node) => options.match ? options.match(node, options.keyword) : treeLabel(node, options.labelKey).includes(options.keyword);
17
+ const keys = [];
18
+ const collectKeys = (node) => {
19
+ keys.push(treeNodeKey(node, options.rowKey));
20
+ for (const child of treeChildren(node, options.childrenKey)) collectKeys(child);
21
+ };
22
+ const walk = (list) => {
23
+ const kept = [];
24
+ for (const node of list) {
25
+ if (hit(node)) {
26
+ collectKeys(node);
27
+ kept.push(node);
28
+ continue;
29
+ }
30
+ keys.push(treeNodeKey(node, options.rowKey));
31
+ const keptChildren = walk(treeChildren(node, options.childrenKey));
32
+ if (keptChildren.length) {
33
+ kept.push({ ...node, [options.childrenKey]: keptChildren });
34
+ } else {
35
+ keys.pop();
36
+ }
37
+ }
38
+ return kept;
39
+ };
40
+ return { nodes: walk(nodes), keys };
41
+ }
42
+ function splitHighlight(text, keyword) {
43
+ if (!keyword) return [{ text, hit: false }];
44
+ const segments = [];
45
+ let cursor = 0;
46
+ for (; ; ) {
47
+ const at = text.indexOf(keyword, cursor);
48
+ if (at < 0) break;
49
+ if (at > cursor) segments.push({ text: text.slice(cursor, at), hit: false });
50
+ segments.push({ text: text.slice(at, at + keyword.length), hit: true });
51
+ cursor = at + keyword.length;
52
+ }
53
+ if (cursor < text.length) segments.push({ text: text.slice(cursor), hit: false });
54
+ return segments.length ? segments : [{ text, hit: false }];
55
+ }
56
+ export {
57
+ filterTreeNodes,
58
+ findTreeNode,
59
+ splitHighlight,
60
+ treeChildren,
61
+ treeLabel,
62
+ treeNodeKey
63
+ };
@@ -0,0 +1,274 @@
1
+ /**
2
+ * SelectTree —— **树选择**(`Select` 的树形态,与它平级导出:`import { SelectTree } from '@manohub/ui'`)。
3
+ *
4
+ * 它与 `Select` 共用**同一批内件**:触发器(像输入框 / 清除位 / 箭头 / 键盘开面板)、
5
+ * 面板壳(皮肤 / 定位档 / 显式锚 / 搜索行)、共用原子(面板 id / popover 开合 / 键盘契约)。
6
+ * 所以「面板长相与开合行为」两件只有一份规格;本件独有的只有**树体那一层**:
7
+ *
8
+ * 1. **仅叶子可选**:点叶子行即选中并收起面板;点父节点行只切换展开(不产生选中值)——
9
+ * 父节点是「分组」而不是「选项」,选中它语义上是空的(`Tree` 自身不做这个判断,故在此兜住)。
10
+ * 2. **本地过滤树**:搜索行在场时按关键词过滤,命中节点的**祖先链保留**、父节点自身命中则
11
+ * **整支保留**,并强制全展到命中层(算法与切分都是纯函数,见 `select-tree-filter.ts`);
12
+ * 命中文本按面层的 `.mh-select__hit` 高亮(靠 `Tree` 的可选 `renderLabel` 钩子落进标签槽)。
13
+ * 3. **面板内限高滚动**:树体包在 `.mh-select__tree` 里(内距 + 限高 + 溢出滚动),长树不撑破面板。
14
+ *
15
+ * ## 与 `Select` 的三处有意差异(都是「树不是列表」决定的)
16
+ *
17
+ * | 事项 | `Select` | `SelectTree` |
18
+ * | --- | --- | --- |
19
+ * | 值 | `string \| number \| Array<…>` | 只单选、只 `string`(`Tree` 的主键本就 `String()` 化) |
20
+ * | 面板内 ↑↓ 行导航 | 有(选项是真实 `<button>`,焦点即高亮) | **无**(树的行是 `div`、没有 tabindex;`Tree` 自身也不做键盘导航) |
21
+ * | 空 / 加载态 | 列表体的内建行 | 面板内同样出一行文字(**不复用**整件三态容器:下拉里出空态插画太重) |
22
+ *
23
+ * @example 基础单选
24
+ * <SelectTree nodes={tree} rowKey="id" modelValue={v} onChange={setV} placeholder="请选择业务域" />
25
+ *
26
+ * @example 搜索 + 默认全展开
27
+ * <SelectTree nodes={tree} rowKey="id" labelKey="name" searchable defaultExpandAll onChange={setV} />
28
+ */
29
+ import { type PropType, type SlotsType, type VNodeChild } from 'vue';
30
+ import type { ControlSize } from '../control-size';
31
+ import type { InputStatus } from '../input';
32
+ import { type TreeNode } from '../tree';
33
+ export declare const SelectTree: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
34
+ /** 树数据(与 `Tree` 同一个 `TreeNode` 类型,不另造节点形状) */
35
+ nodes: {
36
+ type: PropType<TreeNode[]>;
37
+ required: true;
38
+ };
39
+ /** 节点主键:字段名或取值函数(与 `Tree` 同义) */
40
+ rowKey: {
41
+ type: PropType<string | ((node: TreeNode) => string)>;
42
+ required: true;
43
+ };
44
+ /** 标签字段名(默认 'label') */
45
+ labelKey: {
46
+ type: StringConstructor;
47
+ default: string;
48
+ };
49
+ /** 子节点字段名(默认 'children') */
50
+ childrenKey: {
51
+ type: StringConstructor;
52
+ default: string;
53
+ };
54
+ /** 受控值(选中叶子的主键;树选择只单选) */
55
+ modelValue: {
56
+ type: StringConstructor;
57
+ default: undefined;
58
+ };
59
+ /** 非受控初始值 */
60
+ defaultValue: {
61
+ type: StringConstructor;
62
+ default: undefined;
63
+ };
64
+ placeholder: {
65
+ type: StringConstructor;
66
+ default: string;
67
+ };
68
+ /** 搜索:`true` 强制开;不给时节点总数多于 8 自动开(与 `Select` 同口径) */
69
+ searchable: {
70
+ type: BooleanConstructor;
71
+ default: boolean;
72
+ };
73
+ /** 自定义命中判定(缺省:标签区分大小写地包含关键词) */
74
+ filterNode: {
75
+ type: PropType<(node: TreeNode, keyword: string) => boolean>;
76
+ default: undefined;
77
+ };
78
+ /** 命中文本是否高亮(默认开) */
79
+ highlight: {
80
+ type: BooleanConstructor;
81
+ default: boolean;
82
+ };
83
+ /** 受控展开集(传了就完全受控;**过滤态下组件强制全展**,不受本 prop 约束) */
84
+ expandedKeys: {
85
+ type: PropType<string[]>;
86
+ default: undefined;
87
+ };
88
+ /** 非受控展开初值 */
89
+ defaultExpandedKeys: {
90
+ type: PropType<string[]>;
91
+ default: () => never[];
92
+ };
93
+ /** 初始展开全部(与 `defaultExpandedKeys` 互斥,它优先) */
94
+ defaultExpandAll: {
95
+ type: BooleanConstructor;
96
+ default: boolean;
97
+ };
98
+ /** 展开集变化回调 */
99
+ onExpandChange: {
100
+ type: PropType<(keys: string[]) => void>;
101
+ default: undefined;
102
+ };
103
+ clearable: {
104
+ type: BooleanConstructor;
105
+ default: boolean;
106
+ };
107
+ disabled: {
108
+ type: BooleanConstructor;
109
+ default: boolean;
110
+ };
111
+ /** 加载中(面板里出一行提示,不渲染树) */
112
+ loading: {
113
+ type: BooleanConstructor;
114
+ default: boolean;
115
+ };
116
+ emptyText: {
117
+ type: StringConstructor;
118
+ default: string;
119
+ };
120
+ /** 尺寸档(24 / 28 / 32) */
121
+ size: {
122
+ type: PropType<ControlSize>;
123
+ default: string;
124
+ };
125
+ /** 校验状态(红 / 黄;与 `Input` 同一词表) */
126
+ status: {
127
+ type: PropType<InputStatus>;
128
+ default: undefined;
129
+ };
130
+ /** 值变更回调(选中叶子的主键) */
131
+ onChange: {
132
+ type: PropType<(v: string) => void>;
133
+ default: undefined;
134
+ };
135
+ /** 搜索词变更(远程换数据用;本地过滤不受它影响) */
136
+ onSearch: {
137
+ type: PropType<(keyword: string) => void>;
138
+ default: undefined;
139
+ };
140
+ }>, () => import("vue/jsx-runtime").JSX.Element, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
141
+ 'update:modelValue': (v: string) => true;
142
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
143
+ /** 树数据(与 `Tree` 同一个 `TreeNode` 类型,不另造节点形状) */
144
+ nodes: {
145
+ type: PropType<TreeNode[]>;
146
+ required: true;
147
+ };
148
+ /** 节点主键:字段名或取值函数(与 `Tree` 同义) */
149
+ rowKey: {
150
+ type: PropType<string | ((node: TreeNode) => string)>;
151
+ required: true;
152
+ };
153
+ /** 标签字段名(默认 'label') */
154
+ labelKey: {
155
+ type: StringConstructor;
156
+ default: string;
157
+ };
158
+ /** 子节点字段名(默认 'children') */
159
+ childrenKey: {
160
+ type: StringConstructor;
161
+ default: string;
162
+ };
163
+ /** 受控值(选中叶子的主键;树选择只单选) */
164
+ modelValue: {
165
+ type: StringConstructor;
166
+ default: undefined;
167
+ };
168
+ /** 非受控初始值 */
169
+ defaultValue: {
170
+ type: StringConstructor;
171
+ default: undefined;
172
+ };
173
+ placeholder: {
174
+ type: StringConstructor;
175
+ default: string;
176
+ };
177
+ /** 搜索:`true` 强制开;不给时节点总数多于 8 自动开(与 `Select` 同口径) */
178
+ searchable: {
179
+ type: BooleanConstructor;
180
+ default: boolean;
181
+ };
182
+ /** 自定义命中判定(缺省:标签区分大小写地包含关键词) */
183
+ filterNode: {
184
+ type: PropType<(node: TreeNode, keyword: string) => boolean>;
185
+ default: undefined;
186
+ };
187
+ /** 命中文本是否高亮(默认开) */
188
+ highlight: {
189
+ type: BooleanConstructor;
190
+ default: boolean;
191
+ };
192
+ /** 受控展开集(传了就完全受控;**过滤态下组件强制全展**,不受本 prop 约束) */
193
+ expandedKeys: {
194
+ type: PropType<string[]>;
195
+ default: undefined;
196
+ };
197
+ /** 非受控展开初值 */
198
+ defaultExpandedKeys: {
199
+ type: PropType<string[]>;
200
+ default: () => never[];
201
+ };
202
+ /** 初始展开全部(与 `defaultExpandedKeys` 互斥,它优先) */
203
+ defaultExpandAll: {
204
+ type: BooleanConstructor;
205
+ default: boolean;
206
+ };
207
+ /** 展开集变化回调 */
208
+ onExpandChange: {
209
+ type: PropType<(keys: string[]) => void>;
210
+ default: undefined;
211
+ };
212
+ clearable: {
213
+ type: BooleanConstructor;
214
+ default: boolean;
215
+ };
216
+ disabled: {
217
+ type: BooleanConstructor;
218
+ default: boolean;
219
+ };
220
+ /** 加载中(面板里出一行提示,不渲染树) */
221
+ loading: {
222
+ type: BooleanConstructor;
223
+ default: boolean;
224
+ };
225
+ emptyText: {
226
+ type: StringConstructor;
227
+ default: string;
228
+ };
229
+ /** 尺寸档(24 / 28 / 32) */
230
+ size: {
231
+ type: PropType<ControlSize>;
232
+ default: string;
233
+ };
234
+ /** 校验状态(红 / 黄;与 `Input` 同一词表) */
235
+ status: {
236
+ type: PropType<InputStatus>;
237
+ default: undefined;
238
+ };
239
+ /** 值变更回调(选中叶子的主键) */
240
+ onChange: {
241
+ type: PropType<(v: string) => void>;
242
+ default: undefined;
243
+ };
244
+ /** 搜索词变更(远程换数据用;本地过滤不受它影响) */
245
+ onSearch: {
246
+ type: PropType<(keyword: string) => void>;
247
+ default: undefined;
248
+ };
249
+ }>> & Readonly<{
250
+ "onUpdate:modelValue"?: ((v: string) => any) | undefined;
251
+ }>, {
252
+ size: ControlSize;
253
+ disabled: boolean;
254
+ onChange: (v: string) => void;
255
+ loading: boolean;
256
+ labelKey: string;
257
+ childrenKey: string;
258
+ expandedKeys: string[];
259
+ defaultExpandedKeys: string[];
260
+ defaultExpandAll: boolean;
261
+ onExpandChange: (keys: string[]) => void;
262
+ defaultValue: string;
263
+ placeholder: string;
264
+ modelValue: string;
265
+ status: InputStatus;
266
+ clearable: boolean;
267
+ onSearch: (keyword: string) => void;
268
+ emptyText: string;
269
+ searchable: boolean;
270
+ filterNode: (node: TreeNode, keyword: string) => boolean;
271
+ highlight: boolean;
272
+ }, SlotsType<{
273
+ empty?: () => VNodeChild;
274
+ }>, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;