@ticatec/uniface-element 0.1.45 → 0.1.47

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.
@@ -49,9 +49,11 @@
49
49
  <slot name="header"></slot>
50
50
  </div>
51
51
  <div style="height: 100%; flex: 1 1 auto; overflow: hidden; display: flex; flex-direction: row; position: relative">
52
- <div bind:this={sidebar} style="width: 100%; flex: 0 0 auto; overflow: auto; width: {sidebarWidth}; {minWidth} {maxWidth}">
53
- <slot name="sidebar"></slot>
54
- </div>
52
+ {#if sidebar}
53
+ <div bind:this={sidebar} style="width: 100%; flex: 0 0 auto; overflow: auto; width: {sidebarWidth}; {minWidth} {maxWidth}">
54
+ <slot name="sidebar"></slot>
55
+ </div>
56
+ {/if}
55
57
  {#if sidebarResize}
56
58
  <Split direction="vertical" bindingPanel={sidebar}/>
57
59
  {/if}
@@ -62,7 +64,8 @@
62
64
  {#if sidebarResize}
63
65
  <Split direction="vertical" bindingPanel={rightBar} reverse/>
64
66
  {/if}
65
- <div bind:this={rightBar} style="width: 100%; flex: 0 0 auto; overflow: auto; width: {rightBarWidth}; {rightMinWidth} {rightMaxWidth}">
67
+ <div bind:this={rightBar}
68
+ style="width: 100%; flex: 0 0 auto; overflow: auto; width: {rightBarWidth}; {rightMinWidth} {rightMaxWidth}">
66
69
  <slot name="right-sidebar"></slot>
67
70
  </div>
68
71
  {/if}
@@ -0,0 +1,88 @@
1
+ export declare function compareNumber(a: number, b: number): 0 | 1 | -1;
2
+ export type TreeNode<T> = {
3
+ item: T;
4
+ expand?: boolean;
5
+ children?: TreeNode<T>[];
6
+ };
7
+ export type CheckIsRoot<T> = (data: T) => boolean;
8
+ export type CompareFun<T> = (o1: T, o2: T) => number | undefined;
9
+ export type GetText<T> = (data: T) => string;
10
+ export type CheckIsDirectory<T> = (node: TreeNode<T>) => boolean;
11
+ export interface TreeNodeOptions<T> {
12
+ keyField?: keyof T;
13
+ textField?: keyof T | GetText<T>;
14
+ parentKeyField?: keyof T;
15
+ checkIsRoot: CheckIsRoot<T>;
16
+ checkIsDirectory?: CheckIsDirectory<T>;
17
+ compareFun?: CompareFun<T>;
18
+ expendDepth?: number;
19
+ }
20
+ export declare class CommonTreeNodes<T> {
21
+ protected readonly checkIsRoot: CheckIsRoot<T>;
22
+ protected readonly keyField: keyof T;
23
+ protected readonly parentKeyField: keyof T;
24
+ protected readonly textField: keyof T | GetText<T>;
25
+ protected readonly checkIsDirectory: CheckIsDirectory<T> | undefined;
26
+ protected nodeMap: Map<any, TreeNode<T>>;
27
+ protected compareFun: any | undefined;
28
+ protected expendDepth: number;
29
+ protected _nodes: Array<TreeNode<T>>;
30
+ constructor(options: TreeNodeOptions<T>);
31
+ setData(list: Array<T>): void;
32
+ /**
33
+ * 获取节点
34
+ */
35
+ get nodes(): Array<TreeNode<T>>;
36
+ /**
37
+ * 设置展开层级
38
+ * @param nodes
39
+ * @param currentLevel
40
+ * @protected
41
+ */
42
+ protected setExpandForDepth(nodes: TreeNode<T>[], currentLevel: number): void;
43
+ /**
44
+ * 添加一个节点
45
+ * @param node
46
+ * @param doSort
47
+ * @protected
48
+ */
49
+ protected appendNode(node: TreeNode<T>, doSort?: boolean): void;
50
+ }
51
+ export default class TreeNodes<T> extends CommonTreeNodes<T> {
52
+ /**
53
+ * 获取展开的展示列表
54
+ */
55
+ getHierarchyList(): Array<TreeNode<T>>;
56
+ /**
57
+ * 给treeview设定数据,根据数据构建树结构
58
+ * @param list
59
+ */
60
+ /**
61
+ * 增加一个新节点
62
+ * @param item
63
+ */
64
+ append(item: T): void;
65
+ /**
66
+ * 替换一个节点的数据
67
+ * @param item
68
+ */
69
+ replace(item: T): void;
70
+ remove(item: T): void;
71
+ /**
72
+ * 将一个节点移动到另外一个节点下
73
+ * @param item
74
+ * @param parentId
75
+ */
76
+ moveTo(item: T, parentId: string): void;
77
+ /**
78
+ * 获取除指定节点外的其他节点
79
+ * @param exclusiveData
80
+ */
81
+ extractDirectories(exclusiveData: T): TreeNode<T>[];
82
+ /**
83
+ * 获取所有展开的节点
84
+ * @param tree
85
+ * @private
86
+ */
87
+ private collectExpandedNodes;
88
+ }
@@ -0,0 +1,202 @@
1
+ export function compareNumber(a, b) {
2
+ return a === b ? 0 : a > b ? 1 : -1;
3
+ }
4
+ export class CommonTreeNodes {
5
+ checkIsRoot;
6
+ keyField;
7
+ parentKeyField;
8
+ textField;
9
+ checkIsDirectory;
10
+ nodeMap;
11
+ compareFun;
12
+ expendDepth;
13
+ _nodes = [];
14
+ constructor(options) {
15
+ this.checkIsRoot = options.checkIsRoot;
16
+ this.compareFun = options.compareFun;
17
+ this.keyField = options.keyField ?? 'id';
18
+ this.textField = options.textField ?? 'text';
19
+ this.parentKeyField = options.parentKeyField ?? 'parentId';
20
+ this.nodeMap = new Map();
21
+ this.expendDepth = options.expendDepth ?? 1;
22
+ this.checkIsDirectory = options.checkIsDirectory;
23
+ }
24
+ setData(list) {
25
+ this.nodeMap = new Map();
26
+ this._nodes = [];
27
+ // 初始化每个节点
28
+ for (const item of list) {
29
+ const node = {
30
+ item,
31
+ expand: false
32
+ };
33
+ const key = item[this.keyField];
34
+ this.nodeMap.set(key, node);
35
+ }
36
+ for (const item of list) {
37
+ const node = this.nodeMap.get(item[this.keyField]);
38
+ if (node) {
39
+ this.appendNode(node);
40
+ }
41
+ }
42
+ if (this.expendDepth > 1) {
43
+ this.setExpandForDepth(this.nodes, 0);
44
+ }
45
+ }
46
+ /**
47
+ * 获取节点
48
+ */
49
+ get nodes() {
50
+ return this._nodes;
51
+ }
52
+ /**
53
+ * 设置展开层级
54
+ * @param nodes
55
+ * @param currentLevel
56
+ * @protected
57
+ */
58
+ setExpandForDepth(nodes, currentLevel) {
59
+ for (const node of nodes) {
60
+ node.expand = currentLevel < this.expendDepth;
61
+ if (node.children) {
62
+ this.setExpandForDepth(node.children, currentLevel + 1);
63
+ }
64
+ }
65
+ }
66
+ /**
67
+ * 添加一个节点
68
+ * @param node
69
+ * @param doSort
70
+ * @protected
71
+ */
72
+ appendNode(node, doSort = false) {
73
+ let item = node.item;
74
+ const parentKey = item[this.parentKeyField];
75
+ if (this.checkIsRoot(item)) { //|| !this.nodeMap.has(parentKey)
76
+ this._nodes.push(node);
77
+ }
78
+ else {
79
+ const parentNode = this.nodeMap.get(parentKey);
80
+ if (parentNode) {
81
+ parentNode.expand = true;
82
+ parentNode.children = [...(parentNode.children ?? []), node];
83
+ if (doSort && this.compareFun) {
84
+ parentNode.children = parentNode.children.sort(this.compareFun);
85
+ }
86
+ }
87
+ else {
88
+ console.warn('Ignore the isolate item:', item);
89
+ }
90
+ }
91
+ }
92
+ }
93
+ export default class TreeNodes extends CommonTreeNodes {
94
+ /**
95
+ * 获取展开的展示列表
96
+ */
97
+ getHierarchyList() {
98
+ return this.collectExpandedNodes(this._nodes);
99
+ }
100
+ /**
101
+ * 给treeview设定数据,根据数据构建树结构
102
+ * @param list
103
+ */
104
+ /**
105
+ * 增加一个新节点
106
+ * @param item
107
+ */
108
+ append(item) {
109
+ const node = {
110
+ item,
111
+ expand: true
112
+ };
113
+ this.appendNode(node, true);
114
+ this.nodeMap.set(item[this.keyField], node);
115
+ }
116
+ /**
117
+ * 替换一个节点的数据
118
+ * @param item
119
+ */
120
+ replace(item) {
121
+ let node = this.nodeMap.get(item[this.keyField]);
122
+ if (node) {
123
+ node.item = item;
124
+ let parent = this.nodeMap.get(item[this.parentKeyField]);
125
+ if (parent && parent.children && parent.children.length > 0) {
126
+ parent.children = parent.children.sort(this.compareFun);
127
+ }
128
+ }
129
+ }
130
+ remove(item) {
131
+ let idKey = item[this.keyField];
132
+ let node = this.nodeMap.get(idKey);
133
+ if (node) {
134
+ let parent = this.nodeMap.get(node.item[this.parentKeyField]);
135
+ this.nodeMap.delete(idKey);
136
+ if (parent && parent.children) {
137
+ let pos = parent.children.findIndex(el => el.item[this.keyField] == idKey);
138
+ if (pos > -1) {
139
+ parent.children.splice(pos, 1);
140
+ }
141
+ }
142
+ }
143
+ }
144
+ /**
145
+ * 将一个节点移动到另外一个节点下
146
+ * @param item
147
+ * @param parentId
148
+ */
149
+ moveTo(item, parentId) {
150
+ let newParent = this.nodeMap.get(parentId);
151
+ let node = this.nodeMap.get(item[this.keyField]);
152
+ let currentParent = this.nodeMap.get(item[this.parentKeyField]);
153
+ if (newParent && node && currentParent && currentParent.children) {
154
+ let pos = currentParent.children.findIndex(el => el.item[this.keyField] == item[this.keyField]);
155
+ if (pos > -1) {
156
+ currentParent.children.splice(pos, 1);
157
+ }
158
+ newParent.children = [...(newParent.children ?? []), node];
159
+ if (this.compareFun) {
160
+ newParent.children = newParent.children.sort(this.compareFun);
161
+ }
162
+ }
163
+ }
164
+ /**
165
+ * 获取除指定节点外的其他节点
166
+ * @param exclusiveData
167
+ */
168
+ extractDirectories(exclusiveData) {
169
+ const getNodes = (nodes, item) => {
170
+ let list = [];
171
+ for (let node of nodes) {
172
+ if (node.item != item && this.checkIsDirectory?.(node)) {
173
+ list.push({
174
+ item: node.item,
175
+ expand: true,
176
+ children: getNodes(node.children ?? [], item)
177
+ });
178
+ }
179
+ }
180
+ return list;
181
+ };
182
+ return getNodes(this.nodes, exclusiveData);
183
+ }
184
+ /**
185
+ * 获取所有展开的节点
186
+ * @param tree
187
+ * @private
188
+ */
189
+ collectExpandedNodes(tree) {
190
+ const result = [];
191
+ function traverse(nodes) {
192
+ for (const node of nodes) {
193
+ result.push(node);
194
+ if (node.expand && node.children) {
195
+ traverse(node.children);
196
+ }
197
+ }
198
+ }
199
+ traverse(tree);
200
+ return result;
201
+ }
202
+ }
@@ -0,0 +1,9 @@
1
+ import TreeNodes from "./TreeNodes";
2
+ import type { TreeNode } from "./TreeNodes";
3
+ import { CommonTreeNodes } from "./TreeNodes";
4
+ import type { CheckIsRoot, CompareFun, GetText, CheckIsDirectory, TreeNodeOptions } from "./TreeNodes";
5
+ import { compareNumber } from "./TreeNodes";
6
+ export default TreeNodes;
7
+ export { CommonTreeNodes, compareNumber };
8
+ export type { TreeNode };
9
+ export type { CheckIsRoot, CompareFun, GetText, CheckIsDirectory, TreeNodeOptions };
@@ -0,0 +1,5 @@
1
+ import TreeNodes from "./TreeNodes";
2
+ import { CommonTreeNodes } from "./TreeNodes";
3
+ import { compareNumber } from "./TreeNodes";
4
+ export default TreeNodes;
5
+ export { CommonTreeNodes, compareNumber };
@@ -1,27 +1,4 @@
1
- export default interface MenuItem {
2
- /**
3
- * 菜单编码
4
- */
5
- code?: string;
6
- /**
7
- * 菜单文字
8
- */
9
- text: string;
10
- /**
11
- * 用于i18n的key
12
- */
13
- key?: string;
14
- /**
15
- * 绑定数据,用户处理,通常为uri的跳转地址
16
- */
17
- data?: any;
18
- /**
19
- * 子菜单项
20
- */
21
- children?: Array<MenuItem>;
22
- /**
23
- * 是否打开
24
- */
25
- expand?: boolean;
1
+ import type { TreeNode } from "../lib/TreeNodes";
2
+ export default interface MenuItem extends TreeNode<any> {
26
3
  }
27
4
  export type OnMenuClick = (item: MenuItem) => void;
@@ -0,0 +1,8 @@
1
+ import { CommonTreeNodes } from "../lib/TreeNodes";
2
+ import type MenuItem from "./MenuItem";
3
+ export declare class Menus extends CommonTreeNodes<MenuItem> {
4
+ /**
5
+ * 删除所有没有子节点的目录类型节点
6
+ */
7
+ removeEmptyDirectory(): void;
8
+ }
@@ -0,0 +1,23 @@
1
+ import { CommonTreeNodes } from "../lib/TreeNodes";
2
+ export class Menus extends CommonTreeNodes {
3
+ /**
4
+ * 删除所有没有子节点的目录类型节点
5
+ */
6
+ removeEmptyDirectory() {
7
+ const removeRecursive = (nodes) => {
8
+ for (let i = nodes.length - 1; i >= 0; i--) {
9
+ const node = nodes[i];
10
+ if (node.children && node.children.length > 0) {
11
+ removeRecursive(node.children); // 先处理子节点
12
+ }
13
+ else {
14
+ if (this.checkIsDirectory?.(node)) {
15
+ nodes.splice(i, 1); // 从父节点的 children 中移除
16
+ this.nodeMap.delete(node.item[this.keyField]); // 从 nodeMap 中移除
17
+ }
18
+ }
19
+ }
20
+ };
21
+ removeRecursive(this._nodes);
22
+ }
23
+ }
@@ -2,20 +2,25 @@
2
2
  import type MenuItem from "./MenuItem";
3
3
  import type {OnMenuClick} from "./MenuItem";
4
4
  import NavigatorMenuItem from "./NavigatorMenuItem.svelte";
5
+ import type {GetText} from "../lib/TreeNodes";
5
6
 
6
7
  export let menuItems: Array<MenuItem>;
7
8
  export let style: string = '';
9
+
10
+ export let textField: string | GetText<MenuItem>;
11
+
8
12
  export let onItemClick: OnMenuClick;
9
13
 
10
14
 
15
+
11
16
  </script>
12
17
 
13
18
 
14
19
  <div class="uniface-navigator-menu-panel" {style}>
15
20
  {#if menuItems && menuItems.length > 0}
16
21
  <ul>
17
- {#each menuItems as item}
18
- <NavigatorMenuItem {item} onMenuItemClick={onItemClick} expand={item.expand}/>
22
+ {#each menuItems as menu}
23
+ <NavigatorMenuItem {menu} onMenuItemClick={onItemClick} {textField}/>
19
24
  {/each}
20
25
  </ul>
21
26
  {/if}
@@ -1,5 +1,6 @@
1
1
  import type MenuItem from "./MenuItem";
2
2
  import type { OnMenuClick } from "./MenuItem";
3
+ import type { GetText } from "../lib/TreeNodes";
3
4
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
4
5
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
5
6
  $$bindings?: Bindings;
@@ -16,6 +17,7 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
16
17
  declare const NavigatorMenu: $$__sveltets_2_IsomorphicComponent<{
17
18
  menuItems: Array<MenuItem>;
18
19
  style?: string;
20
+ textField: string | GetText<MenuItem>;
19
21
  onItemClick: OnMenuClick;
20
22
  }, {
21
23
  [evt: string]: CustomEvent<any>;
@@ -3,19 +3,17 @@
3
3
  import {slide} from "svelte/transition";
4
4
  import type MenuItem from "./MenuItem";
5
5
  import type {OnMenuClick} from "./MenuItem";
6
- import i18n from "@ticatec/i18n";
6
+ import type {GetText} from "../lib/TreeNodes";
7
7
 
8
- export let item: MenuItem;
9
- export let expand: boolean = false;
10
-
11
- export let onMenuItemClick: OnMenuClick;
8
+ export let menu: MenuItem;
9
+ export let textField: string | GetText<MenuItem>;
12
10
 
11
+ let expand: boolean = menu.expand == true;
13
12
 
14
- let expandable: boolean;
13
+ export let onMenuItemClick: OnMenuClick;
15
14
 
16
- $: {
17
- expandable = item.children != null && item.children.length > 0
18
- }
15
+ $: expandable = menu.children != null && menu.children.length > 0
16
+ $: menuText = typeof textField == 'string' ? menu.item?.[textField]??'Unknown item' : textField(menu.item);
19
17
 
20
18
  let respond: boolean = true;
21
19
  const handleMenuItemClick = () => {
@@ -23,10 +21,10 @@
23
21
  respond = false;
24
22
  setTimeout(() => respond = true, 200);
25
23
  if (expandable) {
26
- item.expand = !item.expand;
24
+ menu.expand = !menu.expand;
27
25
  expand = !expand;
28
26
  } else {
29
- onMenuItemClick?.(item);
27
+ onMenuItemClick?.(menu);
30
28
  }
31
29
  }
32
30
 
@@ -34,12 +32,12 @@
34
32
 
35
33
  </script>
36
34
  <li class:expandable class:fold={!expand}>
37
- <span on:click={handleMenuItemClick} aria-hidden="true">{item.key ? i18n.getText(item.key, item.text) : item.text}</span>
38
- {#if item.children}
35
+ <span on:click={handleMenuItemClick} aria-hidden="true">{menuText}</span>
36
+ {#if menu.children}
39
37
  {#if expand}
40
38
  <ul transition:slide={{duration: 200}}>
41
- {#each item.children as el}
42
- <svelte:self item={el} {onMenuItemClick}/>
39
+ {#each menu.children as el}
40
+ <svelte:self menu={el} {onMenuItemClick} {textField}/>
43
41
  {/each}
44
42
  </ul>
45
43
  {/if}
@@ -1,5 +1,6 @@
1
1
  import type MenuItem from "./MenuItem";
2
2
  import type { OnMenuClick } from "./MenuItem";
3
+ import type { GetText } from "../lib/TreeNodes";
3
4
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
4
5
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
5
6
  $$bindings?: Bindings;
@@ -14,8 +15,8 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
14
15
  z_$$bindings?: Bindings;
15
16
  }
16
17
  declare const NavigatorMenuItem: $$__sveltets_2_IsomorphicComponent<{
17
- item: MenuItem;
18
- expand?: boolean;
18
+ menu: MenuItem;
19
+ textField: string | GetText<MenuItem>;
19
20
  onMenuItemClick: OnMenuClick;
20
21
  }, {
21
22
  [evt: string]: CustomEvent<any>;
@@ -1,25 +1,26 @@
1
1
  <script lang="ts">
2
- import type TreeNode from "./TreeNode";
3
- import type {LazyLoader, NodeVisibleFun, OnNodeSelectionChange} from "./TreeNode";
2
+
3
+ import type {LazyLoader, NodeVisibleFun, OnNodeSelectionChange} from "./Types";
4
4
  import iconLoading from "../assets/loading.gif"
5
5
  import utils from "../common/utils";
6
6
  import type {OnContextMenu} from "../context-menu/ContextMenuItem";
7
+ import type {CheckIsDirectory, GetText, TreeNode} from "../lib/TreeNodes";
7
8
 
8
- export let node: TreeNode;
9
+ export let node: TreeNode<any>;
10
+ export let textField: string | GetText<any>;
9
11
  export let lazyLoader: LazyLoader | null;
10
12
  export let activeNode: any;
11
13
  export let isVisible: NodeVisibleFun;
12
- export let level: number = 1;
13
- export let dispLevels: number = 1;
14
14
  export let onContextMenu: OnContextMenu;
15
15
  export let onNodeSelectionChange: OnNodeSelectionChange;
16
16
 
17
+ export let checkIsDirectory: CheckIsDirectory<TreeNode<any>>;
17
18
 
18
- let expanded: boolean = dispLevels <= level;
19
19
  let loading: boolean = false;
20
20
 
21
- const isBranch = () => {
22
- return lazyLoader == null ? (node.children && node.children.length > 0) : lazyLoader.isBranch(node);
21
+ const isDirectory = () => {
22
+ console.log('检测目录函数', checkIsDirectory);
23
+ return lazyLoader == null ? checkIsDirectory?.(node) : lazyLoader.isBranch(node);
23
24
  }
24
25
 
25
26
  const loadChildren = async () => {
@@ -38,11 +39,13 @@
38
39
  e.preventDefault();
39
40
  if (respond) {
40
41
  respond = false;
41
- if (isBranch()) {
42
- expanded = !expanded;
43
- await loadChildren();
42
+ if (isDirectory()) {
43
+ if (!node.children) {
44
+ node.expand = false;
45
+ await loadChildren();
46
+ }
47
+ node.expand = !node.expand;
44
48
  }
45
- dispLevels = expanded ? level + 1 : level;
46
49
  await utils.sleep(0.2);
47
50
  respond = true;
48
51
  }
@@ -58,7 +61,6 @@
58
61
  }
59
62
  }
60
63
 
61
- $: expanded = dispLevels > level;
62
64
 
63
65
  const handleContextMenu = (event: MouseEvent) => {
64
66
  onContextMenu?.(event, node);
@@ -68,25 +70,25 @@
68
70
 
69
71
 
70
72
  {#if isVisible == null || isVisible(node)}
71
- <div class="tree-node" class:expanded>
73
+ <div class="tree-node" class:expanded={node.expand}>
72
74
  <div class="node-item" class:selected={activeNode===node} on:click={handleNodeClick} aria-hidden="true"
73
75
  on:contextmenu={handleContextMenu}>
74
76
  <div class="item-icon">
75
- {#if isBranch()}
77
+ {#if isDirectory()}
76
78
  {#if loading}
77
79
  <img alt="" style="cursor: default" src={iconLoading}/>
78
80
  {:else }
79
- <span aria-hidden="true" on:click={handleNodeIconClick}>{expanded ? '▼' : '▶'}</span>
81
+ <span aria-hidden="true" on:click={handleNodeIconClick}>{node.expand ? '▼' : '▶'}</span>
80
82
  {/if}
81
83
  {/if}
82
84
  </div>
83
- <span class="item-text">{node.text}</span>
85
+ <span class="item-text">{typeof textField == "string" ? node.item[textField] : textField(node.item)}</span>
84
86
  </div>
85
- {#if expanded && node.children}
87
+ {#if node.expand && node.children}
86
88
  <div class="sub-tree">
87
89
  {#each node.children as child}
88
- <svelte:self node={child} {lazyLoader} {onContextMenu}
89
- {dispLevels} {isVisible} level={level+1} {activeNode} {onNodeSelectionChange}/>
90
+ <svelte:self node={child} {lazyLoader} {onContextMenu} {textField} {checkIsDirectory}
91
+ {isVisible} {activeNode} {onNodeSelectionChange}/>
90
92
  {/each}
91
93
  </div>
92
94
  {/if}
@@ -1,6 +1,6 @@
1
- import type TreeNode from "./TreeNode";
2
- import type { LazyLoader, NodeVisibleFun, OnNodeSelectionChange } from "./TreeNode";
1
+ import type { LazyLoader, NodeVisibleFun, OnNodeSelectionChange } from "./Types";
3
2
  import type { OnContextMenu } from "../context-menu/ContextMenuItem";
3
+ import type { CheckIsDirectory, GetText, TreeNode } from "../lib/TreeNodes";
4
4
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
5
5
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
6
6
  $$bindings?: Bindings;
@@ -15,14 +15,14 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
15
15
  z_$$bindings?: Bindings;
16
16
  }
17
17
  declare const TreeNodeView: $$__sveltets_2_IsomorphicComponent<{
18
- node: TreeNode;
18
+ node: TreeNode<any>;
19
+ textField: string | GetText<any>;
19
20
  lazyLoader: LazyLoader | null;
20
21
  activeNode: any;
21
22
  isVisible: NodeVisibleFun;
22
- level?: number;
23
- dispLevels?: number;
24
23
  onContextMenu: OnContextMenu;
25
24
  onNodeSelectionChange: OnNodeSelectionChange;
25
+ checkIsDirectory: CheckIsDirectory<TreeNode<any>>;
26
26
  }, {
27
27
  [evt: string]: CustomEvent<any>;
28
28
  }, {}, {}, string>;
@@ -1,12 +1,14 @@
1
1
  <script lang="ts">
2
2
 
3
- import type TreeNode from "./TreeNode";
4
- import type {LazyLoader, NodeVisibleFun, OnNodeSelectionChange} from "./TreeNode";
3
+
4
+ import type {LazyLoader, NodeVisibleFun, OnNodeSelectionChange} from "./Types";
5
5
  import TreeNodeView from "./TreeNodeView.svelte";
6
6
  import type {OnContextMenu} from "../context-menu/ContextMenuItem";
7
+ import type {CheckIsDirectory, GetText, TreeNode} from "../lib/TreeNodes";
7
8
 
8
9
 
9
- export let nodes: Array<TreeNode>;
10
+ export let nodes: Array<TreeNode<any>>;
11
+ export let textField: string | GetText<any>;
10
12
  export let style: string = "";
11
13
  export let lazyLoader: LazyLoader | null = null;
12
14
  export let activeNode: any = null;
@@ -14,10 +16,10 @@
14
16
  export let isVisible: NodeVisibleFun = null as unknown as NodeVisibleFun;
15
17
  export let onSelectionChange: OnNodeSelectionChange = null as unknown as OnNodeSelectionChange;
16
18
  export let onContextMenu: OnContextMenu = null as unknown as OnContextMenu;
17
-
19
+ export let checkIsDirectory: CheckIsDirectory<any>;
18
20
  let className: string = "";
19
21
 
20
- const onNodeSelectionChange = async (node: TreeNode): Promise<boolean> => {
22
+ const onNodeSelectionChange = async (node: TreeNode<any>): Promise<boolean> => {
21
23
  let accept: boolean = (await onSelectionChange?.(node));
22
24
  accept = accept == null ? true : accept;
23
25
  if (accept == null || accept == true) {
@@ -30,7 +32,7 @@
30
32
  <div class="uniface-tree-view {className}" {style}>
31
33
  <div>
32
34
  {#each nodes as node}
33
- <TreeNodeView {activeNode} {node} {lazyLoader} {isVisible} {onNodeSelectionChange} {onContextMenu}/>
35
+ <TreeNodeView {activeNode} {node} {textField} {lazyLoader} {onNodeSelectionChange} {isVisible} {checkIsDirectory} {onContextMenu}/>
34
36
  {/each}
35
37
  </div>
36
38
  </div>
@@ -1,6 +1,6 @@
1
- import type TreeNode from "./TreeNode";
2
- import type { LazyLoader, NodeVisibleFun, OnNodeSelectionChange } from "./TreeNode";
1
+ import type { LazyLoader, NodeVisibleFun, OnNodeSelectionChange } from "./Types";
3
2
  import type { OnContextMenu } from "../context-menu/ContextMenuItem";
3
+ import type { CheckIsDirectory, GetText, TreeNode } from "../lib/TreeNodes";
4
4
  interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
5
5
  new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
6
6
  $$bindings?: Bindings;
@@ -15,7 +15,8 @@ interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> =
15
15
  z_$$bindings?: Bindings;
16
16
  }
17
17
  declare const TreeView: $$__sveltets_2_IsomorphicComponent<{
18
- nodes: Array<TreeNode>;
18
+ nodes: Array<TreeNode<any>>;
19
+ textField: string | GetText<any>;
19
20
  style?: string;
20
21
  lazyLoader?: LazyLoader | null;
21
22
  activeNode?: any;
@@ -23,6 +24,7 @@ declare const TreeView: $$__sveltets_2_IsomorphicComponent<{
23
24
  isVisible?: NodeVisibleFun;
24
25
  onSelectionChange?: OnNodeSelectionChange;
25
26
  onContextMenu?: OnContextMenu;
27
+ checkIsDirectory: CheckIsDirectory<any>;
26
28
  }, {
27
29
  [evt: string]: CustomEvent<any>;
28
30
  }, {}, {
@@ -0,0 +1,23 @@
1
+ import type { CheckIsDirectory, TreeNode } from "../lib/TreeNodes";
2
+ export type OnNodeSelectionChange = (node: TreeNode<any>) => Promise<boolean>;
3
+ /**
4
+ * 节点是否显示
5
+ */
6
+ export type NodeVisibleFun = (node: TreeNode<any>) => boolean;
7
+ /**
8
+ * 加载子节点
9
+ */
10
+ export type LoadChildrenFun = (item: TreeNode<any>) => Promise<Array<TreeNode<any>>>;
11
+ /**
12
+ * 按需数据加载器
13
+ */
14
+ export interface LazyLoader {
15
+ /**
16
+ * 检查是否是枝节点
17
+ */
18
+ isBranch: CheckIsDirectory<any>;
19
+ /**
20
+ * 数据加载器
21
+ */
22
+ load: LoadChildrenFun;
23
+ }
@@ -1,7 +1,4 @@
1
1
  import TreeView from "./TreeView.svelte";
2
- import type TreeNode from "./TreeNode";
3
- import type { LazyLoader, NodeVisibleFun, OnNodeSelectionChange, CheckBranchFun, LoadChildrenFun, NodeLevelCompare, RootDetermine } from "./TreeNode";
4
- import treeUtils from "./TreeUtils";
2
+ import type { LazyLoader, NodeVisibleFun, OnNodeSelectionChange, LoadChildrenFun } from "./Types";
5
3
  export default TreeView;
6
- export { treeUtils };
7
- export type { TreeNode, LazyLoader, NodeVisibleFun, OnNodeSelectionChange, CheckBranchFun, LoadChildrenFun, NodeLevelCompare, RootDetermine };
4
+ export type { LazyLoader, NodeVisibleFun, OnNodeSelectionChange, LoadChildrenFun };
@@ -1,4 +1,2 @@
1
1
  import TreeView from "./TreeView.svelte";
2
- import treeUtils from "./TreeUtils";
3
2
  export default TreeView;
4
- export { treeUtils };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ticatec/uniface-element",
3
- "version": "0.1.45",
3
+ "version": "0.1.47",
4
4
  "description": "uniface web elements",
5
5
  "scripts": {
6
6
  "dev": "vite dev",
@@ -292,6 +292,10 @@
292
292
  "types": "./dist/tabs/index.d.ts",
293
293
  "import": "./dist/tabs/index.js"
294
294
  },
295
+ "./TreeNodes": {
296
+ "types": "./dist/lib/index.d.ts",
297
+ "import": "./dist/lib/index.js"
298
+ },
295
299
  "./Tag": {
296
300
  "types": "./dist/tag/index.d.ts",
297
301
  "import": "./dist/tag/index.js"
@@ -1,60 +0,0 @@
1
- export type OnNodeSelectionChange = (node: TreeNode) => Promise<boolean>;
2
- export default interface TreeNode {
3
- /**
4
- * 节点的值
5
- */
6
- value: string;
7
- /**
8
- * 节点的文字
9
- */
10
- text: string;
11
- /**
12
- * 对应节点的数据
13
- */
14
- data?: any;
15
- /**
16
- * 子节点
17
- */
18
- children?: Array<TreeNode> | null;
19
- /**
20
- * 父节点
21
- */
22
- parent?: TreeNode | null;
23
- /**
24
- * 是否是叶节点
25
- */
26
- isLeaf?: boolean;
27
- }
28
- /**
29
- * 节点是否显示
30
- */
31
- export type NodeVisibleFun = (node: TreeNode) => boolean;
32
- /**
33
- * 检查当前是否是叶节点
34
- */
35
- export type CheckBranchFun = (item: TreeNode) => boolean;
36
- /**
37
- * 加载子节点
38
- */
39
- export type LoadChildrenFun = (item: TreeNode) => Promise<Array<TreeNode>>;
40
- /**
41
- * 按需数据加载器
42
- */
43
- export interface LazyLoader {
44
- /**
45
- * 检查是否是枝节点
46
- */
47
- isBranch: CheckBranchFun;
48
- /**
49
- * 数据加载器
50
- */
51
- load: LoadChildrenFun;
52
- }
53
- /**
54
- * 判断是否是根节点
55
- */
56
- export type RootDetermine = (item: any) => boolean;
57
- /**
58
- * 层级排序
59
- */
60
- export type NodeLevelCompare = (e1: any, e2: any) => number;
@@ -1,6 +0,0 @@
1
- import type TreeNode from "./TreeNode";
2
- import type { NodeLevelCompare, RootDetermine } from "./TreeNode";
3
- declare const _default: {
4
- buildTreeNode: (list: Array<any>, idKey: string, joinKey: string, textField: string, valueField?: string, isRoot?: RootDetermine, sortFun?: NodeLevelCompare) => Array<TreeNode>;
5
- };
6
- export default _default;
@@ -1,53 +0,0 @@
1
- /**
2
- * 将一个数组转换成树状结构
3
- * @param list 待转换的数组
4
- * @param idKey 元素的主键
5
- * @param joinKey 父子间连接字段
6
- * @param valueField 取值的字段
7
- * @param textField 显示文字的字段
8
- * @param isRoot 判断是否是根节点,如果函数不存在,通过连接字段查询,无法获取到父节点就是根节点
9
- * @param sortFun 比较函数,用于曾经排序
10
- */
11
- const buildTreeNode = (list, idKey, joinKey, textField, valueField, isRoot, sortFun) => {
12
- if (sortFun != null) {
13
- list = list.sort(sortFun);
14
- }
15
- let nodes = [];
16
- let map = new Map();
17
- list.forEach(item => {
18
- let node = { value: item[valueField ?? idKey], text: item[textField], data: item };
19
- if (isRoot != null) {
20
- if (isRoot(item)) {
21
- nodes.push(node);
22
- map.set(item[idKey], node);
23
- }
24
- else {
25
- let parent = map.get(item[joinKey]);
26
- if (parent != null) {
27
- parent.children = [...(parent.children ?? []), node];
28
- node.parent = parent;
29
- map.set(item[idKey], node);
30
- }
31
- else {
32
- console.warn('Isolated node:', item);
33
- }
34
- }
35
- }
36
- else {
37
- let parent = map.get(item[joinKey]);
38
- if (parent != null) {
39
- parent.children = [...(parent.children ?? []), item];
40
- node.parent = parent;
41
- map.set(item[idKey], node);
42
- }
43
- else {
44
- nodes.push(node);
45
- map.set(item[idKey], node);
46
- }
47
- }
48
- });
49
- return nodes;
50
- };
51
- export default {
52
- buildTreeNode
53
- };
File without changes