@ticatec/uniface-element 0.2.0 → 0.2.2
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 +320 -1
- package/README_CN.md +392 -0
- package/dist/accordion/Accordion.svelte +1 -1
- package/dist/action-bar/ActionBar.svelte +7 -1
- package/dist/attachment-files/FileRender.svelte +1 -1
- package/dist/attachment-files/FileUploadBar.svelte +7 -6
- package/dist/attachment-files/FileUploadPanel.svelte +2 -2
- package/dist/base-calendar/DateContext.js +5 -4
- package/dist/base-calendar/YearPickupPanel.svelte +4 -4
- package/dist/card/Card.svelte +1 -1
- package/dist/card/Card.svelte.d.ts +1 -1
- package/dist/cascade-options-select/CascadeOptionSelect.svelte +2 -3
- package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +46 -1
- package/dist/cascade-options-select/CascadePanel.svelte +1 -1
- package/dist/checkbox/CheckBox.svelte +1 -1
- package/dist/color-picker/ColorPicker.svelte +9 -9
- package/dist/color-picker/ColorPicker.svelte.d.ts +0 -2
- package/dist/color-picker/ColorPickerPanel.svelte +11 -15
- package/dist/color-picker/ColorPickerPanel.svelte.d.ts +1 -1
- package/dist/common/CommonPicker.svelte +2 -2
- package/dist/common/CommonPicker.svelte.d.ts +1 -1
- package/dist/common/MouseClickHandler.d.ts +1 -1
- package/dist/common/Popover.svelte +28 -6
- package/dist/common/Popover.svelte.d.ts +9 -3
- package/dist/common/uniface-utils.js +6 -4
- package/dist/common-editor/CommonEditor.svelte +1 -1
- package/dist/common-editor/CommonEditor.svelte.d.ts +1 -1
- package/dist/common-editor/NumberInput.svelte +1 -1
- package/dist/common-editor/NumberInput.svelte.d.ts +1 -1
- package/dist/concise-data-table/ConciseListTable.svelte +7 -2
- package/dist/concise-data-table/ConciseListTable.svelte.d.ts +1 -0
- package/dist/concise-data-table/DataRow.svelte +1 -1
- package/dist/concise-data-table/TableOptions.d.ts +1 -1
- package/dist/data-table/DataTable.svelte +1 -1
- package/dist/data-table/parts/ActionsPanel.svelte +4 -3
- package/dist/data-table/parts/ActionsRow.svelte +3 -3
- package/dist/data-table/parts/ContentPanel.svelte +3 -2
- package/dist/data-table/parts/FixedColumnsPanel.svelte +0 -1
- package/dist/data-table/parts/FixedColumnsPanel.svelte.d.ts +1 -2
- package/dist/data-table/parts/FixedHeaderPanel.svelte +2 -2
- package/dist/data-table/parts/FixedRow.svelte +2 -1
- package/dist/data-table/parts/FixedRow.svelte.d.ts +1 -1
- package/dist/data-table/parts/HrefCell.svelte +23 -2
- package/dist/data-table/parts/PopupMenu.svelte +25 -2
- package/dist/data-table/parts/PopupMenu.svelte.d.ts +8 -1
- package/dist/date-picker/DatePicker.svelte +0 -1
- package/dist/date-picker/DateTimePicker.svelte +3 -3
- package/dist/date-picker/ScrollBar.svelte +4 -7
- package/dist/date-range/DateRangeEditor.svelte +1 -1
- package/dist/dialog/CommonDialog.svelte +8 -5
- package/dist/dialog/CommonDialog.svelte.d.ts +2 -1
- package/dist/dialog/Dialog.svelte +37 -12
- package/dist/dialog/Dialog.svelte.d.ts +4 -3
- package/dist/dialog/DialogBoard.svelte +11 -8
- package/dist/dialog/DialogWrapper.svelte +10 -0
- package/dist/{common-editor/DateInput.svelte.d.ts → dialog/DialogWrapper.svelte.d.ts} +6 -13
- package/dist/dialog/Dialogs.js +1 -1
- package/dist/dialog/ModalResult.d.ts +5 -0
- package/dist/dialog/ModalResult.js +5 -0
- package/dist/drawer/Drawer.svelte +1 -1
- package/dist/form-field/FormField.svelte +2 -1
- package/dist/form-field/FormField.svelte.d.ts +1 -0
- package/dist/form-panel/flex-row-form/FormContainer.svelte +1 -1
- package/dist/form-panel/grid-form/EmptyCell.svelte +8 -7
- package/dist/form-panel/grid-form/EmptyCell.svelte.d.ts +2 -2
- package/dist/form-panel/grid-form/GridField.svelte +1 -1
- package/dist/i18nRes/i18nRes.d.ts +2 -0
- package/dist/i18nRes/i18nRes.js +44 -0
- package/dist/i18nRes/index.d.ts +2 -0
- package/dist/i18nRes/index.js +2 -0
- package/dist/image-files/ImageFilesField.svelte +1 -1
- package/dist/indicator/IndicatorBoard.svelte +1 -1
- package/dist/inline-cell-editor/InvalidEditor.svelte +1 -0
- package/dist/input-options-select/InputOptionsSelect.svelte +6 -6
- package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +1 -1
- package/dist/layout/flex/FlexBlock.svelte +1 -1
- package/dist/lookup-editor/LookupEditor.svelte +1 -1
- package/dist/memo-editor/MemoEditor.svelte +2 -2
- package/dist/message-box/IMessageBox.d.ts +2 -4
- package/dist/message-box/IMessageBox.js +4 -6
- package/dist/message-box/MessageBoxBoard.svelte +1 -3
- package/dist/options-multi-select/OptionsMultiSelect.svelte +1 -1
- package/dist/prompts-text-editor/PromptsTextEditor.svelte +2 -2
- package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +1 -1
- package/dist/property-editor/PropertyEditor.svelte +3 -3
- package/dist/text-editor/PasswordEditor.svelte +1 -1
- package/dist/transfer/Transfer.svelte +17 -12
- package/dist/transfer/Transfer.svelte.d.ts +0 -1
- package/dist/unit-number-editor/UnitNumberEditor.svelte +2 -2
- package/docs/buttons/cn/ActionBar.md +459 -0
- package/docs/buttons/cn/Button.md +228 -0
- package/docs/buttons/cn/IconButton.md +294 -0
- package/docs/buttons/cn/README.md +600 -0
- package/docs/buttons/cn/TextButton.md +163 -0
- package/docs/buttons/en/ActionBar.md +459 -0
- package/docs/buttons/en/Button.md +228 -0
- package/docs/buttons/en/IconButton.md +294 -0
- package/docs/buttons/en/README.md +600 -0
- package/docs/buttons/en/TextButton.md +163 -0
- package/docs/containers/cn/accordion.md +622 -0
- package/docs/containers/cn/box.md +445 -0
- package/docs/containers/cn/card.md +404 -0
- package/docs/containers/cn/page.md +576 -0
- package/docs/containers/cn/tabs.md +686 -0
- package/docs/containers/en/accordion.md +622 -0
- package/docs/containers/en/box.md +445 -0
- package/docs/containers/en/card.md +404 -0
- package/docs/containers/en/page.md +576 -0
- package/docs/containers/en/tabs.md +686 -0
- package/docs/data-display/cn/concise-data-table.md +731 -0
- package/docs/data-display/cn/listbox.md +786 -0
- package/docs/data-display/cn/treeview.md +863 -0
- package/docs/data-display/en/concise-data-table.md +732 -0
- package/docs/data-display/en/listbox.md +786 -0
- package/docs/data-display/en/treeview.md +863 -0
- package/docs/data-table/cn/README.md +596 -0
- package/docs/data-table/en/README.md +596 -0
- package/docs/dialog/cn/README.md +767 -0
- package/docs/dialog/en/README.md +767 -0
- package/docs/form/cn/README.md +847 -0
- package/docs/form/en/README.md +847 -0
- package/docs/form-components/cn/README.md +495 -0
- package/docs/form-components/cn/attachmentfilesfield.md +757 -0
- package/docs/form-components/cn/cascade-options-select.md +374 -0
- package/docs/form-components/cn/checkbox.md +58 -0
- package/docs/form-components/cn/date-picker.md +138 -0
- package/docs/form-components/cn/datetime-picker.md +228 -0
- package/docs/form-components/cn/group-checkbox.md +405 -0
- package/docs/form-components/cn/group-radiobox.md +525 -0
- package/docs/form-components/cn/imagefilesfield.md +651 -0
- package/docs/form-components/cn/input-options-select.md +250 -0
- package/docs/form-components/cn/lookup-editor.md +406 -0
- package/docs/form-components/cn/memoeditor.md +409 -0
- package/docs/form-components/cn/number-editor.md +261 -0
- package/docs/form-components/cn/options-multi-select.md +177 -0
- package/docs/form-components/cn/options-select.md +83 -0
- package/docs/form-components/cn/passwordeditor.md +538 -0
- package/docs/form-components/cn/prompts-text-editor.md +241 -0
- package/docs/form-components/cn/radiobutton.md +84 -0
- package/docs/form-components/cn/switch.md +178 -0
- package/docs/form-components/cn/text-editor.md +142 -0
- package/docs/form-components/cn/time-editor.md +159 -0
- package/docs/form-components/cn/unit-number-editor.md +164 -0
- package/docs/form-components/en/README.md +463 -0
- package/docs/form-components/en/attachmentfilesfield.md +757 -0
- package/docs/form-components/en/cascade-options-select.md +358 -0
- package/docs/form-components/en/checkbox.md +59 -0
- package/docs/form-components/en/date-picker.md +138 -0
- package/docs/form-components/en/datetime-picker.md +228 -0
- package/docs/form-components/en/group-checkbox.md +395 -0
- package/docs/form-components/en/group-radiobox.md +498 -0
- package/docs/form-components/en/imagefilesfield.md +651 -0
- package/docs/form-components/en/input-options-select.md +239 -0
- package/docs/form-components/en/lookup-editor.md +389 -0
- package/docs/form-components/en/memoeditor.md +409 -0
- package/docs/form-components/en/number-editor.md +249 -0
- package/docs/form-components/en/options-multi-select.md +177 -0
- package/docs/form-components/en/options-select.md +83 -0
- package/docs/form-components/en/passwordeditor.md +538 -0
- package/docs/form-components/en/prompts-text-editor.md +241 -0
- package/docs/form-components/en/radiobutton.md +84 -0
- package/docs/form-components/en/switch.md +180 -0
- package/docs/form-components/en/text-editor.md +142 -0
- package/docs/form-components/en/time-editor.md +159 -0
- package/docs/form-components/en/unit-number-editor.md +164 -0
- package/docs/form-layout/cn/criteria-field.md +652 -0
- package/docs/form-layout/cn/flex-form.md +454 -0
- package/docs/form-layout/cn/flex-row-form.md +542 -0
- package/docs/form-layout/cn/form-field.md +923 -0
- package/docs/form-layout/cn/grid-form.md +676 -0
- package/docs/form-layout/en/criteria-field.md +652 -0
- package/docs/form-layout/en/flex-form.md +454 -0
- package/docs/form-layout/en/flex-row-form.md +542 -0
- package/docs/form-layout/en/form-field.md +923 -0
- package/docs/form-layout/en/grid-form.md +676 -0
- package/docs/global/cn/README.md +534 -0
- package/docs/global/en/README.md +534 -0
- package/docs/layout/cn/classiclayout.md +460 -0
- package/docs/layout/cn/headerlayout.md +524 -0
- package/docs/layout/cn/sidebarlayout.md +263 -0
- package/docs/layout/en/classiclayout.md +951 -0
- package/docs/layout/en/headerlayout.md +524 -0
- package/docs/layout/en/sidebarlayout.md +262 -0
- package/docs/misc/cn/README.md +1217 -0
- package/docs/misc/en/README.md +1217 -0
- package/docs/navigation/cn/breadcrumb.md +291 -0
- package/docs/navigation/cn/navigator.md +322 -0
- package/docs/navigation/cn/navigatormenu.md +512 -0
- package/docs/navigation/cn/progressbar.md +199 -0
- package/docs/navigation/cn/progressstepbar.md +299 -0
- package/docs/navigation/en/breadcrumb.md +291 -0
- package/docs/navigation/en/navigator.md +322 -0
- package/docs/navigation/en/navigatormenu.md +512 -0
- package/docs/navigation/en/progressbar.md +199 -0
- package/docs/navigation/en/progressstepbar.md +299 -0
- package/docs/search-filters/cn/daterange.md +1156 -0
- package/docs/search-filters/cn/numberrange.md +688 -0
- package/docs/search-filters/cn/searchbox.md +1582 -0
- package/docs/search-filters/en/daterange.md +1156 -0
- package/docs/search-filters/en/numberrange.md +688 -0
- package/docs/search-filters/en/searchbox.md +1582 -0
- package/package.json +53 -13
- package/dist/common-editor/DateInput.svelte +0 -27
- package/dist/i18n_resources/index.d.ts +0 -3
- package/dist/i18n_resources/index.js +0 -3
- /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.d.ts +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.js +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.d.ts +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.js +0 -0
|
@@ -0,0 +1,863 @@
|
|
|
1
|
+
# TreeView Component
|
|
2
|
+
|
|
3
|
+
A hierarchical data display component that renders tree structures with expandable/collapsible nodes, lazy loading support, and interactive node selection.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
The TreeView component provides a sophisticated interface for displaying hierarchical data structures. It supports node expansion/collapse, lazy loading for large datasets, custom node rendering, context menus, and flexible node selection. Perfect for file systems, organization charts, menu structures, and any hierarchical data visualization.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```typescript
|
|
12
|
+
import TreeView from '@ticatec/uniface-element/TreeView';
|
|
13
|
+
import type { LazyLoader, NodeVisibleFun, OnNodeSelectionChange, LoadChildrenFun } from '@ticatec/uniface-element/TreeView';
|
|
14
|
+
import type { TreeNode, CheckIsDirectory, GetText } from '@ticatec/uniface-element/TreeNodes';
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Basic Usage
|
|
18
|
+
|
|
19
|
+
```svelte
|
|
20
|
+
<script lang="ts">
|
|
21
|
+
import TreeView from '@ticatec/uniface-element/TreeView';
|
|
22
|
+
import type { TreeNode, CheckIsDirectory } from '@ticatec/uniface-element/TreeNodes';
|
|
23
|
+
|
|
24
|
+
// Sample hierarchical data
|
|
25
|
+
let treeData: TreeNode<any>[] = [
|
|
26
|
+
{
|
|
27
|
+
item: { id: '1', name: 'Root Folder', type: 'folder' },
|
|
28
|
+
expand: true,
|
|
29
|
+
children: [
|
|
30
|
+
{
|
|
31
|
+
item: { id: '2', name: 'Documents', type: 'folder' },
|
|
32
|
+
expand: false,
|
|
33
|
+
children: [
|
|
34
|
+
{ item: { id: '3', name: 'file1.txt', type: 'file' } },
|
|
35
|
+
{ item: { id: '4', name: 'file2.pdf', type: 'file' } }
|
|
36
|
+
]
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
item: { id: '5', name: 'Images', type: 'folder' },
|
|
40
|
+
expand: false,
|
|
41
|
+
children: [
|
|
42
|
+
{ item: { id: '6', name: 'photo.jpg', type: 'file' } }
|
|
43
|
+
]
|
|
44
|
+
}
|
|
45
|
+
]
|
|
46
|
+
}
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
const checkIsDirectory: CheckIsDirectory<any> = (node) => {
|
|
50
|
+
return node.item.type === 'folder';
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
let activeNode = null;
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<TreeView
|
|
57
|
+
nodes={treeData}
|
|
58
|
+
textField="name"
|
|
59
|
+
{checkIsDirectory}
|
|
60
|
+
bind:activeNode
|
|
61
|
+
/>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Properties
|
|
65
|
+
|
|
66
|
+
| Property | Type | Default | Description |
|
|
67
|
+
|----------|------|---------|-------------|
|
|
68
|
+
| `nodes` | `Array<TreeNode<any>>` | - | Array of tree nodes to display |
|
|
69
|
+
| `textField` | `string \| GetText<any>` | - | Field name or function to get node text |
|
|
70
|
+
| `style` | `string` | `""` | Custom CSS styles for the tree container |
|
|
71
|
+
| `lazyLoader` | `LazyLoader \| null` | `null` | Lazy loading configuration |
|
|
72
|
+
| `activeNode` | `any` | `null` | Currently active/selected node |
|
|
73
|
+
| `class` | `string` | `""` | Additional CSS class names |
|
|
74
|
+
| `isVisible` | `NodeVisibleFun` | `null` | Function to determine node visibility |
|
|
75
|
+
| `onSelectionChange` | `OnNodeSelectionChange` | `null` | Node selection change callback |
|
|
76
|
+
| `onContextMenu` | `OnContextMenu` | `null` | Context menu callback |
|
|
77
|
+
| `checkIsDirectory` | `CheckIsDirectory<any>` | - | Function to check if node is a directory |
|
|
78
|
+
|
|
79
|
+
## Type Definitions
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
/**
|
|
83
|
+
* Tree node structure
|
|
84
|
+
*/
|
|
85
|
+
export type TreeNode<T> = {
|
|
86
|
+
item: T;
|
|
87
|
+
expand?: boolean;
|
|
88
|
+
children?: TreeNode<T>[];
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Function to check if node is a directory/branch
|
|
93
|
+
*/
|
|
94
|
+
export type CheckIsDirectory<T> = (node: TreeNode<T>) => boolean;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Function to get text from node item
|
|
98
|
+
*/
|
|
99
|
+
export type GetText<T> = (data: T) => string;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Node selection change callback
|
|
103
|
+
*/
|
|
104
|
+
export type OnNodeSelectionChange = (node: TreeNode<any>) => Promise<boolean>;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Node visibility filter function
|
|
108
|
+
*/
|
|
109
|
+
export type NodeVisibleFun = (node: TreeNode<any>) => boolean;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Load children function for lazy loading
|
|
113
|
+
*/
|
|
114
|
+
export type LoadChildrenFun = (item: TreeNode<any>) => Promise<Array<TreeNode<any>>>;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Lazy loader configuration
|
|
118
|
+
*/
|
|
119
|
+
export interface LazyLoader {
|
|
120
|
+
/**
|
|
121
|
+
* Check if node is a branch (has children)
|
|
122
|
+
*/
|
|
123
|
+
isBranch: CheckIsDirectory<any>;
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Data loader function
|
|
127
|
+
*/
|
|
128
|
+
load: LoadChildrenFun;
|
|
129
|
+
}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## Usage Examples
|
|
133
|
+
|
|
134
|
+
### File System Tree
|
|
135
|
+
|
|
136
|
+
```svelte
|
|
137
|
+
<script lang="ts">
|
|
138
|
+
import TreeView from '@ticatec/uniface-element/TreeView';
|
|
139
|
+
import type { TreeNode, CheckIsDirectory } from '@ticatec/uniface-element/TreeNodes';
|
|
140
|
+
|
|
141
|
+
interface FileSystemItem {
|
|
142
|
+
id: string;
|
|
143
|
+
name: string;
|
|
144
|
+
type: 'file' | 'folder';
|
|
145
|
+
size?: number;
|
|
146
|
+
modified?: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
let fileSystem: TreeNode<FileSystemItem>[] = [
|
|
150
|
+
{
|
|
151
|
+
item: { id: 'root', name: 'Project Root', type: 'folder' },
|
|
152
|
+
expand: true,
|
|
153
|
+
children: [
|
|
154
|
+
{
|
|
155
|
+
item: { id: 'src', name: 'src', type: 'folder' },
|
|
156
|
+
expand: true,
|
|
157
|
+
children: [
|
|
158
|
+
{
|
|
159
|
+
item: { id: 'components', name: 'components', type: 'folder' },
|
|
160
|
+
expand: false,
|
|
161
|
+
children: [
|
|
162
|
+
{ item: { id: 'header', name: 'Header.svelte', type: 'file', size: 2048 } },
|
|
163
|
+
{ item: { id: 'footer', name: 'Footer.svelte', type: 'file', size: 1024 } }
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
{ item: { id: 'main', name: 'main.ts', type: 'file', size: 512 } },
|
|
167
|
+
{ item: { id: 'app', name: 'App.svelte', type: 'file', size: 3072 } }
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
item: { id: 'public', name: 'public', type: 'folder' },
|
|
172
|
+
expand: false,
|
|
173
|
+
children: [
|
|
174
|
+
{ item: { id: 'index', name: 'index.html', type: 'file', size: 1536 } },
|
|
175
|
+
{ item: { id: 'favicon', name: 'favicon.ico', type: 'file', size: 256 } }
|
|
176
|
+
]
|
|
177
|
+
},
|
|
178
|
+
{ item: { id: 'package', name: 'package.json', type: 'file', size: 1024 } },
|
|
179
|
+
{ item: { id: 'readme', name: 'README.md', type: 'file', size: 2048 } }
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
const checkIsDirectory: CheckIsDirectory<FileSystemItem> = (node) => {
|
|
185
|
+
return node.item.type === 'folder';
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
let selectedNode: TreeNode<FileSystemItem> | null = null;
|
|
189
|
+
|
|
190
|
+
async function handleNodeSelection(node: TreeNode<FileSystemItem>): Promise<boolean> {
|
|
191
|
+
console.log('Selected node:', node.item.name);
|
|
192
|
+
selectedNode = node;
|
|
193
|
+
return true; // Allow selection
|
|
194
|
+
}
|
|
195
|
+
</script>
|
|
196
|
+
|
|
197
|
+
<div class="file-explorer">
|
|
198
|
+
<TreeView
|
|
199
|
+
nodes={fileSystem}
|
|
200
|
+
textField="name"
|
|
201
|
+
checkIsDirectory={checkIsDirectory}
|
|
202
|
+
onSelectionChange={handleNodeSelection}
|
|
203
|
+
style="border: 1px solid #ddd; height: 400px; overflow-y: auto;"
|
|
204
|
+
/>
|
|
205
|
+
|
|
206
|
+
{#if selectedNode}
|
|
207
|
+
<div class="file-details">
|
|
208
|
+
<h3>Selected: {selectedNode.item.name}</h3>
|
|
209
|
+
<p><strong>Type:</strong> {selectedNode.item.type}</p>
|
|
210
|
+
{#if selectedNode.item.size}
|
|
211
|
+
<p><strong>Size:</strong> {selectedNode.item.size} bytes</p>
|
|
212
|
+
{/if}
|
|
213
|
+
</div>
|
|
214
|
+
{/if}
|
|
215
|
+
</div>
|
|
216
|
+
|
|
217
|
+
<style>
|
|
218
|
+
.file-explorer {
|
|
219
|
+
display: flex;
|
|
220
|
+
gap: 20px;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
.file-details {
|
|
224
|
+
padding: 16px;
|
|
225
|
+
background: #f8f9fa;
|
|
226
|
+
border-radius: 4px;
|
|
227
|
+
min-width: 200px;
|
|
228
|
+
}
|
|
229
|
+
</style>
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Organization Chart
|
|
233
|
+
|
|
234
|
+
```svelte
|
|
235
|
+
<script lang="ts">
|
|
236
|
+
import TreeView from '@ticatec/uniface-element/TreeView';
|
|
237
|
+
import type { TreeNode, CheckIsDirectory, GetText } from '@ticatec/uniface-element/TreeNodes';
|
|
238
|
+
|
|
239
|
+
interface Employee {
|
|
240
|
+
id: string;
|
|
241
|
+
name: string;
|
|
242
|
+
position: string;
|
|
243
|
+
department: string;
|
|
244
|
+
hasSubordinates: boolean;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let organizationChart: TreeNode<Employee>[] = [
|
|
248
|
+
{
|
|
249
|
+
item: {
|
|
250
|
+
id: 'ceo',
|
|
251
|
+
name: 'John Smith',
|
|
252
|
+
position: 'CEO',
|
|
253
|
+
department: 'Executive',
|
|
254
|
+
hasSubordinates: true
|
|
255
|
+
},
|
|
256
|
+
expand: true,
|
|
257
|
+
children: [
|
|
258
|
+
{
|
|
259
|
+
item: {
|
|
260
|
+
id: 'cto',
|
|
261
|
+
name: 'Sarah Johnson',
|
|
262
|
+
position: 'CTO',
|
|
263
|
+
department: 'Technology',
|
|
264
|
+
hasSubordinates: true
|
|
265
|
+
},
|
|
266
|
+
expand: true,
|
|
267
|
+
children: [
|
|
268
|
+
{
|
|
269
|
+
item: {
|
|
270
|
+
id: 'dev-manager',
|
|
271
|
+
name: 'Mike Wilson',
|
|
272
|
+
position: 'Development Manager',
|
|
273
|
+
department: 'Engineering',
|
|
274
|
+
hasSubordinates: true
|
|
275
|
+
},
|
|
276
|
+
expand: false,
|
|
277
|
+
children: [
|
|
278
|
+
{ item: { id: 'dev1', name: 'Alice Brown', position: 'Senior Developer', department: 'Engineering', hasSubordinates: false } },
|
|
279
|
+
{ item: { id: 'dev2', name: 'Bob Davis', position: 'Developer', department: 'Engineering', hasSubordinates: false } }
|
|
280
|
+
]
|
|
281
|
+
},
|
|
282
|
+
{ item: { id: 'qa', name: 'Emily Chen', position: 'QA Lead', department: 'Quality Assurance', hasSubordinates: false } }
|
|
283
|
+
]
|
|
284
|
+
},
|
|
285
|
+
{
|
|
286
|
+
item: {
|
|
287
|
+
id: 'cfo',
|
|
288
|
+
name: 'David Rodriguez',
|
|
289
|
+
position: 'CFO',
|
|
290
|
+
department: 'Finance',
|
|
291
|
+
hasSubordinates: true
|
|
292
|
+
},
|
|
293
|
+
expand: false,
|
|
294
|
+
children: [
|
|
295
|
+
{ item: { id: 'accountant', name: 'Lisa Wang', position: 'Senior Accountant', department: 'Finance', hasSubordinates: false } }
|
|
296
|
+
]
|
|
297
|
+
}
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
];
|
|
301
|
+
|
|
302
|
+
const checkIsDirectory: CheckIsDirectory<Employee> = (node) => {
|
|
303
|
+
return node.item.hasSubordinates;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const getEmployeeText: GetText<Employee> = (employee) => {
|
|
307
|
+
return `${employee.name} - ${employee.position}`;
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
let selectedEmployee: TreeNode<Employee> | null = null;
|
|
311
|
+
</script>
|
|
312
|
+
|
|
313
|
+
<div class="org-chart">
|
|
314
|
+
<h2>Organization Chart</h2>
|
|
315
|
+
|
|
316
|
+
<TreeView
|
|
317
|
+
nodes={organizationChart}
|
|
318
|
+
textField={getEmployeeText}
|
|
319
|
+
checkIsDirectory={checkIsDirectory}
|
|
320
|
+
bind:activeNode={selectedEmployee}
|
|
321
|
+
style="background: white; border: 1px solid #e0e0e0; padding: 16px; border-radius: 8px;"
|
|
322
|
+
/>
|
|
323
|
+
|
|
324
|
+
{#if selectedEmployee}
|
|
325
|
+
<div class="employee-card">
|
|
326
|
+
<div class="employee-header">
|
|
327
|
+
<h3>{selectedEmployee.item.name}</h3>
|
|
328
|
+
<span class="position">{selectedEmployee.item.position}</span>
|
|
329
|
+
</div>
|
|
330
|
+
<div class="employee-details">
|
|
331
|
+
<p><strong>Department:</strong> {selectedEmployee.item.department}</p>
|
|
332
|
+
<p><strong>ID:</strong> {selectedEmployee.item.id}</p>
|
|
333
|
+
<p><strong>Has Team:</strong> {selectedEmployee.item.hasSubordinates ? 'Yes' : 'No'}</p>
|
|
334
|
+
</div>
|
|
335
|
+
</div>
|
|
336
|
+
{/if}
|
|
337
|
+
</div>
|
|
338
|
+
|
|
339
|
+
<style>
|
|
340
|
+
.org-chart {
|
|
341
|
+
max-width: 800px;
|
|
342
|
+
margin: 0 auto;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
.employee-card {
|
|
346
|
+
margin-top: 20px;
|
|
347
|
+
padding: 20px;
|
|
348
|
+
background: #f8f9fa;
|
|
349
|
+
border-radius: 8px;
|
|
350
|
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.employee-header {
|
|
354
|
+
margin-bottom: 12px;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
.employee-header h3 {
|
|
358
|
+
margin: 0 0 4px 0;
|
|
359
|
+
color: #333;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.position {
|
|
363
|
+
background: #007bff;
|
|
364
|
+
color: white;
|
|
365
|
+
padding: 4px 8px;
|
|
366
|
+
border-radius: 4px;
|
|
367
|
+
font-size: 0.875rem;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
.employee-details p {
|
|
371
|
+
margin: 8px 0;
|
|
372
|
+
color: #555;
|
|
373
|
+
}
|
|
374
|
+
</style>
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Lazy Loading Tree
|
|
378
|
+
|
|
379
|
+
```svelte
|
|
380
|
+
<script lang="ts">
|
|
381
|
+
import TreeView from '@ticatec/uniface-element/TreeView';
|
|
382
|
+
import type { TreeNode, CheckIsDirectory } from '@ticatec/uniface-element/TreeNodes';
|
|
383
|
+
import type { LazyLoader, LoadChildrenFun } from '@ticatec/uniface-element/TreeView';
|
|
384
|
+
|
|
385
|
+
interface ApiNode {
|
|
386
|
+
id: string;
|
|
387
|
+
name: string;
|
|
388
|
+
type: 'folder' | 'file';
|
|
389
|
+
hasChildren?: boolean;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// Initial root nodes
|
|
393
|
+
let initialNodes: TreeNode<ApiNode>[] = [
|
|
394
|
+
{
|
|
395
|
+
item: { id: 'api', name: 'API Endpoints', type: 'folder', hasChildren: true },
|
|
396
|
+
expand: false
|
|
397
|
+
},
|
|
398
|
+
{
|
|
399
|
+
item: { id: 'components', name: 'Components', type: 'folder', hasChildren: true },
|
|
400
|
+
expand: false
|
|
401
|
+
}
|
|
402
|
+
];
|
|
403
|
+
|
|
404
|
+
const checkIsDirectory: CheckIsDirectory<ApiNode> = (node) => {
|
|
405
|
+
return node.item.type === 'folder' && node.item.hasChildren;
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
// Simulate API call for loading children
|
|
409
|
+
const loadChildren: LoadChildrenFun = async (parentNode) => {
|
|
410
|
+
console.log('Loading children for:', parentNode.item.name);
|
|
411
|
+
|
|
412
|
+
// Simulate network delay
|
|
413
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
414
|
+
|
|
415
|
+
// Mock data based on parent node
|
|
416
|
+
if (parentNode.item.id === 'api') {
|
|
417
|
+
return [
|
|
418
|
+
{
|
|
419
|
+
item: { id: 'users', name: 'Users API', type: 'folder', hasChildren: true }
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
item: { id: 'orders', name: 'Orders API', type: 'folder', hasChildren: true }
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
item: { id: 'auth', name: 'Authentication', type: 'file' }
|
|
426
|
+
}
|
|
427
|
+
];
|
|
428
|
+
} else if (parentNode.item.id === 'components') {
|
|
429
|
+
return [
|
|
430
|
+
{
|
|
431
|
+
item: { id: 'ui', name: 'UI Components', type: 'folder', hasChildren: true }
|
|
432
|
+
},
|
|
433
|
+
{
|
|
434
|
+
item: { id: 'forms', name: 'Form Components', type: 'folder', hasChildren: true }
|
|
435
|
+
}
|
|
436
|
+
];
|
|
437
|
+
} else if (parentNode.item.id === 'users') {
|
|
438
|
+
return [
|
|
439
|
+
{ item: { id: 'get-users', name: 'GET /users', type: 'file' } },
|
|
440
|
+
{ item: { id: 'post-user', name: 'POST /users', type: 'file' } },
|
|
441
|
+
{ item: { id: 'put-user', name: 'PUT /users/:id', type: 'file' } }
|
|
442
|
+
];
|
|
443
|
+
} else if (parentNode.item.id === 'orders') {
|
|
444
|
+
return [
|
|
445
|
+
{ item: { id: 'get-orders', name: 'GET /orders', type: 'file' } },
|
|
446
|
+
{ item: { id: 'post-order', name: 'POST /orders', type: 'file' } }
|
|
447
|
+
];
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
return [];
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
const lazyLoader: LazyLoader = {
|
|
454
|
+
isBranch: checkIsDirectory,
|
|
455
|
+
load: loadChildren
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
let activeNode: TreeNode<ApiNode> | null = null;
|
|
459
|
+
let loadingNodes = new Set();
|
|
460
|
+
|
|
461
|
+
async function handleNodeSelection(node: TreeNode<ApiNode>): Promise<boolean> {
|
|
462
|
+
console.log('Selected:', node.item.name);
|
|
463
|
+
return true;
|
|
464
|
+
}
|
|
465
|
+
</script>
|
|
466
|
+
|
|
467
|
+
<div class="api-explorer">
|
|
468
|
+
<h2>API Explorer (Lazy Loading)</h2>
|
|
469
|
+
|
|
470
|
+
<TreeView
|
|
471
|
+
nodes={initialNodes}
|
|
472
|
+
textField="name"
|
|
473
|
+
checkIsDirectory={checkIsDirectory}
|
|
474
|
+
lazyLoader={lazyLoader}
|
|
475
|
+
onSelectionChange={handleNodeSelection}
|
|
476
|
+
bind:activeNode
|
|
477
|
+
style="height: 500px; border: 1px solid #ddd; overflow-y: auto; padding: 8px;"
|
|
478
|
+
/>
|
|
479
|
+
|
|
480
|
+
{#if activeNode}
|
|
481
|
+
<div class="node-info">
|
|
482
|
+
<h3>Selected: {activeNode.item.name}</h3>
|
|
483
|
+
<p><strong>Type:</strong> {activeNode.item.type}</p>
|
|
484
|
+
<p><strong>ID:</strong> {activeNode.item.id}</p>
|
|
485
|
+
{#if activeNode.item.hasChildren}
|
|
486
|
+
<p><strong>Has Children:</strong> Yes</p>
|
|
487
|
+
{/if}
|
|
488
|
+
</div>
|
|
489
|
+
{/if}
|
|
490
|
+
</div>
|
|
491
|
+
|
|
492
|
+
<style>
|
|
493
|
+
.api-explorer {
|
|
494
|
+
max-width: 600px;
|
|
495
|
+
margin: 20px 0;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
.node-info {
|
|
499
|
+
margin-top: 20px;
|
|
500
|
+
padding: 16px;
|
|
501
|
+
background: #f8f9fa;
|
|
502
|
+
border-radius: 4px;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.node-info h3 {
|
|
506
|
+
margin: 0 0 12px 0;
|
|
507
|
+
color: #333;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.node-info p {
|
|
511
|
+
margin: 6px 0;
|
|
512
|
+
color: #555;
|
|
513
|
+
}
|
|
514
|
+
</style>
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
### Filtered Tree with Context Menu
|
|
518
|
+
|
|
519
|
+
```svelte
|
|
520
|
+
<script lang="ts">
|
|
521
|
+
import TreeView from '@ticatec/uniface-element/TreeView';
|
|
522
|
+
import type { TreeNode, CheckIsDirectory } from '@ticatec/uniface-element/TreeNodes';
|
|
523
|
+
import type { NodeVisibleFun, OnNodeSelectionChange } from '@ticatec/uniface-element/TreeView';
|
|
524
|
+
import type { OnContextMenu } from '@ticatec/uniface-element/ContextMenu';
|
|
525
|
+
|
|
526
|
+
interface MenuItem {
|
|
527
|
+
id: string;
|
|
528
|
+
label: string;
|
|
529
|
+
icon?: string;
|
|
530
|
+
children?: MenuItem[];
|
|
531
|
+
category: string;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
let menuStructure: TreeNode<MenuItem>[] = [
|
|
535
|
+
{
|
|
536
|
+
item: { id: 'dashboard', label: 'Dashboard', icon: '📊', category: 'main' },
|
|
537
|
+
expand: true,
|
|
538
|
+
children: [
|
|
539
|
+
{ item: { id: 'analytics', label: 'Analytics', icon: '📈', category: 'dashboard' } },
|
|
540
|
+
{ item: { id: 'reports', label: 'Reports', icon: '📋', category: 'dashboard' } }
|
|
541
|
+
]
|
|
542
|
+
},
|
|
543
|
+
{
|
|
544
|
+
item: { id: 'users', label: 'User Management', icon: '👥', category: 'main' },
|
|
545
|
+
expand: false,
|
|
546
|
+
children: [
|
|
547
|
+
{ item: { id: 'user-list', label: 'User List', icon: '📝', category: 'users' } },
|
|
548
|
+
{ item: { id: 'user-roles', label: 'Roles & Permissions', icon: '🔒', category: 'users' } },
|
|
549
|
+
{ item: { id: 'user-settings', label: 'User Settings', icon: '⚙️', category: 'users' } }
|
|
550
|
+
]
|
|
551
|
+
},
|
|
552
|
+
{
|
|
553
|
+
item: { id: 'content', label: 'Content Management', icon: '📄', category: 'main' },
|
|
554
|
+
expand: false,
|
|
555
|
+
children: [
|
|
556
|
+
{ item: { id: 'pages', label: 'Pages', icon: '📖', category: 'content' } },
|
|
557
|
+
{ item: { id: 'media', label: 'Media Library', icon: '🖼️', category: 'content' } }
|
|
558
|
+
]
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
item: { id: 'settings', label: 'System Settings', icon: '🔧', category: 'main' },
|
|
562
|
+
expand: false,
|
|
563
|
+
children: [
|
|
564
|
+
{ item: { id: 'general', label: 'General', icon: '⚙️', category: 'settings' } },
|
|
565
|
+
{ item: { id: 'security', label: 'Security', icon: '🛡️', category: 'settings' } }
|
|
566
|
+
]
|
|
567
|
+
}
|
|
568
|
+
];
|
|
569
|
+
|
|
570
|
+
let searchQuery = '';
|
|
571
|
+
let selectedNode: TreeNode<MenuItem> | null = null;
|
|
572
|
+
|
|
573
|
+
const checkIsDirectory: CheckIsDirectory<MenuItem> = (node) => {
|
|
574
|
+
return node.children && node.children.length > 0;
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
// Filter function for search
|
|
578
|
+
const nodeVisibilityFilter: NodeVisibleFun = (node) => {
|
|
579
|
+
if (!searchQuery.trim()) return true;
|
|
580
|
+
|
|
581
|
+
const query = searchQuery.toLowerCase();
|
|
582
|
+
return (
|
|
583
|
+
node.item.label.toLowerCase().includes(query) ||
|
|
584
|
+
node.item.category.toLowerCase().includes(query)
|
|
585
|
+
);
|
|
586
|
+
};
|
|
587
|
+
|
|
588
|
+
// Node selection handler
|
|
589
|
+
const handleNodeSelection: OnNodeSelectionChange = async (node) => {
|
|
590
|
+
selectedNode = node;
|
|
591
|
+
console.log('Selected menu item:', node.item.label);
|
|
592
|
+
return true;
|
|
593
|
+
};
|
|
594
|
+
|
|
595
|
+
// Context menu handler
|
|
596
|
+
const handleContextMenu: OnContextMenu = (event, node) => {
|
|
597
|
+
event.preventDefault();
|
|
598
|
+
console.log('Context menu for:', node.item.label);
|
|
599
|
+
|
|
600
|
+
// You could show a custom context menu here
|
|
601
|
+
const menuItems = [
|
|
602
|
+
{ label: 'Edit', action: () => console.log('Edit', node.item.label) },
|
|
603
|
+
{ label: 'Delete', action: () => console.log('Delete', node.item.label) },
|
|
604
|
+
{ label: 'Duplicate', action: () => console.log('Duplicate', node.item.label) }
|
|
605
|
+
];
|
|
606
|
+
|
|
607
|
+
// Show context menu at cursor position
|
|
608
|
+
showContextMenu(event.clientX, event.clientY, menuItems);
|
|
609
|
+
};
|
|
610
|
+
|
|
611
|
+
function showContextMenu(x: number, y: number, items: any[]) {
|
|
612
|
+
// Implementation would show a context menu at the specified position
|
|
613
|
+
alert(`Context menu at (${x}, ${y})\nItems: ${items.map(i => i.label).join(', ')}`);
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
function clearSearch() {
|
|
617
|
+
searchQuery = '';
|
|
618
|
+
}
|
|
619
|
+
</script>
|
|
620
|
+
|
|
621
|
+
<div class="menu-manager">
|
|
622
|
+
<h2>Navigation Menu Manager</h2>
|
|
623
|
+
|
|
624
|
+
<div class="search-controls">
|
|
625
|
+
<input
|
|
626
|
+
type="text"
|
|
627
|
+
bind:value={searchQuery}
|
|
628
|
+
placeholder="Search menu items..."
|
|
629
|
+
class="search-input"
|
|
630
|
+
/>
|
|
631
|
+
{#if searchQuery}
|
|
632
|
+
<button on:click={clearSearch} class="clear-btn">Clear</button>
|
|
633
|
+
{/if}
|
|
634
|
+
</div>
|
|
635
|
+
|
|
636
|
+
<div class="tree-container">
|
|
637
|
+
<TreeView
|
|
638
|
+
nodes={menuStructure}
|
|
639
|
+
textField="label"
|
|
640
|
+
checkIsDirectory={checkIsDirectory}
|
|
641
|
+
isVisible={nodeVisibilityFilter}
|
|
642
|
+
onSelectionChange={handleNodeSelection}
|
|
643
|
+
onContextMenu={handleContextMenu}
|
|
644
|
+
style="height: 400px; border: 1px solid #ddd; padding: 12px; overflow-y: auto;"
|
|
645
|
+
/>
|
|
646
|
+
|
|
647
|
+
{#if selectedNode}
|
|
648
|
+
<div class="menu-item-details">
|
|
649
|
+
<h3>
|
|
650
|
+
{#if selectedNode.item.icon}
|
|
651
|
+
<span class="item-icon">{selectedNode.item.icon}</span>
|
|
652
|
+
{/if}
|
|
653
|
+
{selectedNode.item.label}
|
|
654
|
+
</h3>
|
|
655
|
+
<div class="details-grid">
|
|
656
|
+
<div class="detail-item">
|
|
657
|
+
<strong>ID:</strong> {selectedNode.item.id}
|
|
658
|
+
</div>
|
|
659
|
+
<div class="detail-item">
|
|
660
|
+
<strong>Category:</strong> {selectedNode.item.category}
|
|
661
|
+
</div>
|
|
662
|
+
<div class="detail-item">
|
|
663
|
+
<strong>Type:</strong> {checkIsDirectory(selectedNode) ? 'Menu Group' : 'Menu Item'}
|
|
664
|
+
</div>
|
|
665
|
+
{#if selectedNode.children}
|
|
666
|
+
<div class="detail-item">
|
|
667
|
+
<strong>Children:</strong> {selectedNode.children.length}
|
|
668
|
+
</div>
|
|
669
|
+
{/if}
|
|
670
|
+
</div>
|
|
671
|
+
|
|
672
|
+
<div class="action-buttons">
|
|
673
|
+
<button class="btn btn-primary">Edit</button>
|
|
674
|
+
<button class="btn btn-secondary">Duplicate</button>
|
|
675
|
+
<button class="btn btn-danger">Delete</button>
|
|
676
|
+
</div>
|
|
677
|
+
</div>
|
|
678
|
+
{/if}
|
|
679
|
+
</div>
|
|
680
|
+
</div>
|
|
681
|
+
|
|
682
|
+
<style>
|
|
683
|
+
.menu-manager {
|
|
684
|
+
max-width: 800px;
|
|
685
|
+
margin: 0 auto;
|
|
686
|
+
padding: 20px;
|
|
687
|
+
}
|
|
688
|
+
|
|
689
|
+
.search-controls {
|
|
690
|
+
display: flex;
|
|
691
|
+
gap: 8px;
|
|
692
|
+
margin-bottom: 16px;
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
.search-input {
|
|
696
|
+
flex: 1;
|
|
697
|
+
padding: 8px 12px;
|
|
698
|
+
border: 1px solid #ddd;
|
|
699
|
+
border-radius: 4px;
|
|
700
|
+
font-size: 14px;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
.clear-btn {
|
|
704
|
+
padding: 8px 16px;
|
|
705
|
+
background: #f8f9fa;
|
|
706
|
+
border: 1px solid #ddd;
|
|
707
|
+
border-radius: 4px;
|
|
708
|
+
cursor: pointer;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
.clear-btn:hover {
|
|
712
|
+
background: #e9ecef;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
.tree-container {
|
|
716
|
+
display: flex;
|
|
717
|
+
gap: 20px;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.menu-item-details {
|
|
721
|
+
flex: 0 0 300px;
|
|
722
|
+
padding: 20px;
|
|
723
|
+
background: #f8f9fa;
|
|
724
|
+
border-radius: 8px;
|
|
725
|
+
height: fit-content;
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
.menu-item-details h3 {
|
|
729
|
+
display: flex;
|
|
730
|
+
align-items: center;
|
|
731
|
+
gap: 8px;
|
|
732
|
+
margin: 0 0 16px 0;
|
|
733
|
+
color: #333;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
.item-icon {
|
|
737
|
+
font-size: 1.2em;
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.details-grid {
|
|
741
|
+
display: grid;
|
|
742
|
+
gap: 8px;
|
|
743
|
+
margin-bottom: 20px;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
.detail-item {
|
|
747
|
+
padding: 8px 0;
|
|
748
|
+
border-bottom: 1px solid #e9ecef;
|
|
749
|
+
color: #555;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
.action-buttons {
|
|
753
|
+
display: flex;
|
|
754
|
+
gap: 8px;
|
|
755
|
+
flex-wrap: wrap;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
.btn {
|
|
759
|
+
padding: 6px 12px;
|
|
760
|
+
border: none;
|
|
761
|
+
border-radius: 4px;
|
|
762
|
+
cursor: pointer;
|
|
763
|
+
font-size: 0.875rem;
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
.btn-primary {
|
|
767
|
+
background: #007bff;
|
|
768
|
+
color: white;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
.btn-secondary {
|
|
772
|
+
background: #6c757d;
|
|
773
|
+
color: white;
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
.btn-danger {
|
|
777
|
+
background: #dc3545;
|
|
778
|
+
color: white;
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
.btn:hover {
|
|
782
|
+
opacity: 0.8;
|
|
783
|
+
}
|
|
784
|
+
</style>
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
## Styling
|
|
788
|
+
|
|
789
|
+
The TreeView component uses the following CSS classes:
|
|
790
|
+
|
|
791
|
+
```css
|
|
792
|
+
.uniface-tree-view {
|
|
793
|
+
/* Main tree container */
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
/* Individual tree nodes are styled by the TreeNodeView component */
|
|
797
|
+
```
|
|
798
|
+
|
|
799
|
+
## API Reference
|
|
800
|
+
|
|
801
|
+
### TreeView Component Props
|
|
802
|
+
|
|
803
|
+
```typescript
|
|
804
|
+
interface TreeViewProps {
|
|
805
|
+
nodes: Array<TreeNode<any>>; // Tree nodes to display
|
|
806
|
+
textField: string | GetText<any>; // Field or function for node text
|
|
807
|
+
style?: string; // Custom styles
|
|
808
|
+
lazyLoader?: LazyLoader | null; // Lazy loading config
|
|
809
|
+
activeNode?: any; // Currently active node
|
|
810
|
+
class?: string; // CSS classes
|
|
811
|
+
isVisible?: NodeVisibleFun; // Node visibility filter
|
|
812
|
+
onSelectionChange?: OnNodeSelectionChange; // Selection callback
|
|
813
|
+
onContextMenu?: OnContextMenu; // Context menu callback
|
|
814
|
+
checkIsDirectory: CheckIsDirectory<any>; // Directory check function
|
|
815
|
+
}
|
|
816
|
+
```
|
|
817
|
+
|
|
818
|
+
## Integration with TreeNodes Utility
|
|
819
|
+
|
|
820
|
+
The TreeView component works seamlessly with the TreeNodes utility class for managing hierarchical data:
|
|
821
|
+
|
|
822
|
+
```svelte
|
|
823
|
+
<script lang="ts">
|
|
824
|
+
import TreeView from '@ticatec/uniface-element/TreeView';
|
|
825
|
+
import TreeNodes from '@ticatec/uniface-element/TreeNodes';
|
|
826
|
+
|
|
827
|
+
// Create TreeNodes instance for data management
|
|
828
|
+
const treeManager = new TreeNodes({
|
|
829
|
+
keyField: 'id',
|
|
830
|
+
parentKeyField: 'parentId',
|
|
831
|
+
textField: 'name',
|
|
832
|
+
checkIsRoot: (item) => !item.parentId,
|
|
833
|
+
checkIsDirectory: (node) => node.item.type === 'folder'
|
|
834
|
+
});
|
|
835
|
+
|
|
836
|
+
// Set flat data array - TreeNodes will build the hierarchy
|
|
837
|
+
let flatData = [
|
|
838
|
+
{ id: '1', name: 'Root', type: 'folder', parentId: null },
|
|
839
|
+
{ id: '2', name: 'Child 1', type: 'folder', parentId: '1' },
|
|
840
|
+
{ id: '3', name: 'File 1', type: 'file', parentId: '2' }
|
|
841
|
+
];
|
|
842
|
+
|
|
843
|
+
treeManager.setData(flatData);
|
|
844
|
+
let treeNodes = treeManager.nodes;
|
|
845
|
+
</script>
|
|
846
|
+
|
|
847
|
+
<TreeView
|
|
848
|
+
nodes={treeNodes}
|
|
849
|
+
textField="name"
|
|
850
|
+
checkIsDirectory={treeManager.checkIsDirectory}
|
|
851
|
+
/>
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
## Best Practices
|
|
855
|
+
|
|
856
|
+
1. **Performance** - Use lazy loading for large tree structures (>100 nodes)
|
|
857
|
+
2. **Node Text** - Use consistent text field or function for node display
|
|
858
|
+
3. **State Management** - Track active/selected nodes for user interaction
|
|
859
|
+
4. **Accessibility** - Ensure keyboard navigation support
|
|
860
|
+
5. **Error Handling** - Handle loading errors gracefully in lazy loader
|
|
861
|
+
6. **Visual Feedback** - Provide loading indicators during lazy loading
|
|
862
|
+
7. **Context Actions** - Implement context menus for node operations
|
|
863
|
+
8. **Filtering** - Use visibility functions for search/filter functionality
|