@neural-ui/core 1.3.2 → 1.5.0
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 +14 -7
- package/calendar/package.json +4 -0
- package/fesm2022/neural-ui-core-accordion.mjs +8 -6
- package/fesm2022/neural-ui-core-accordion.mjs.map +1 -1
- package/fesm2022/neural-ui-core-autocomplete.mjs +121 -29
- package/fesm2022/neural-ui-core-autocomplete.mjs.map +1 -1
- package/fesm2022/neural-ui-core-badge.mjs +2 -2
- package/fesm2022/neural-ui-core-badge.mjs.map +1 -1
- package/fesm2022/neural-ui-core-block-ui.mjs +2 -2
- package/fesm2022/neural-ui-core-button.mjs +2 -2
- package/fesm2022/neural-ui-core-button.mjs.map +1 -1
- package/fesm2022/neural-ui-core-calendar.mjs +551 -0
- package/fesm2022/neural-ui-core-calendar.mjs.map +1 -0
- package/fesm2022/neural-ui-core-chip.mjs +2 -2
- package/fesm2022/neural-ui-core-chip.mjs.map +1 -1
- package/fesm2022/neural-ui-core-color-picker.mjs +3 -9
- package/fesm2022/neural-ui-core-color-picker.mjs.map +1 -1
- package/fesm2022/neural-ui-core-confirm-dialog.mjs +2 -2
- package/fesm2022/neural-ui-core-confirm-dialog.mjs.map +1 -1
- package/fesm2022/neural-ui-core-dashboard-grid.mjs +2 -2
- package/fesm2022/neural-ui-core-dashboard-grid.mjs.map +1 -1
- package/fesm2022/neural-ui-core-date-input.mjs +2 -2
- package/fesm2022/neural-ui-core-date-input.mjs.map +1 -1
- package/fesm2022/neural-ui-core-filter-bar.mjs +2 -2
- package/fesm2022/neural-ui-core-filter-bar.mjs.map +1 -1
- package/fesm2022/neural-ui-core-image-gallery.mjs +224 -0
- package/fesm2022/neural-ui-core-image-gallery.mjs.map +1 -0
- package/fesm2022/neural-ui-core-input.mjs +2 -2
- package/fesm2022/neural-ui-core-kanban.mjs +270 -0
- package/fesm2022/neural-ui-core-kanban.mjs.map +1 -0
- package/fesm2022/neural-ui-core-meter-group.mjs +2 -2
- package/fesm2022/neural-ui-core-modal.mjs +81 -31
- package/fesm2022/neural-ui-core-modal.mjs.map +1 -1
- package/fesm2022/neural-ui-core-multiselect.mjs +269 -99
- package/fesm2022/neural-ui-core-multiselect.mjs.map +1 -1
- package/fesm2022/neural-ui-core-nav.mjs +4 -6
- package/fesm2022/neural-ui-core-nav.mjs.map +1 -1
- package/fesm2022/neural-ui-core-number-input.mjs +2 -2
- package/fesm2022/neural-ui-core-pagination.mjs +2 -2
- package/fesm2022/neural-ui-core-pagination.mjs.map +1 -1
- package/fesm2022/neural-ui-core-progress-bar.mjs +2 -2
- package/fesm2022/neural-ui-core-scheduler-gantt.mjs +289 -0
- package/fesm2022/neural-ui-core-scheduler-gantt.mjs.map +1 -0
- package/fesm2022/neural-ui-core-select.mjs +276 -101
- package/fesm2022/neural-ui-core-select.mjs.map +1 -1
- package/fesm2022/neural-ui-core-sidebar.mjs +3 -2
- package/fesm2022/neural-ui-core-sidebar.mjs.map +1 -1
- package/fesm2022/neural-ui-core-slider.mjs +2 -2
- package/fesm2022/neural-ui-core-slider.mjs.map +1 -1
- package/fesm2022/neural-ui-core-split-button.mjs +2 -2
- package/fesm2022/neural-ui-core-split-button.mjs.map +1 -1
- package/fesm2022/neural-ui-core-stepper.mjs +2 -2
- package/fesm2022/neural-ui-core-stepper.mjs.map +1 -1
- package/fesm2022/neural-ui-core-table.mjs +435 -34
- package/fesm2022/neural-ui-core-table.mjs.map +1 -1
- package/fesm2022/neural-ui-core-tabs.mjs +11 -4
- package/fesm2022/neural-ui-core-tabs.mjs.map +1 -1
- package/fesm2022/neural-ui-core-textarea.mjs +2 -2
- package/fesm2022/neural-ui-core-timeline-grid.mjs +215 -0
- package/fesm2022/neural-ui-core-timeline-grid.mjs.map +1 -0
- package/fesm2022/neural-ui-core-toggle-button-group.mjs +2 -2
- package/fesm2022/neural-ui-core-toggle-button-group.mjs.map +1 -1
- package/fesm2022/neural-ui-core-toolbar.mjs +2 -2
- package/fesm2022/neural-ui-core-toolbar.mjs.map +1 -1
- package/fesm2022/neural-ui-core-tree-table.mjs +262 -0
- package/fesm2022/neural-ui-core-tree-table.mjs.map +1 -0
- package/fesm2022/neural-ui-core-tree.mjs +413 -0
- package/fesm2022/neural-ui-core-tree.mjs.map +1 -0
- package/fesm2022/neural-ui-core-uploader.mjs +624 -0
- package/fesm2022/neural-ui-core-uploader.mjs.map +1 -0
- package/fesm2022/neural-ui-core-url-state.mjs +90 -10
- package/fesm2022/neural-ui-core-url-state.mjs.map +1 -1
- package/fesm2022/neural-ui-core-virtual-list.mjs +53 -23
- package/fesm2022/neural-ui-core-virtual-list.mjs.map +1 -1
- package/fesm2022/neural-ui-core.mjs +3 -1
- package/fesm2022/neural-ui-core.mjs.map +1 -1
- package/image-gallery/package.json +4 -0
- package/kanban/package.json +4 -0
- package/package.json +34 -2
- package/scheduler-gantt/package.json +4 -0
- package/styles/_tokens.scss +13 -4
- package/timeline-grid/package.json +4 -0
- package/tree/package.json +4 -0
- package/tree-table/package.json +4 -0
- package/types/neural-ui-core-autocomplete.d.ts +10 -1
- package/types/neural-ui-core-calendar.d.ts +79 -0
- package/types/neural-ui-core-color-picker.d.ts +0 -1
- package/types/neural-ui-core-image-gallery.d.ts +26 -0
- package/types/neural-ui-core-kanban.d.ts +52 -0
- package/types/neural-ui-core-modal.d.ts +22 -16
- package/types/neural-ui-core-multiselect.d.ts +13 -1
- package/types/neural-ui-core-scheduler-gantt.d.ts +68 -0
- package/types/neural-ui-core-select.d.ts +14 -1
- package/types/neural-ui-core-sidebar.d.ts +1 -0
- package/types/neural-ui-core-table.d.ts +66 -4
- package/types/neural-ui-core-tabs.d.ts +1 -0
- package/types/neural-ui-core-timeline-grid.d.ts +55 -0
- package/types/neural-ui-core-tree-table.d.ts +72 -0
- package/types/neural-ui-core-tree.d.ts +52 -0
- package/types/neural-ui-core-uploader.d.ts +98 -0
- package/types/neural-ui-core-url-state.d.ts +9 -0
- package/types/neural-ui-core-virtual-list.d.ts +17 -1
- package/uploader/package.json +4 -0
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { input, output, signal, computed, effect, ChangeDetectionStrategy, ViewEncapsulation, Component } from '@angular/core';
|
|
3
|
+
import { NgTemplateOutlet } from '@angular/common';
|
|
4
|
+
|
|
5
|
+
class NeuTreeComponent {
|
|
6
|
+
nodes = input([], ...(ngDevMode ? [{ debugName: "nodes" }] : /* istanbul ignore next */ []));
|
|
7
|
+
selectable = input(false, ...(ngDevMode ? [{ debugName: "selectable" }] : /* istanbul ignore next */ []));
|
|
8
|
+
searchable = input(false, ...(ngDevMode ? [{ debugName: "searchable" }] : /* istanbul ignore next */ []));
|
|
9
|
+
selectionMode = input('single', ...(ngDevMode ? [{ debugName: "selectionMode" }] : /* istanbul ignore next */ []));
|
|
10
|
+
indentSize = input(18, ...(ngDevMode ? [{ debugName: "indentSize" }] : /* istanbul ignore next */ []));
|
|
11
|
+
ariaLabel = input('Tree', ...(ngDevMode ? [{ debugName: "ariaLabel" }] : /* istanbul ignore next */ []));
|
|
12
|
+
searchPlaceholder = input('Search nodes', ...(ngDevMode ? [{ debugName: "searchPlaceholder" }] : /* istanbul ignore next */ []));
|
|
13
|
+
emptyLabel = input('No nodes available', ...(ngDevMode ? [{ debugName: "emptyLabel" }] : /* istanbul ignore next */ []));
|
|
14
|
+
expandLabel = input('Expand node', ...(ngDevMode ? [{ debugName: "expandLabel" }] : /* istanbul ignore next */ []));
|
|
15
|
+
collapseLabel = input('Collapse node', ...(ngDevMode ? [{ debugName: "collapseLabel" }] : /* istanbul ignore next */ []));
|
|
16
|
+
selectionChange = output();
|
|
17
|
+
expansionChange = output();
|
|
18
|
+
nodeClick = output();
|
|
19
|
+
searchQuery = signal('', ...(ngDevMode ? [{ debugName: "searchQuery" }] : /* istanbul ignore next */ []));
|
|
20
|
+
expandedKeys = signal(new Set(), ...(ngDevMode ? [{ debugName: "expandedKeys" }] : /* istanbul ignore next */ []));
|
|
21
|
+
selectedKeys = signal(new Set(), ...(ngDevMode ? [{ debugName: "selectedKeys" }] : /* istanbul ignore next */ []));
|
|
22
|
+
visibleNodes = computed(() => {
|
|
23
|
+
const query = this.searchQuery().trim().toLowerCase();
|
|
24
|
+
if (!query) {
|
|
25
|
+
return this.nodes();
|
|
26
|
+
}
|
|
27
|
+
return this.filterNodes(this.nodes(), query);
|
|
28
|
+
}, ...(ngDevMode ? [{ debugName: "visibleNodes" }] : /* istanbul ignore next */ []));
|
|
29
|
+
constructor() {
|
|
30
|
+
effect(() => {
|
|
31
|
+
const nextExpanded = this.collectExpandedKeys(this.nodes());
|
|
32
|
+
this.expandedKeys.set(nextExpanded);
|
|
33
|
+
this.selectedKeys.set(new Set());
|
|
34
|
+
this.searchQuery.set('');
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
hasChildren(node) {
|
|
38
|
+
return !!node.children?.length;
|
|
39
|
+
}
|
|
40
|
+
canSelect(node) {
|
|
41
|
+
return this.selectable() && node.selectable !== false;
|
|
42
|
+
}
|
|
43
|
+
isExpanded(nodeId) {
|
|
44
|
+
return this.expandedKeys().has(nodeId);
|
|
45
|
+
}
|
|
46
|
+
isRenderedExpanded(node) {
|
|
47
|
+
if (this.searchQuery().trim()) {
|
|
48
|
+
return node.expanded ?? this.isExpanded(node.id);
|
|
49
|
+
}
|
|
50
|
+
return this.isExpanded(node.id);
|
|
51
|
+
}
|
|
52
|
+
isSelected(nodeId) {
|
|
53
|
+
return this.selectedKeys().has(nodeId);
|
|
54
|
+
}
|
|
55
|
+
onSearch(event) {
|
|
56
|
+
const target = event.target;
|
|
57
|
+
this.searchQuery.set(target.value);
|
|
58
|
+
}
|
|
59
|
+
toggleNode(node, event) {
|
|
60
|
+
event?.stopPropagation();
|
|
61
|
+
if (node.disabled || !this.hasChildren(node)) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const next = new Set(this.expandedKeys());
|
|
65
|
+
if (next.has(node.id)) {
|
|
66
|
+
next.delete(node.id);
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
next.add(node.id);
|
|
70
|
+
}
|
|
71
|
+
this.expandedKeys.set(next);
|
|
72
|
+
this.expansionChange.emit([...next]);
|
|
73
|
+
}
|
|
74
|
+
activateNode(node) {
|
|
75
|
+
if (node.disabled) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
this.nodeClick.emit(node);
|
|
79
|
+
if (!this.canSelect(node)) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
if (this.selectionMode() === 'multiple') {
|
|
83
|
+
const checked = !this.isSelected(node.id);
|
|
84
|
+
this.updateSelection(node, checked);
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.updateSelection(node, true);
|
|
88
|
+
}
|
|
89
|
+
onCheckboxChange(node, event) {
|
|
90
|
+
const target = event.target;
|
|
91
|
+
this.updateSelection(node, target.checked);
|
|
92
|
+
}
|
|
93
|
+
updateSelection(node, checked) {
|
|
94
|
+
if (node.disabled || !this.canSelect(node)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const next = new Set(this.selectedKeys());
|
|
98
|
+
if (this.selectionMode() === 'single') {
|
|
99
|
+
next.clear();
|
|
100
|
+
if (checked) {
|
|
101
|
+
next.add(node.id);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
else if (checked) {
|
|
105
|
+
next.add(node.id);
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
next.delete(node.id);
|
|
109
|
+
}
|
|
110
|
+
this.selectedKeys.set(next);
|
|
111
|
+
this.selectionChange.emit(this.collectSelectedNodes(this.nodes(), next));
|
|
112
|
+
}
|
|
113
|
+
collectExpandedKeys(nodes) {
|
|
114
|
+
const expanded = new Set();
|
|
115
|
+
for (const node of nodes) {
|
|
116
|
+
if (node.expanded) {
|
|
117
|
+
expanded.add(node.id);
|
|
118
|
+
}
|
|
119
|
+
if (node.children?.length) {
|
|
120
|
+
for (const childId of this.collectExpandedKeys(node.children)) {
|
|
121
|
+
expanded.add(childId);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return expanded;
|
|
126
|
+
}
|
|
127
|
+
collectSelectedNodes(nodes, selected) {
|
|
128
|
+
const result = [];
|
|
129
|
+
for (const node of nodes) {
|
|
130
|
+
if (selected.has(node.id)) {
|
|
131
|
+
result.push(node);
|
|
132
|
+
}
|
|
133
|
+
if (node.children?.length) {
|
|
134
|
+
result.push(...this.collectSelectedNodes(node.children, selected));
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return result;
|
|
138
|
+
}
|
|
139
|
+
filterNodes(nodes, query) {
|
|
140
|
+
const filtered = [];
|
|
141
|
+
for (const node of nodes) {
|
|
142
|
+
const children = node.children?.length ? this.filterNodes(node.children, query) : [];
|
|
143
|
+
const matches = node.label.toLowerCase().includes(query) ||
|
|
144
|
+
node.description?.toLowerCase().includes(query) ||
|
|
145
|
+
node.badge?.toLowerCase().includes(query);
|
|
146
|
+
if (matches || children.length) {
|
|
147
|
+
filtered.push({
|
|
148
|
+
...node,
|
|
149
|
+
children,
|
|
150
|
+
expanded: children.length ? true : node.expanded,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return filtered;
|
|
155
|
+
}
|
|
156
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuTreeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
157
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.8", type: NeuTreeComponent, isStandalone: true, selector: "neu-tree", inputs: { nodes: { classPropertyName: "nodes", publicName: "nodes", isSignal: true, isRequired: false, transformFunction: null }, selectable: { classPropertyName: "selectable", publicName: "selectable", isSignal: true, isRequired: false, transformFunction: null }, searchable: { classPropertyName: "searchable", publicName: "searchable", isSignal: true, isRequired: false, transformFunction: null }, selectionMode: { classPropertyName: "selectionMode", publicName: "selectionMode", isSignal: true, isRequired: false, transformFunction: null }, indentSize: { classPropertyName: "indentSize", publicName: "indentSize", isSignal: true, isRequired: false, transformFunction: null }, ariaLabel: { classPropertyName: "ariaLabel", publicName: "ariaLabel", isSignal: true, isRequired: false, transformFunction: null }, searchPlaceholder: { classPropertyName: "searchPlaceholder", publicName: "searchPlaceholder", isSignal: true, isRequired: false, transformFunction: null }, emptyLabel: { classPropertyName: "emptyLabel", publicName: "emptyLabel", isSignal: true, isRequired: false, transformFunction: null }, expandLabel: { classPropertyName: "expandLabel", publicName: "expandLabel", isSignal: true, isRequired: false, transformFunction: null }, collapseLabel: { classPropertyName: "collapseLabel", publicName: "collapseLabel", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectionChange: "selectionChange", expansionChange: "expansionChange", nodeClick: "nodeClick" }, ngImport: i0, template: `
|
|
158
|
+
<div class="neu-tree">
|
|
159
|
+
@if (searchable()) {
|
|
160
|
+
<label class="neu-tree__search" [attr.aria-label]="searchPlaceholder()">
|
|
161
|
+
<svg
|
|
162
|
+
class="neu-tree__search-icon"
|
|
163
|
+
viewBox="0 0 24 24"
|
|
164
|
+
fill="none"
|
|
165
|
+
stroke="currentColor"
|
|
166
|
+
stroke-width="2"
|
|
167
|
+
stroke-linecap="round"
|
|
168
|
+
stroke-linejoin="round"
|
|
169
|
+
aria-hidden="true"
|
|
170
|
+
>
|
|
171
|
+
<circle cx="11" cy="11" r="7"></circle>
|
|
172
|
+
<path d="m20 20-3.5-3.5"></path>
|
|
173
|
+
</svg>
|
|
174
|
+
<input
|
|
175
|
+
class="neu-tree__search-input"
|
|
176
|
+
type="search"
|
|
177
|
+
[value]="searchQuery()"
|
|
178
|
+
[attr.placeholder]="searchPlaceholder()"
|
|
179
|
+
(input)="onSearch($event)"
|
|
180
|
+
/>
|
|
181
|
+
</label>
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
@if (visibleNodes().length) {
|
|
185
|
+
<ul
|
|
186
|
+
class="neu-tree__list neu-tree__list--root"
|
|
187
|
+
role="tree"
|
|
188
|
+
[attr.aria-label]="ariaLabel()"
|
|
189
|
+
[attr.aria-multiselectable]="
|
|
190
|
+
selectable() && selectionMode() === 'multiple' ? 'true' : null
|
|
191
|
+
"
|
|
192
|
+
>
|
|
193
|
+
<ng-container
|
|
194
|
+
[ngTemplateOutlet]="treeNodes"
|
|
195
|
+
[ngTemplateOutletContext]="{ $implicit: visibleNodes(), level: 1 }"
|
|
196
|
+
/>
|
|
197
|
+
</ul>
|
|
198
|
+
} @else {
|
|
199
|
+
<div class="neu-tree__empty">{{ emptyLabel() }}</div>
|
|
200
|
+
}
|
|
201
|
+
</div>
|
|
202
|
+
|
|
203
|
+
<ng-template #treeNodes let-nodes let-level="level">
|
|
204
|
+
@for (node of nodes; track node.id) {
|
|
205
|
+
<li
|
|
206
|
+
class="neu-tree__node"
|
|
207
|
+
role="treeitem"
|
|
208
|
+
[attr.aria-level]="level"
|
|
209
|
+
[attr.aria-expanded]="hasChildren(node) ? isRenderedExpanded(node) : null"
|
|
210
|
+
[attr.aria-selected]="canSelect(node) ? isSelected(node.id) : null"
|
|
211
|
+
[attr.aria-disabled]="node.disabled ? 'true' : null"
|
|
212
|
+
>
|
|
213
|
+
<div
|
|
214
|
+
class="neu-tree__row"
|
|
215
|
+
[class.neu-tree__row--selected]="isSelected(node.id)"
|
|
216
|
+
[class.neu-tree__row--disabled]="node.disabled"
|
|
217
|
+
[style.padding-inline-start.px]="(level - 1) * indentSize() + 6"
|
|
218
|
+
>
|
|
219
|
+
@if (hasChildren(node)) {
|
|
220
|
+
<button
|
|
221
|
+
class="neu-tree__toggle"
|
|
222
|
+
type="button"
|
|
223
|
+
[class.neu-tree__toggle--open]="isRenderedExpanded(node)"
|
|
224
|
+
[attr.aria-label]="isRenderedExpanded(node) ? collapseLabel() : expandLabel()"
|
|
225
|
+
(click)="toggleNode(node, $event)"
|
|
226
|
+
>
|
|
227
|
+
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
|
228
|
+
<path d="m7 5 6 5-6 5" />
|
|
229
|
+
</svg>
|
|
230
|
+
</button>
|
|
231
|
+
} @else {
|
|
232
|
+
<span
|
|
233
|
+
class="neu-tree__toggle neu-tree__toggle--placeholder"
|
|
234
|
+
aria-hidden="true"
|
|
235
|
+
></span>
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
@if (canSelect(node) && selectionMode() === 'multiple') {
|
|
239
|
+
<input
|
|
240
|
+
class="neu-tree__checkbox"
|
|
241
|
+
type="checkbox"
|
|
242
|
+
[attr.aria-label]="'Select ' + node.label"
|
|
243
|
+
[checked]="isSelected(node.id)"
|
|
244
|
+
[disabled]="node.disabled"
|
|
245
|
+
(click)="$event.stopPropagation()"
|
|
246
|
+
(change)="onCheckboxChange(node, $event)"
|
|
247
|
+
/>
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
<button
|
|
251
|
+
class="neu-tree__content"
|
|
252
|
+
type="button"
|
|
253
|
+
[disabled]="node.disabled"
|
|
254
|
+
(click)="activateNode(node)"
|
|
255
|
+
>
|
|
256
|
+
<span class="neu-tree__main">
|
|
257
|
+
<span class="neu-tree__label">{{ node.label }}</span>
|
|
258
|
+
@if (node.badge) {
|
|
259
|
+
<span class="neu-tree__badge">{{ node.badge }}</span>
|
|
260
|
+
}
|
|
261
|
+
</span>
|
|
262
|
+
@if (node.description) {
|
|
263
|
+
<span class="neu-tree__description">{{ node.description }}</span>
|
|
264
|
+
}
|
|
265
|
+
</button>
|
|
266
|
+
</div>
|
|
267
|
+
|
|
268
|
+
@if (hasChildren(node) && isRenderedExpanded(node)) {
|
|
269
|
+
<ul class="neu-tree__list" role="group">
|
|
270
|
+
<ng-container
|
|
271
|
+
[ngTemplateOutlet]="treeNodes"
|
|
272
|
+
[ngTemplateOutletContext]="{ $implicit: node.children ?? [], level: level + 1 }"
|
|
273
|
+
/>
|
|
274
|
+
</ul>
|
|
275
|
+
}
|
|
276
|
+
</li>
|
|
277
|
+
}
|
|
278
|
+
</ng-template>
|
|
279
|
+
`, isInline: true, styles: [".neu-tree{display:flex;flex-direction:column;gap:.75rem;min-width:0}.neu-tree__search{position:relative;display:flex;align-items:center}.neu-tree__search-icon{position:absolute;left:.875rem;width:.9375rem;height:.9375rem;color:var(--neu-text-muted);pointer-events:none}.neu-tree__search-input{width:100%;min-height:2.625rem;border:1px solid var(--neu-border);border-radius:var(--neu-radius-lg, 14px);background:var(--neu-surface);color:var(--neu-text);padding:.6875rem .875rem .6875rem 2.4rem;outline:none;transition:border-color .16s ease,box-shadow .16s ease,background-color .16s ease}.neu-tree__search-input::placeholder{color:var(--neu-text-muted)}.neu-tree__search-input:focus{border-color:color-mix(in srgb,var(--neu-primary) 62%,var(--neu-border));box-shadow:0 0 0 3px color-mix(in srgb,var(--neu-primary) 16%,transparent)}.neu-tree__list{list-style:none;margin:0;padding:0}.neu-tree__list--root{display:flex;flex-direction:column;gap:.375rem}.neu-tree__node{position:relative}.neu-tree__row{display:flex;align-items:flex-start;gap:.5rem;min-width:0;border-radius:calc(var(--neu-radius-lg, 14px) - 2px);transition:background-color .16s ease,border-color .16s ease,box-shadow .16s ease}.neu-tree__row:hover{background:color-mix(in srgb,var(--neu-primary) 5%,var(--neu-surface))}.neu-tree__row--selected{background:color-mix(in srgb,var(--neu-primary) 10%,var(--neu-surface));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--neu-primary) 20%,var(--neu-border))}.neu-tree__row--disabled{opacity:.6}.neu-tree__toggle{flex:0 0 auto;width:1.75rem;height:1.75rem;margin-top:.4rem;border:0;border-radius:999px;background:transparent;color:var(--neu-text-muted);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:background-color .16s ease,color .16s ease,transform .16s ease}.neu-tree__toggle svg{width:.95rem;height:.95rem;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;transition:transform .16s ease}.neu-tree__toggle:hover{background:color-mix(in srgb,var(--neu-primary) 9%,transparent);color:var(--neu-primary)}.neu-tree__toggle--open svg{transform:rotate(90deg)}.neu-tree__toggle--placeholder{cursor:default}.neu-tree__checkbox{flex:0 0 auto;width:1rem;height:1rem;margin:.8rem 0 0;accent-color:var(--neu-primary)}.neu-tree__content{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:.125rem;border:0;background:transparent;text-align:left;padding:.55rem .75rem .6rem 0;color:inherit;cursor:pointer}.neu-tree__main{display:inline-flex;align-items:center;gap:.5rem;min-width:0}.neu-tree__label{font-size:.9375rem;font-weight:600;color:var(--neu-text)}.neu-tree__badge{display:inline-flex;align-items:center;min-height:1.25rem;padding:0 .45rem;border-radius:999px;background:color-mix(in srgb,var(--neu-primary) 12%,transparent);color:var(--neu-primary);font-size:.6875rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.neu-tree__description{color:var(--neu-text-muted);font-size:.8125rem;line-height:1.45}.neu-tree__empty{border:1px dashed var(--neu-border);border-radius:var(--neu-radius-lg, 14px);background:color-mix(in srgb,var(--neu-surface-2) 72%,transparent);color:var(--neu-text-muted);padding:1rem 1.125rem;font-size:.875rem}.neu-tree__node>.neu-tree__list{margin-top:.125rem}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
|
|
280
|
+
}
|
|
281
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.8", ngImport: i0, type: NeuTreeComponent, decorators: [{
|
|
282
|
+
type: Component,
|
|
283
|
+
args: [{ selector: 'neu-tree', standalone: true, imports: [NgTemplateOutlet], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: `
|
|
284
|
+
<div class="neu-tree">
|
|
285
|
+
@if (searchable()) {
|
|
286
|
+
<label class="neu-tree__search" [attr.aria-label]="searchPlaceholder()">
|
|
287
|
+
<svg
|
|
288
|
+
class="neu-tree__search-icon"
|
|
289
|
+
viewBox="0 0 24 24"
|
|
290
|
+
fill="none"
|
|
291
|
+
stroke="currentColor"
|
|
292
|
+
stroke-width="2"
|
|
293
|
+
stroke-linecap="round"
|
|
294
|
+
stroke-linejoin="round"
|
|
295
|
+
aria-hidden="true"
|
|
296
|
+
>
|
|
297
|
+
<circle cx="11" cy="11" r="7"></circle>
|
|
298
|
+
<path d="m20 20-3.5-3.5"></path>
|
|
299
|
+
</svg>
|
|
300
|
+
<input
|
|
301
|
+
class="neu-tree__search-input"
|
|
302
|
+
type="search"
|
|
303
|
+
[value]="searchQuery()"
|
|
304
|
+
[attr.placeholder]="searchPlaceholder()"
|
|
305
|
+
(input)="onSearch($event)"
|
|
306
|
+
/>
|
|
307
|
+
</label>
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
@if (visibleNodes().length) {
|
|
311
|
+
<ul
|
|
312
|
+
class="neu-tree__list neu-tree__list--root"
|
|
313
|
+
role="tree"
|
|
314
|
+
[attr.aria-label]="ariaLabel()"
|
|
315
|
+
[attr.aria-multiselectable]="
|
|
316
|
+
selectable() && selectionMode() === 'multiple' ? 'true' : null
|
|
317
|
+
"
|
|
318
|
+
>
|
|
319
|
+
<ng-container
|
|
320
|
+
[ngTemplateOutlet]="treeNodes"
|
|
321
|
+
[ngTemplateOutletContext]="{ $implicit: visibleNodes(), level: 1 }"
|
|
322
|
+
/>
|
|
323
|
+
</ul>
|
|
324
|
+
} @else {
|
|
325
|
+
<div class="neu-tree__empty">{{ emptyLabel() }}</div>
|
|
326
|
+
}
|
|
327
|
+
</div>
|
|
328
|
+
|
|
329
|
+
<ng-template #treeNodes let-nodes let-level="level">
|
|
330
|
+
@for (node of nodes; track node.id) {
|
|
331
|
+
<li
|
|
332
|
+
class="neu-tree__node"
|
|
333
|
+
role="treeitem"
|
|
334
|
+
[attr.aria-level]="level"
|
|
335
|
+
[attr.aria-expanded]="hasChildren(node) ? isRenderedExpanded(node) : null"
|
|
336
|
+
[attr.aria-selected]="canSelect(node) ? isSelected(node.id) : null"
|
|
337
|
+
[attr.aria-disabled]="node.disabled ? 'true' : null"
|
|
338
|
+
>
|
|
339
|
+
<div
|
|
340
|
+
class="neu-tree__row"
|
|
341
|
+
[class.neu-tree__row--selected]="isSelected(node.id)"
|
|
342
|
+
[class.neu-tree__row--disabled]="node.disabled"
|
|
343
|
+
[style.padding-inline-start.px]="(level - 1) * indentSize() + 6"
|
|
344
|
+
>
|
|
345
|
+
@if (hasChildren(node)) {
|
|
346
|
+
<button
|
|
347
|
+
class="neu-tree__toggle"
|
|
348
|
+
type="button"
|
|
349
|
+
[class.neu-tree__toggle--open]="isRenderedExpanded(node)"
|
|
350
|
+
[attr.aria-label]="isRenderedExpanded(node) ? collapseLabel() : expandLabel()"
|
|
351
|
+
(click)="toggleNode(node, $event)"
|
|
352
|
+
>
|
|
353
|
+
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
|
354
|
+
<path d="m7 5 6 5-6 5" />
|
|
355
|
+
</svg>
|
|
356
|
+
</button>
|
|
357
|
+
} @else {
|
|
358
|
+
<span
|
|
359
|
+
class="neu-tree__toggle neu-tree__toggle--placeholder"
|
|
360
|
+
aria-hidden="true"
|
|
361
|
+
></span>
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
@if (canSelect(node) && selectionMode() === 'multiple') {
|
|
365
|
+
<input
|
|
366
|
+
class="neu-tree__checkbox"
|
|
367
|
+
type="checkbox"
|
|
368
|
+
[attr.aria-label]="'Select ' + node.label"
|
|
369
|
+
[checked]="isSelected(node.id)"
|
|
370
|
+
[disabled]="node.disabled"
|
|
371
|
+
(click)="$event.stopPropagation()"
|
|
372
|
+
(change)="onCheckboxChange(node, $event)"
|
|
373
|
+
/>
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
<button
|
|
377
|
+
class="neu-tree__content"
|
|
378
|
+
type="button"
|
|
379
|
+
[disabled]="node.disabled"
|
|
380
|
+
(click)="activateNode(node)"
|
|
381
|
+
>
|
|
382
|
+
<span class="neu-tree__main">
|
|
383
|
+
<span class="neu-tree__label">{{ node.label }}</span>
|
|
384
|
+
@if (node.badge) {
|
|
385
|
+
<span class="neu-tree__badge">{{ node.badge }}</span>
|
|
386
|
+
}
|
|
387
|
+
</span>
|
|
388
|
+
@if (node.description) {
|
|
389
|
+
<span class="neu-tree__description">{{ node.description }}</span>
|
|
390
|
+
}
|
|
391
|
+
</button>
|
|
392
|
+
</div>
|
|
393
|
+
|
|
394
|
+
@if (hasChildren(node) && isRenderedExpanded(node)) {
|
|
395
|
+
<ul class="neu-tree__list" role="group">
|
|
396
|
+
<ng-container
|
|
397
|
+
[ngTemplateOutlet]="treeNodes"
|
|
398
|
+
[ngTemplateOutletContext]="{ $implicit: node.children ?? [], level: level + 1 }"
|
|
399
|
+
/>
|
|
400
|
+
</ul>
|
|
401
|
+
}
|
|
402
|
+
</li>
|
|
403
|
+
}
|
|
404
|
+
</ng-template>
|
|
405
|
+
`, styles: [".neu-tree{display:flex;flex-direction:column;gap:.75rem;min-width:0}.neu-tree__search{position:relative;display:flex;align-items:center}.neu-tree__search-icon{position:absolute;left:.875rem;width:.9375rem;height:.9375rem;color:var(--neu-text-muted);pointer-events:none}.neu-tree__search-input{width:100%;min-height:2.625rem;border:1px solid var(--neu-border);border-radius:var(--neu-radius-lg, 14px);background:var(--neu-surface);color:var(--neu-text);padding:.6875rem .875rem .6875rem 2.4rem;outline:none;transition:border-color .16s ease,box-shadow .16s ease,background-color .16s ease}.neu-tree__search-input::placeholder{color:var(--neu-text-muted)}.neu-tree__search-input:focus{border-color:color-mix(in srgb,var(--neu-primary) 62%,var(--neu-border));box-shadow:0 0 0 3px color-mix(in srgb,var(--neu-primary) 16%,transparent)}.neu-tree__list{list-style:none;margin:0;padding:0}.neu-tree__list--root{display:flex;flex-direction:column;gap:.375rem}.neu-tree__node{position:relative}.neu-tree__row{display:flex;align-items:flex-start;gap:.5rem;min-width:0;border-radius:calc(var(--neu-radius-lg, 14px) - 2px);transition:background-color .16s ease,border-color .16s ease,box-shadow .16s ease}.neu-tree__row:hover{background:color-mix(in srgb,var(--neu-primary) 5%,var(--neu-surface))}.neu-tree__row--selected{background:color-mix(in srgb,var(--neu-primary) 10%,var(--neu-surface));box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--neu-primary) 20%,var(--neu-border))}.neu-tree__row--disabled{opacity:.6}.neu-tree__toggle{flex:0 0 auto;width:1.75rem;height:1.75rem;margin-top:.4rem;border:0;border-radius:999px;background:transparent;color:var(--neu-text-muted);display:inline-flex;align-items:center;justify-content:center;cursor:pointer;transition:background-color .16s ease,color .16s ease,transform .16s ease}.neu-tree__toggle svg{width:.95rem;height:.95rem;stroke:currentColor;stroke-width:1.9;stroke-linecap:round;stroke-linejoin:round;transition:transform .16s ease}.neu-tree__toggle:hover{background:color-mix(in srgb,var(--neu-primary) 9%,transparent);color:var(--neu-primary)}.neu-tree__toggle--open svg{transform:rotate(90deg)}.neu-tree__toggle--placeholder{cursor:default}.neu-tree__checkbox{flex:0 0 auto;width:1rem;height:1rem;margin:.8rem 0 0;accent-color:var(--neu-primary)}.neu-tree__content{flex:1 1 auto;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:.125rem;border:0;background:transparent;text-align:left;padding:.55rem .75rem .6rem 0;color:inherit;cursor:pointer}.neu-tree__main{display:inline-flex;align-items:center;gap:.5rem;min-width:0}.neu-tree__label{font-size:.9375rem;font-weight:600;color:var(--neu-text)}.neu-tree__badge{display:inline-flex;align-items:center;min-height:1.25rem;padding:0 .45rem;border-radius:999px;background:color-mix(in srgb,var(--neu-primary) 12%,transparent);color:var(--neu-primary);font-size:.6875rem;font-weight:700;letter-spacing:.04em;text-transform:uppercase}.neu-tree__description{color:var(--neu-text-muted);font-size:.8125rem;line-height:1.45}.neu-tree__empty{border:1px dashed var(--neu-border);border-radius:var(--neu-radius-lg, 14px);background:color-mix(in srgb,var(--neu-surface-2) 72%,transparent);color:var(--neu-text-muted);padding:1rem 1.125rem;font-size:.875rem}.neu-tree__node>.neu-tree__list{margin-top:.125rem}\n"] }]
|
|
406
|
+
}], ctorParameters: () => [], propDecorators: { nodes: [{ type: i0.Input, args: [{ isSignal: true, alias: "nodes", required: false }] }], selectable: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectable", required: false }] }], searchable: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchable", required: false }] }], selectionMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectionMode", required: false }] }], indentSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "indentSize", required: false }] }], ariaLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "ariaLabel", required: false }] }], searchPlaceholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "searchPlaceholder", required: false }] }], emptyLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyLabel", required: false }] }], expandLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "expandLabel", required: false }] }], collapseLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "collapseLabel", required: false }] }], selectionChange: [{ type: i0.Output, args: ["selectionChange"] }], expansionChange: [{ type: i0.Output, args: ["expansionChange"] }], nodeClick: [{ type: i0.Output, args: ["nodeClick"] }] } });
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Generated bundle index. Do not edit.
|
|
410
|
+
*/
|
|
411
|
+
|
|
412
|
+
export { NeuTreeComponent };
|
|
413
|
+
//# sourceMappingURL=neural-ui-core-tree.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"neural-ui-core-tree.mjs","sources":["../../../../projects/ui-core/tree/neu-tree.component.ts","../../../../projects/ui-core/tree/neural-ui-core-tree.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n computed,\n effect,\n input,\n output,\n signal,\n ViewEncapsulation,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\n\nexport interface NeuTreeNode<T = unknown> {\n id: string;\n label: string;\n description?: string;\n badge?: string;\n children?: NeuTreeNode<T>[];\n disabled?: boolean;\n expanded?: boolean;\n selectable?: boolean;\n data?: T;\n}\n\nexport type NeuTreeSelectionMode = 'single' | 'multiple';\n\n@Component({\n selector: 'neu-tree',\n standalone: true,\n imports: [NgTemplateOutlet],\n encapsulation: ViewEncapsulation.None,\n changeDetection: ChangeDetectionStrategy.OnPush,\n template: `\n <div class=\"neu-tree\">\n @if (searchable()) {\n <label class=\"neu-tree__search\" [attr.aria-label]=\"searchPlaceholder()\">\n <svg\n class=\"neu-tree__search-icon\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n aria-hidden=\"true\"\n >\n <circle cx=\"11\" cy=\"11\" r=\"7\"></circle>\n <path d=\"m20 20-3.5-3.5\"></path>\n </svg>\n <input\n class=\"neu-tree__search-input\"\n type=\"search\"\n [value]=\"searchQuery()\"\n [attr.placeholder]=\"searchPlaceholder()\"\n (input)=\"onSearch($event)\"\n />\n </label>\n }\n\n @if (visibleNodes().length) {\n <ul\n class=\"neu-tree__list neu-tree__list--root\"\n role=\"tree\"\n [attr.aria-label]=\"ariaLabel()\"\n [attr.aria-multiselectable]=\"\n selectable() && selectionMode() === 'multiple' ? 'true' : null\n \"\n >\n <ng-container\n [ngTemplateOutlet]=\"treeNodes\"\n [ngTemplateOutletContext]=\"{ $implicit: visibleNodes(), level: 1 }\"\n />\n </ul>\n } @else {\n <div class=\"neu-tree__empty\">{{ emptyLabel() }}</div>\n }\n </div>\n\n <ng-template #treeNodes let-nodes let-level=\"level\">\n @for (node of nodes; track node.id) {\n <li\n class=\"neu-tree__node\"\n role=\"treeitem\"\n [attr.aria-level]=\"level\"\n [attr.aria-expanded]=\"hasChildren(node) ? isRenderedExpanded(node) : null\"\n [attr.aria-selected]=\"canSelect(node) ? isSelected(node.id) : null\"\n [attr.aria-disabled]=\"node.disabled ? 'true' : null\"\n >\n <div\n class=\"neu-tree__row\"\n [class.neu-tree__row--selected]=\"isSelected(node.id)\"\n [class.neu-tree__row--disabled]=\"node.disabled\"\n [style.padding-inline-start.px]=\"(level - 1) * indentSize() + 6\"\n >\n @if (hasChildren(node)) {\n <button\n class=\"neu-tree__toggle\"\n type=\"button\"\n [class.neu-tree__toggle--open]=\"isRenderedExpanded(node)\"\n [attr.aria-label]=\"isRenderedExpanded(node) ? collapseLabel() : expandLabel()\"\n (click)=\"toggleNode(node, $event)\"\n >\n <svg viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"m7 5 6 5-6 5\" />\n </svg>\n </button>\n } @else {\n <span\n class=\"neu-tree__toggle neu-tree__toggle--placeholder\"\n aria-hidden=\"true\"\n ></span>\n }\n\n @if (canSelect(node) && selectionMode() === 'multiple') {\n <input\n class=\"neu-tree__checkbox\"\n type=\"checkbox\"\n [attr.aria-label]=\"'Select ' + node.label\"\n [checked]=\"isSelected(node.id)\"\n [disabled]=\"node.disabled\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"onCheckboxChange(node, $event)\"\n />\n }\n\n <button\n class=\"neu-tree__content\"\n type=\"button\"\n [disabled]=\"node.disabled\"\n (click)=\"activateNode(node)\"\n >\n <span class=\"neu-tree__main\">\n <span class=\"neu-tree__label\">{{ node.label }}</span>\n @if (node.badge) {\n <span class=\"neu-tree__badge\">{{ node.badge }}</span>\n }\n </span>\n @if (node.description) {\n <span class=\"neu-tree__description\">{{ node.description }}</span>\n }\n </button>\n </div>\n\n @if (hasChildren(node) && isRenderedExpanded(node)) {\n <ul class=\"neu-tree__list\" role=\"group\">\n <ng-container\n [ngTemplateOutlet]=\"treeNodes\"\n [ngTemplateOutletContext]=\"{ $implicit: node.children ?? [], level: level + 1 }\"\n />\n </ul>\n }\n </li>\n }\n </ng-template>\n `,\n styleUrl: './neu-tree.component.scss',\n})\nexport class NeuTreeComponent {\n nodes = input<NeuTreeNode[]>([]);\n selectable = input(false);\n searchable = input(false);\n selectionMode = input<NeuTreeSelectionMode>('single');\n indentSize = input(18);\n ariaLabel = input('Tree');\n searchPlaceholder = input('Search nodes');\n emptyLabel = input('No nodes available');\n expandLabel = input('Expand node');\n collapseLabel = input('Collapse node');\n\n selectionChange = output<NeuTreeNode[]>();\n expansionChange = output<string[]>();\n nodeClick = output<NeuTreeNode>();\n\n readonly searchQuery = signal('');\n\n private readonly expandedKeys = signal<Set<string>>(new Set());\n private readonly selectedKeys = signal<Set<string>>(new Set());\n\n readonly visibleNodes = computed(() => {\n const query = this.searchQuery().trim().toLowerCase();\n if (!query) {\n return this.nodes();\n }\n\n return this.filterNodes(this.nodes(), query);\n });\n\n constructor() {\n effect(() => {\n const nextExpanded = this.collectExpandedKeys(this.nodes());\n this.expandedKeys.set(nextExpanded);\n this.selectedKeys.set(new Set());\n this.searchQuery.set('');\n });\n }\n\n hasChildren(node: NeuTreeNode): boolean {\n return !!node.children?.length;\n }\n\n canSelect(node: NeuTreeNode): boolean {\n return this.selectable() && node.selectable !== false;\n }\n\n isExpanded(nodeId: string): boolean {\n return this.expandedKeys().has(nodeId);\n }\n\n isRenderedExpanded(node: NeuTreeNode): boolean {\n if (this.searchQuery().trim()) {\n return node.expanded ?? this.isExpanded(node.id);\n }\n\n return this.isExpanded(node.id);\n }\n\n isSelected(nodeId: string): boolean {\n return this.selectedKeys().has(nodeId);\n }\n\n onSearch(event: Event): void {\n const target = event.target as HTMLInputElement;\n this.searchQuery.set(target.value);\n }\n\n toggleNode(node: NeuTreeNode, event?: Event): void {\n event?.stopPropagation();\n if (node.disabled || !this.hasChildren(node)) {\n return;\n }\n\n const next = new Set(this.expandedKeys());\n if (next.has(node.id)) {\n next.delete(node.id);\n } else {\n next.add(node.id);\n }\n\n this.expandedKeys.set(next);\n this.expansionChange.emit([...next]);\n }\n\n activateNode(node: NeuTreeNode): void {\n if (node.disabled) {\n return;\n }\n\n this.nodeClick.emit(node);\n\n if (!this.canSelect(node)) {\n return;\n }\n\n if (this.selectionMode() === 'multiple') {\n const checked = !this.isSelected(node.id);\n this.updateSelection(node, checked);\n return;\n }\n\n this.updateSelection(node, true);\n }\n\n onCheckboxChange(node: NeuTreeNode, event: Event): void {\n const target = event.target as HTMLInputElement;\n this.updateSelection(node, target.checked);\n }\n\n private updateSelection(node: NeuTreeNode, checked: boolean): void {\n if (node.disabled || !this.canSelect(node)) {\n return;\n }\n\n const next = new Set(this.selectedKeys());\n\n if (this.selectionMode() === 'single') {\n next.clear();\n if (checked) {\n next.add(node.id);\n }\n } else if (checked) {\n next.add(node.id);\n } else {\n next.delete(node.id);\n }\n\n this.selectedKeys.set(next);\n this.selectionChange.emit(this.collectSelectedNodes(this.nodes(), next));\n }\n\n private collectExpandedKeys(nodes: NeuTreeNode[]): Set<string> {\n const expanded = new Set<string>();\n for (const node of nodes) {\n if (node.expanded) {\n expanded.add(node.id);\n }\n if (node.children?.length) {\n for (const childId of this.collectExpandedKeys(node.children)) {\n expanded.add(childId);\n }\n }\n }\n return expanded;\n }\n\n private collectSelectedNodes(nodes: NeuTreeNode[], selected: Set<string>): NeuTreeNode[] {\n const result: NeuTreeNode[] = [];\n for (const node of nodes) {\n if (selected.has(node.id)) {\n result.push(node);\n }\n if (node.children?.length) {\n result.push(...this.collectSelectedNodes(node.children, selected));\n }\n }\n return result;\n }\n\n private filterNodes(nodes: NeuTreeNode[], query: string): NeuTreeNode[] {\n const filtered: NeuTreeNode[] = [];\n for (const node of nodes) {\n const children = node.children?.length ? this.filterNodes(node.children, query) : [];\n const matches =\n node.label.toLowerCase().includes(query) ||\n node.description?.toLowerCase().includes(query) ||\n node.badge?.toLowerCase().includes(query);\n\n if (matches || children.length) {\n filtered.push({\n ...node,\n children,\n expanded: children.length ? true : node.expanded,\n });\n }\n }\n return filtered;\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public_api';\n"],"names":[],"mappings":"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"}
|