concepto-user-controls 0.0.8 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/esm2022/lib/concepto-tree/components/tree-node/tree-node.component.mjs +301 -0
  2. package/esm2022/lib/concepto-tree/components/tree-node-checkbox/tree-node-checkbox.component.mjs +90 -0
  3. package/esm2022/lib/concepto-tree/components/tree-node-content/tree-node-content.component.mjs +65 -0
  4. package/esm2022/lib/concepto-tree/components/tree-node-expander/tree-node-expander.component.mjs +74 -0
  5. package/esm2022/lib/concepto-tree/components/tree-root/tree-root.component.mjs +230 -0
  6. package/esm2022/lib/concepto-tree/components/tree-viewport/tree-viewport.component.mjs +216 -0
  7. package/esm2022/lib/concepto-tree/concepto-tree.component.mjs +214 -13
  8. package/esm2022/lib/concepto-tree/core/models/tree-events.model.mjs +2 -0
  9. package/esm2022/lib/concepto-tree/core/models/tree-node.model.mjs +102 -0
  10. package/esm2022/lib/concepto-tree/core/models/tree-options.model.mjs +24 -0
  11. package/esm2022/lib/concepto-tree/core/models/tree.model.mjs +313 -0
  12. package/esm2022/lib/concepto-tree/core/services/tree-drag-drop.service.mjs +27 -0
  13. package/esm2022/lib/concepto-tree/directives/tree-drag.directive.mjs +69 -0
  14. package/esm2022/lib/concepto-tree/directives/tree-drop.directive.mjs +124 -0
  15. package/esm2022/lib/concepto-tree/directives/tree-node-template.directive.mjs +19 -0
  16. package/fesm2022/concepto-user-controls.mjs +1818 -12
  17. package/fesm2022/concepto-user-controls.mjs.map +1 -1
  18. package/lib/concepto-tree/components/tree-node/tree-node.component.d.ts +19 -0
  19. package/lib/concepto-tree/components/tree-node-checkbox/tree-node-checkbox.component.d.ts +17 -0
  20. package/lib/concepto-tree/components/tree-node-content/tree-node-content.component.d.ts +18 -0
  21. package/lib/concepto-tree/components/tree-node-expander/tree-node-expander.component.d.ts +12 -0
  22. package/lib/concepto-tree/components/tree-root/tree-root.component.d.ts +35 -0
  23. package/lib/concepto-tree/components/tree-viewport/tree-viewport.component.d.ts +33 -0
  24. package/lib/concepto-tree/concepto-tree.component.d.ts +32 -1
  25. package/lib/concepto-tree/core/models/tree-events.model.d.ts +13 -0
  26. package/lib/concepto-tree/core/models/tree-node.model.d.ts +39 -0
  27. package/lib/concepto-tree/core/models/tree-options.model.d.ts +28 -0
  28. package/lib/concepto-tree/core/models/tree.model.d.ts +54 -0
  29. package/lib/concepto-tree/core/services/tree-drag-drop.service.d.ts +11 -0
  30. package/lib/concepto-tree/directives/tree-drag.directive.d.ts +16 -0
  31. package/lib/concepto-tree/directives/tree-drop.directive.d.ts +25 -0
  32. package/lib/concepto-tree/directives/tree-node-template.directive.d.ts +8 -0
  33. package/package.json +1 -1
@@ -0,0 +1,301 @@
1
+ // lib/components/tree-node/tree-node.component.ts
2
+ import { Component, Input, ChangeDetectionStrategy, computed, } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import { trigger, state, style, transition, animate } from '@angular/animations';
5
+ import { TreeNodeExpanderComponent } from '../tree-node-expander/tree-node-expander.component';
6
+ import { TreeNodeCheckboxComponent } from '../tree-node-checkbox/tree-node-checkbox.component';
7
+ import { TreeNodeContentComponent } from '../tree-node-content/tree-node-content.component';
8
+ import { TreeDragDirective } from '../../directives/tree-drag.directive';
9
+ import { TreeDropDirective } from '../../directives/tree-drop.directive';
10
+ import * as i0 from "@angular/core";
11
+ export class TreeNodeComponent {
12
+ node;
13
+ treeModel;
14
+ options;
15
+ nodeTemplate;
16
+ paddingLeft = computed(() => {
17
+ return this.options.levelPadding || 40;
18
+ });
19
+ onNodeClick(event) {
20
+ const useMetaKey = this.options.useMetaKey !== false;
21
+ const multiSelect = this.options.multiSelect || false;
22
+ const isMetaKeyPressed = event.ctrlKey || event.metaKey;
23
+ const shouldMultiSelect = multiSelect && (!useMetaKey || isMetaKeyPressed);
24
+ this.treeModel.activateNode(this.node, shouldMultiSelect);
25
+ this.treeModel.focusNode(this.node);
26
+ }
27
+ onNodeDoubleClick(event) {
28
+ if (this.node.hasChildren) {
29
+ this.node.toggle();
30
+ this.treeModel.expandedNodeIds.update(ids => {
31
+ const newIds = new Set(ids);
32
+ if (this.node.isExpanded()) {
33
+ newIds.add(this.node.id);
34
+ }
35
+ else {
36
+ newIds.delete(this.node.id);
37
+ }
38
+ return newIds;
39
+ });
40
+ }
41
+ }
42
+ onNodeContextMenu(event) {
43
+ event.preventDefault();
44
+ // Emit context menu event
45
+ }
46
+ onToggleExpanded() {
47
+ if (this.node.hasChildren) {
48
+ this.node.toggle();
49
+ if (this.node.isExpanded()) {
50
+ // Load children if needed
51
+ if (this.options.getChildren && this.node.children.length === 0) {
52
+ this.treeModel.loadChildren(this.node);
53
+ }
54
+ this.treeModel.expandNode(this.node);
55
+ }
56
+ else {
57
+ this.treeModel.collapseNode(this.node);
58
+ }
59
+ }
60
+ }
61
+ onCheckboxChange(checked) {
62
+ this.treeModel.selectNode(this.node, this.options.multiSelect || false);
63
+ }
64
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeNodeComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
65
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: TreeNodeComponent, isStandalone: true, selector: "tree-node", inputs: { node: "node", treeModel: "treeModel", options: "options", nodeTemplate: "nodeTemplate" }, ngImport: i0, template: `
66
+ <div
67
+ class="tree-node"
68
+ [class.tree-node-expanded]="node.isExpanded()"
69
+ [class.tree-node-collapsed]="node.isCollapsed()"
70
+ [class.tree-node-active]="node.isActive()"
71
+ [class.tree-node-focused]="node.isFocused()"
72
+ [class.tree-node-leaf]="node.isLeaf()"
73
+ [class.tree-node-loading]="node.isLoading()"
74
+ [style.padding-left.px]="paddingLeft()">
75
+
76
+ <div class="tree-node-wrapper"
77
+ [treeDrag]="node"
78
+ [treeModel]="treeModel"
79
+ [options]="options">
80
+
81
+ <!-- Drop zone before node -->
82
+ <div class="tree-node-drop-slot tree-node-drop-slot-before"
83
+ [treeDrop]="node"
84
+ [treeModel]="treeModel"
85
+ [dropPosition]="'before'"
86
+ [options]="options">
87
+ </div>
88
+
89
+ <!-- Node content wrapper -->
90
+ <div class="tree-node-content-wrapper"
91
+ (click)="onNodeClick($event)"
92
+ (dblclick)="onNodeDoubleClick($event)"
93
+ (contextmenu)="onNodeContextMenu($event)">
94
+
95
+ <!-- Expander -->
96
+ @if (node.hasChildren) {
97
+ <tree-node-expander
98
+ [node]="node"
99
+ [treeModel]="treeModel"
100
+ (toggle)="onToggleExpanded()">
101
+ </tree-node-expander>
102
+ }
103
+
104
+ <!-- Checkbox -->
105
+ @if (options.useCheckbox) {
106
+ <tree-node-checkbox
107
+ [node]="node"
108
+ [treeModel]="treeModel"
109
+ [useTriState]="options.useTriState ?? false"
110
+ (change)="onCheckboxChange($event)">
111
+ </tree-node-checkbox>
112
+ }
113
+
114
+ <!-- Content -->
115
+ <tree-node-content
116
+ [node]="node"
117
+ [treeModel]="treeModel"
118
+ [template]="nodeTemplate"
119
+ [displayField]="options.displayField || 'name'">
120
+ </tree-node-content>
121
+ </div>
122
+
123
+ <!-- Drop zone after node -->
124
+ <div class="tree-node-drop-slot tree-node-drop-slot-after"
125
+ [treeDrop]="node"
126
+ [treeModel]="treeModel"
127
+ [dropPosition]="'after'"
128
+ [options]="options">
129
+ </div>
130
+ </div>
131
+
132
+ <!-- Children container -->
133
+ @if (node.isExpanded() && node.children.length > 0) {
134
+ <div class="tree-node-children"
135
+ [@expandCollapse]="node.isExpanded() ? 'expanded' : 'collapsed'">
136
+ @for (child of node.children; track child.id) {
137
+ <tree-node
138
+ [node]="child"
139
+ [treeModel]="treeModel"
140
+ [options]="options"
141
+ [nodeTemplate]="nodeTemplate">
142
+ </tree-node>
143
+ }
144
+ </div>
145
+ }
146
+
147
+ <!-- Loading indicator -->
148
+ @if (node.isLoading()) {
149
+ <div class="tree-node-loading">
150
+ <span class="loading-spinner"></span>
151
+ Loading...
152
+ </div>
153
+ }
154
+ </div>
155
+ `, isInline: true, styles: [".tree-node{position:relative}.tree-node-wrapper{position:relative;display:flex;align-items:center;min-height:22px}.tree-node-content-wrapper{display:flex;align-items:center;flex:1;cursor:pointer;border-radius:3px;padding:2px 4px;transition:background-color .15s}.tree-node-content-wrapper:hover{background-color:#f5f5f5}.tree-node-active .tree-node-content-wrapper{background-color:#e3f2fd}.tree-node-focused .tree-node-content-wrapper{outline:2px solid #2196f3;outline-offset:-2px}.tree-node-children{overflow:hidden}.tree-node-drop-slot{position:absolute;left:0;right:0;height:2px;z-index:10}.tree-node-drop-slot-before{top:-1px}.tree-node-drop-slot-after{bottom:-1px}.tree-node-loading{padding:8px 24px;display:flex;align-items:center;gap:8px;color:#666;font-size:14px}.loading-spinner{display:inline-block;width:16px;height:16px;border:2px solid #f3f3f3;border-top:2px solid #2196f3;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "component", type: TreeNodeComponent, selector: "tree-node", inputs: ["node", "treeModel", "options", "nodeTemplate"] }, { kind: "ngmodule", type: CommonModule }, { kind: "component", type: TreeNodeExpanderComponent, selector: "tree-node-expander", inputs: ["node", "treeModel"], outputs: ["toggle"] }, { kind: "component", type: TreeNodeCheckboxComponent, selector: "tree-node-checkbox", inputs: ["node", "treeModel", "useTriState"], outputs: ["change"] }, { kind: "component", type: TreeNodeContentComponent, selector: "tree-node-content", inputs: ["node", "treeModel", "template", "displayField"] }, { kind: "directive", type: TreeDragDirective, selector: "[treeDrag]", inputs: ["treeDrag", "treeModel", "options"] }, { kind: "directive", type: TreeDropDirective, selector: "[treeDrop]", inputs: ["treeDrop", "treeModel", "options", "dropPosition"] }], animations: [
156
+ trigger('expandCollapse', [
157
+ state('collapsed', style({
158
+ height: '0',
159
+ overflow: 'hidden',
160
+ opacity: '0'
161
+ })),
162
+ state('expanded', style({
163
+ height: '*',
164
+ overflow: 'visible',
165
+ opacity: '1'
166
+ })),
167
+ transition('collapsed <=> expanded', [
168
+ animate('200ms ease-in-out')
169
+ ])
170
+ ])
171
+ ], changeDetection: i0.ChangeDetectionStrategy.OnPush });
172
+ }
173
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeNodeComponent, decorators: [{
174
+ type: Component,
175
+ args: [{ selector: 'tree-node', standalone: true, imports: [
176
+ CommonModule,
177
+ TreeNodeExpanderComponent,
178
+ TreeNodeCheckboxComponent,
179
+ TreeNodeContentComponent,
180
+ TreeDragDirective,
181
+ TreeDropDirective,
182
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: `
183
+ <div
184
+ class="tree-node"
185
+ [class.tree-node-expanded]="node.isExpanded()"
186
+ [class.tree-node-collapsed]="node.isCollapsed()"
187
+ [class.tree-node-active]="node.isActive()"
188
+ [class.tree-node-focused]="node.isFocused()"
189
+ [class.tree-node-leaf]="node.isLeaf()"
190
+ [class.tree-node-loading]="node.isLoading()"
191
+ [style.padding-left.px]="paddingLeft()">
192
+
193
+ <div class="tree-node-wrapper"
194
+ [treeDrag]="node"
195
+ [treeModel]="treeModel"
196
+ [options]="options">
197
+
198
+ <!-- Drop zone before node -->
199
+ <div class="tree-node-drop-slot tree-node-drop-slot-before"
200
+ [treeDrop]="node"
201
+ [treeModel]="treeModel"
202
+ [dropPosition]="'before'"
203
+ [options]="options">
204
+ </div>
205
+
206
+ <!-- Node content wrapper -->
207
+ <div class="tree-node-content-wrapper"
208
+ (click)="onNodeClick($event)"
209
+ (dblclick)="onNodeDoubleClick($event)"
210
+ (contextmenu)="onNodeContextMenu($event)">
211
+
212
+ <!-- Expander -->
213
+ @if (node.hasChildren) {
214
+ <tree-node-expander
215
+ [node]="node"
216
+ [treeModel]="treeModel"
217
+ (toggle)="onToggleExpanded()">
218
+ </tree-node-expander>
219
+ }
220
+
221
+ <!-- Checkbox -->
222
+ @if (options.useCheckbox) {
223
+ <tree-node-checkbox
224
+ [node]="node"
225
+ [treeModel]="treeModel"
226
+ [useTriState]="options.useTriState ?? false"
227
+ (change)="onCheckboxChange($event)">
228
+ </tree-node-checkbox>
229
+ }
230
+
231
+ <!-- Content -->
232
+ <tree-node-content
233
+ [node]="node"
234
+ [treeModel]="treeModel"
235
+ [template]="nodeTemplate"
236
+ [displayField]="options.displayField || 'name'">
237
+ </tree-node-content>
238
+ </div>
239
+
240
+ <!-- Drop zone after node -->
241
+ <div class="tree-node-drop-slot tree-node-drop-slot-after"
242
+ [treeDrop]="node"
243
+ [treeModel]="treeModel"
244
+ [dropPosition]="'after'"
245
+ [options]="options">
246
+ </div>
247
+ </div>
248
+
249
+ <!-- Children container -->
250
+ @if (node.isExpanded() && node.children.length > 0) {
251
+ <div class="tree-node-children"
252
+ [@expandCollapse]="node.isExpanded() ? 'expanded' : 'collapsed'">
253
+ @for (child of node.children; track child.id) {
254
+ <tree-node
255
+ [node]="child"
256
+ [treeModel]="treeModel"
257
+ [options]="options"
258
+ [nodeTemplate]="nodeTemplate">
259
+ </tree-node>
260
+ }
261
+ </div>
262
+ }
263
+
264
+ <!-- Loading indicator -->
265
+ @if (node.isLoading()) {
266
+ <div class="tree-node-loading">
267
+ <span class="loading-spinner"></span>
268
+ Loading...
269
+ </div>
270
+ }
271
+ </div>
272
+ `, animations: [
273
+ trigger('expandCollapse', [
274
+ state('collapsed', style({
275
+ height: '0',
276
+ overflow: 'hidden',
277
+ opacity: '0'
278
+ })),
279
+ state('expanded', style({
280
+ height: '*',
281
+ overflow: 'visible',
282
+ opacity: '1'
283
+ })),
284
+ transition('collapsed <=> expanded', [
285
+ animate('200ms ease-in-out')
286
+ ])
287
+ ])
288
+ ], styles: [".tree-node{position:relative}.tree-node-wrapper{position:relative;display:flex;align-items:center;min-height:22px}.tree-node-content-wrapper{display:flex;align-items:center;flex:1;cursor:pointer;border-radius:3px;padding:2px 4px;transition:background-color .15s}.tree-node-content-wrapper:hover{background-color:#f5f5f5}.tree-node-active .tree-node-content-wrapper{background-color:#e3f2fd}.tree-node-focused .tree-node-content-wrapper{outline:2px solid #2196f3;outline-offset:-2px}.tree-node-children{overflow:hidden}.tree-node-drop-slot{position:absolute;left:0;right:0;height:2px;z-index:10}.tree-node-drop-slot-before{top:-1px}.tree-node-drop-slot-after{bottom:-1px}.tree-node-loading{padding:8px 24px;display:flex;align-items:center;gap:8px;color:#666;font-size:14px}.loading-spinner{display:inline-block;width:16px;height:16px;border:2px solid #f3f3f3;border-top:2px solid #2196f3;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
289
+ }], propDecorators: { node: [{
290
+ type: Input,
291
+ args: [{ required: true }]
292
+ }], treeModel: [{
293
+ type: Input,
294
+ args: [{ required: true }]
295
+ }], options: [{
296
+ type: Input,
297
+ args: [{ required: true }]
298
+ }], nodeTemplate: [{
299
+ type: Input
300
+ }] } });
301
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS1ub2RlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NvbmNlcHRvLXVzZXItY29udHJvbHMvc3JjL2xpYi9jb25jZXB0by10cmVlL2NvbXBvbmVudHMvdHJlZS1ub2RlL3RyZWUtbm9kZS5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsa0RBQWtEO0FBQ2xELE9BQU8sRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUVMLHVCQUF1QixFQUN2QixRQUFRLEdBQ1QsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFJakYsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sb0RBQW9ELENBQUM7QUFDL0YsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sb0RBQW9ELENBQUM7QUFDL0YsT0FBTyxFQUFFLHdCQUF3QixFQUFFLE1BQU0sa0RBQWtELENBQUM7QUFDNUYsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sc0NBQXNDLENBQUM7QUFDekUsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sc0NBQXNDLENBQUM7O0FBME16RSxNQUFNLE9BQU8saUJBQWlCO0lBQ0QsSUFBSSxDQUFZO0lBQ2hCLFNBQVMsQ0FBYTtJQUN0QixPQUFPLENBQWU7SUFDeEMsWUFBWSxDQUFvQjtJQUVoQyxXQUFXLEdBQUcsUUFBUSxDQUFDLEdBQUcsRUFBRTtRQUNuQyxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxJQUFJLEVBQUUsQ0FBQztJQUN6QyxDQUFDLENBQUMsQ0FBQztJQUVILFdBQVcsQ0FBQyxLQUFpQjtRQUMzQixNQUFNLFVBQVUsR0FBRyxJQUFJLENB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QUFDOzRCQUNILFVBQVUsQ0FBQyx3QkFBd0IsRUFBRTtnQ0FDbkMsT0FBTyxDQUFDLG1CQUFtQixDQUFDOzZCQUM3QixDQUFDO3lCQUNILENBQUM7cUJBQ0g7OEJBRzBCLElBQUk7c0JBQTlCLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQUNFLFNBQVM7c0JBQW5DLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQUNFLE9BQU87c0JBQWpDLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQUNoQixZQUFZO3NCQUFwQixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiLy8gbGliL2NvbXBvbmVudHMvdHJlZS1ub2RlL3RyZWUtbm9kZS5jb21wb25lbnQudHNcclxuaW1wb3J0IHtcclxuICBDb21wb25lbnQsXHJcbiAgSW5wdXQsXHJcbiAgVGVtcGxhdGVSZWYsXHJcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXHJcbiAgY29tcHV0ZWQsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IHRyaWdnZXIsIHN0YXRlLCBzdHlsZSwgdHJhbnNpdGlvbiwgYW5pbWF0ZSB9IGZyb20gJ0Bhbmd1bGFyL2FuaW1hdGlvbnMnO1xyXG5pbXBvcnQgeyBUcmVlTm9kZSB9IGZyb20gJy4uLy4uL2NvcmUvbW9kZWxzL3RyZWUtbm9kZS5tb2RlbCc7XHJcbmltcG9ydCB7IFRyZWVNb2RlbCB9IGZyb20gJy4uLy4uL2NvcmUvbW9kZWxzL3RyZWUubW9kZWwnO1xyXG5pbXBvcnQgeyBUcmVlT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvcmUvbW9kZWxzL3RyZWUtb3B0aW9ucy5tb2RlbCc7XHJcbmltcG9ydCB7IFRyZWVOb2RlRXhwYW5kZXJDb21wb25lbnQgfSBmcm9tICcuLi90cmVlLW5vZGUtZXhwYW5kZXIvdHJlZS1ub2RlLWV4cGFuZGVyLmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IFRyZWVOb2RlQ2hlY2tib3hDb21wb25lbnQgfSBmcm9tICcuLi90cmVlLW5vZGUtY2hlY2tib3gvdHJlZS1ub2RlLWNoZWNrYm94LmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IFRyZWVOb2RlQ29udGVudENvbXBvbmVudCB9IGZyb20gJy4uL3RyZWUtbm9kZS1jb250ZW50L3RyZWUtbm9kZS1jb250ZW50LmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IFRyZWVEcmFnRGlyZWN0aXZlIH0gZnJvbSAnLi4vLi4vZGlyZWN0aXZlcy90cmVlLWRyYWcuZGlyZWN0aXZlJztcclxuaW1wb3J0IHsgVHJlZURyb3BEaXJlY3RpdmUgfSBmcm9tICcuLi8uLi9kaXJlY3RpdmVzL3RyZWUtZHJvcC5kaXJlY3RpdmUnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICd0cmVlLW5vZGUnLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW1xyXG4gICAgQ29tbW9uTW9kdWxlLFxyXG4gICAgVHJlZU5vZGVFeHBhbmRlckNvbXBvbmVudCxcclxuICAgIFRyZWVOb2RlQ2hlY2tib3hDb21wb25lbnQsXHJcbiAgICBUcmVlTm9kZUNvbnRlbnRDb21wb25lbnQsXHJcbiAgICBUcmVlRHJhZ0RpcmVjdGl2ZSxcclxuICAgIFRyZWVEcm9wRGlyZWN0aXZlLFxyXG4gIF0sXHJcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXHJcbiAgdGVtcGxhdGU6IGBcclxuICAgIDxkaXYgXHJcbiAgICAgIGNsYXNzPVwidHJlZS1ub2RlXCJcclxuICAgICAgW2NsYXNzLnRyZWUtbm9kZS1leHBhbmRlZF09XCJub2RlLmlzRXhwYW5kZWQoKVwiXHJcbiAgICAgIFtjbGFzcy50cmVlLW5vZGUtY29sbGFwc2VkXT1cIm5vZGUuaXNDb2xsYXBzZWQoKVwiXHJcbiAgICAgIFtjbGFzcy50cmVlLW5vZGUtYWN0aXZlXT1cIm5vZGUuaXNBY3RpdmUoKVwiXHJcbiAgICAgIFtjbGFzcy50cmVlLW5vZGUtZm9jdXNlZF09XCJub2RlLmlzRm9jdXNlZCgpXCJcclxuICAgICAgW2NsYXNzLnRyZWUtbm9kZS1sZWFmXT1cIm5vZGUuaXNMZWFmKClcIlxyXG4gICAgICBbY2xhc3MudHJlZS1ub2RlLWxvYWRpbmddPVwibm9kZS5pc0xvYWRpbmcoKVwiXHJcbiAgICAgIFtzdHlsZS5wYWRkaW5nLWxlZnQucHhdPVwicGFkZGluZ0xlZnQoKVwiPlxyXG4gICAgICBcclxuICAgICAgPGRpdiBjbGFzcz1cInRyZWUtbm9kZS13cmFwcGVyXCJcclxuICAgICAgICAgICBbdHJlZURyYWddPVwibm9kZVwiXHJcbiAgICAgICAgICAgW3RyZWVNb2RlbF09XCJ0cmVlTW9kZWxcIlxyXG4gICAgICAgICAgIFtvcHRpb25zXT1cIm9wdGlvbnNcIj5cclxuICAgICAgICBcclxuICAgICAgICA8IS0tIERyb3Agem9uZSBiZWZvcmUgbm9kZSAtLT5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwidHJlZS1ub2RlLWRyb3Atc2xvdCB0cmVlLW5vZGUtZHJvcC1zbG90LWJlZm9yZVwiXHJcbiAgICAgICAgICAgICBbdHJlZURyb3BdPVwibm9kZVwiXHJcbiAgICAgICAgICAgICBbdHJlZU1vZGVsXT1cInRyZWVNb2RlbFwiXHJcbiAgICAgICAgICAgICBbZHJvcFBvc2l0aW9uXT1cIidiZWZvcmUnXCJcclxuICAgICAgICAgICAgIFtvcHRpb25zXT1cIm9wdGlvbnNcIj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgICBcclxuICAgICAgICA8IS0tIE5vZGUgY29udGVudCB3cmFwcGVyIC0tPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0cmVlLW5vZGUtY29udGVudC13cmFwcGVyXCJcclxuICAgICAgICAgICAgIChjbGljayk9XCJvbk5vZGVDbGljaygkZXZlbnQpXCJcclxuICAgICAgICAgICAgIChkYmxjbGljayk9XCJvbk5vZGVEb3VibGVDbGljaygkZXZlbnQpXCJcclxuICAgICAgICAgICAgIChjb250ZXh0bWVudSk9XCJvbk5vZGVDb250ZXh0TWVudSgkZXZlbnQpXCI+XHJcbiAgICAgICAgICBcclxuICAgICAgICAgIDwhLS0gRXhwYW5kZXIgLS0+XHJcbiAgICAgICAgICBAaWYgKG5vZGUuaGFzQ2hpbGRyZW4pIHtcclxuICAgICAgICAgICAgPHRyZWUtbm9kZS1leHBhbmRlclxyXG4gICAgICAgICAgICAgIFtub2RlXT1cIm5vZGVcIlxyXG4gICAgICAgICAgICAgIFt0cmVlTW9kZWxdPVwidHJlZU1vZGVsXCJcclxuICAgICAgICAgICAgICAodG9nZ2xlKT1cIm9uVG9nZ2xlRXhwYW5kZWQoKVwiPlxyXG4gICAgICAgICAgICA8L3RyZWUtbm9kZS1leHBhbmRlcj5cclxuICAgICAgICAgIH1cclxuICAgICAgICAgIFxyXG4gICAgICAgICAgPCEtLSBDaGVja2JveCAtLT5cclxuICAgICAgICAgIEBpZiAob3B0aW9ucy51c2VDaGVja2JveCkge1xyXG4gICAgICAgICAgICA8dHJlZS1ub2RlLWNoZWNrYm94XHJcbiAgICAgICAgICAgICAgW25vZGVdPVwibm9kZVwiXHJcbiAgICAgICAgICAgICAgW3RyZWVNb2RlbF09XCJ0cmVlTW9kZWxcIlxyXG4gICAgICAgICAgICAgIFt1c2VUcmlTdGF0ZV09XCJvcHRpb25zLnVzZVRyaVN0YXRlID8/IGZhbHNlXCJcclxuICAgICAgICAgICAgICAoY2hhbmdlKT1cIm9uQ2hlY2tib3hDaGFuZ2UoJGV2ZW50KVwiPlxyXG4gICAgICAgICAgICA8L3RyZWUtbm9kZS1jaGVja2JveD5cclxuICAgICAgICAgIH1cclxuICAgICAgICAgIFxyXG4gICAgICAgICAgPCEtLSBDb250ZW50IC0tPlxyXG4gICAgICAgICAgPHRyZWUtbm9kZS1jb250ZW50XHJcbiAgICAgICAgICAgIFtub2RlXT1cIm5vZGVcIlxyXG4gICAgICAgICAgICBbdHJlZU1vZGVsXT1cInRyZWVNb2RlbFwiXHJcbiAgICAgICAgICAgIFt0ZW1wbGF0ZV09XCJub2RlVGVtcGxhdGVcIlxyXG4gICAgICAgICAgICBbZGlzcGxheUZpZWxkXT1cIm9wdGlvbnMuZGlzcGxheUZpZWxkIHx8ICduYW1lJ1wiPlxyXG4gICAgICAgICAgPC90cmVlLW5vZGUtY29udGVudD5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgICBcclxuICAgICAgICA8IS0tIERyb3Agem9uZSBhZnRlciBub2RlIC0tPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJ0cmVlLW5vZGUtZHJvcC1zbG90IHRyZWUtbm9kZS1kcm9wLXNsb3QtYWZ0ZXJcIlxyXG4gICAgICAgICAgICAgW3RyZWVEcm9wXT1cIm5vZGVcIlxyXG4gICAgICAgICAgICAgW3RyZWVNb2RlbF09XCJ0cmVlTW9kZWxcIlxyXG4gICAgICAgICAgICAgW2Ryb3BQb3NpdGlvbl09XCInYWZ0ZXInXCJcclxuICAgICAgICAgICAgIFtvcHRpb25zXT1cIm9wdGlvbnNcIj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgPC9kaXY+XHJcbiAgICAgIFxyXG4gICAgICA8IS0tIENoaWxkcmVuIGNvbnRhaW5lciAtLT5cclxuICAgICAgQGlmIChub2RlLmlzRXhwYW5kZWQoKSAmJiBub2RlLmNoaWxkcmVuLmxlbmd0aCA+IDApIHtcclxuICAgICAgICA8ZGl2IGNsYXNzPVwidHJlZS1ub2RlLWNoaWxkcmVuXCJcclxuICAgICAgICAgICAgIFtAZXhwYW5kQ29sbGFwc2VdPVwibm9kZS5pc0V4cGFuZGVkKCkgPyAnZXhwYW5kZWQnIDogJ2NvbGxhcHNlZCdcIj5cclxuICAgICAgICAgIEBmb3IgKGNoaWxkIG9mIG5vZGUuY2hpbGRyZW47IHRyYWNrIGNoaWxkLmlkKSB7XHJcbiAgICAgICAgICAgIDx0cmVlLW5vZGVcclxuICAgICAgICAgICAgICBbbm9kZV09XCJjaGlsZFwiXHJcbiAgICAgICAgICAgICAgW3RyZWVNb2RlbF09XCJ0cmVlTW9kZWxcIlxyXG4gICAgICAgICAgICAgIFtvcHRpb25zXT1cIm9wdGlvbnNcIlxyXG4gICAgICAgICAgICAgIFtub2RlVGVtcGxhdGVdPVwibm9kZVRlbXBsYXRlXCI+XHJcbiAgICAgICAgICAgIDwvdHJlZS1ub2RlPlxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICB9XHJcbiAgICAgIFxyXG4gICAgICA8IS0tIExvYWRpbmcgaW5kaWNhdG9yIC0tPlxyXG4gICAgICBAaWYgKG5vZGUuaXNMb2FkaW5nKCkpIHtcclxuICAgICAgICA8ZGl2IGNsYXNzPVwidHJlZS1ub2RlLWxvYWRpbmdcIj5cclxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwibG9hZGluZy1zcGlubmVyXCI+PC9zcGFuPlxyXG4gICAgICAgICAgTG9hZGluZy4uLlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICB9XHJcbiAgICA8L2Rpdj5cclxuICBgLFxyXG4gIHN0eWxlczogW2BcclxuICAgIC50cmVlLW5vZGUge1xyXG4gICAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIC50cmVlLW5vZGUtd3JhcHBlciB7XHJcbiAgICAgIHBvc2l0aW9uOiByZWxhdGl2ZTtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAgbWluLWhlaWdodDogMjJweDtcclxuICAgIH1cclxuICAgIFxyXG4gICAgLnRyZWUtbm9kZS1jb250ZW50LXdyYXBwZXIge1xyXG4gICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICBmbGV4OiAxO1xyXG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICAgIGJvcmRlci1yYWRpdXM6IDNweDtcclxuICAgICAgcGFkZGluZzogMnB4IDRweDtcclxuICAgICAgdHJhbnNpdGlvbjogYmFja2dyb3VuZC1jb2xvciAwLjE1cztcclxuICAgIH1cclxuICAgIFxyXG4gICAgLnRyZWUtbm9kZS1jb250ZW50LXdyYXBwZXI6aG92ZXIge1xyXG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiAjZjVmNWY1O1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICAudHJlZS1ub2RlLWFjdGl2ZSAudHJlZS1ub2RlLWNvbnRlbnQtd3JhcHBlciB7XHJcbiAgICAgIGJhY2tncm91bmQtY29sb3I6ICNlM2YyZmQ7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIC50cmVlLW5vZGUtZm9jdXNlZCAudHJlZS1ub2RlLWNvbnRlbnQtd3JhcHBlciB7XHJcbiAgICAgIG91dGxpbmU6IDJweCBzb2xpZCAjMjE5NmYzO1xyXG4gICAgICBvdXRsaW5lLW9mZnNldDogLTJweDtcclxuICAgIH1cclxuICAgIFxyXG4gICAgLnRyZWUtbm9kZS1jaGlsZHJlbiB7XHJcbiAgICAgIG92ZXJmbG93OiBoaWRkZW47XHJcbiAgICB9XHJcbiAgICBcclxuICAgIC50cmVlLW5vZGUtZHJvcC1zbG90IHtcclxuICAgICAgcG9zaXRpb246IGFic29sdXRlO1xyXG4gICAgICBsZWZ0OiAwO1xyXG4gICAgICByaWdodDogMDtcclxuICAgICAgaGVpZ2h0OiAycHg7XHJcbiAgICAgIHotaW5kZXg6IDEwO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICAudHJlZS1ub2RlLWRyb3Atc2xvdC1iZWZvcmUge1xyXG4gICAgICB0b3A6IC0xcHg7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIC50cmVlLW5vZGUtZHJvcC1zbG90LWFmdGVyIHtcclxuICAgICAgYm90dG9tOiAtMXB4O1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICAudHJlZS1ub2RlLWxvYWRpbmcge1xyXG4gICAgICBwYWRkaW5nOiA4cHggMjRweDtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAgZ2FwOiA4cHg7XHJcbiAgICAgIGNvbG9yOiAjNjY2O1xyXG4gICAgICBmb250LXNpemU6IDE0cHg7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIC5sb2FkaW5nLXNwaW5uZXIge1xyXG4gICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XHJcbiAgICAgIHdpZHRoOiAxNnB4O1xyXG4gICAgICBoZWlnaHQ6IDE2cHg7XHJcbiAgICAgIGJvcmRlcjogMnB4IHNvbGlkICNmM2YzZjM7XHJcbiAgICAgIGJvcmRlci10b3A6IDJweCBzb2xpZCAjMjE5NmYzO1xyXG4gICAgICBib3JkZXItcmFkaXVzOiA1MCU7XHJcbiAgICAgIGFuaW1hdGlvbjogc3BpbiAxcyBsaW5lYXIgaW5maW5pdGU7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIEBrZXlmcmFtZXMgc3BpbiB7XHJcbiAgICAgIDAlIHsgdHJhbnNmb3JtOiByb3RhdGUoMGRlZyk7IH1cclxuICAgICAgMTAwJSB7IHRyYW5zZm9ybTogcm90YXRlKDM2MGRlZyk7IH1cclxuICAgIH1cclxuICBgXSxcclxuICBhbmltYXRpb25zOiBbXHJcbiAgICB0cmlnZ2VyKCdleHBhbmRDb2xsYXBzZScsIFtcclxuICAgICAgc3RhdGUoJ2NvbGxhcHNlZCcsIHN0eWxlKHtcclxuICAgICAgICBoZWlnaHQ6ICcwJyxcclxuICAgICAgICBvdmVyZmxvdzogJ2hpZGRlbicsXHJcbiAgICAgICAgb3BhY2l0eTogJzAnXHJcbiAgICAgIH0pKSxcclxuICAgICAgc3RhdGUoJ2V4cGFuZGVkJywgc3R5bGUoe1xyXG4gICAgICAgIGhlaWdodDogJyonLFxyXG4gICAgICAgIG92ZXJmbG93OiAndmlzaWJsZScsXHJcbiAgICAgICAgb3BhY2l0eTogJzEnXHJcbiAgICAgIH0pKSxcclxuICAgICAgdHJhbnNpdGlvbignY29sbGFwc2VkIDw9PiBleHBhbmRlZCcsIFtcclxuICAgICAgICBhbmltYXRlKCcyMDBtcyBlYXNlLWluLW91dCcpXHJcbiAgICAgIF0pXHJcbiAgICBdKVxyXG4gIF0sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBUcmVlTm9kZUNvbXBvbmVudCB7XHJcbiAgQElucHV0KHsgcmVxdWlyZWQ6IHRydWUgfSkgbm9kZSE6IFRyZWVOb2RlO1xyXG4gIEBJbnB1dCh7IHJlcXVpcmVkOiB0cnVlIH0pIHRyZWVNb2RlbCE6IFRyZWVNb2RlbDtcclxuICBASW5wdXQoeyByZXF1aXJlZDogdHJ1ZSB9KSBvcHRpb25zITogVHJlZU9wdGlvbnM7XHJcbiAgQElucHV0KCkgbm9kZVRlbXBsYXRlPzogVGVtcGxhdGVSZWY8YW55PjtcclxuICBcclxuICByZWFkb25seSBwYWRkaW5nTGVmdCA9IGNvbXB1dGVkKCgpID0+IHtcclxuICAgIHJldHVybiB0aGlzLm9wdGlvbnMubGV2ZWxQYWRkaW5nIHx8IDQwO1xyXG4gIH0pO1xyXG4gIFxyXG4gIG9uTm9kZUNsaWNrKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XHJcbiAgICBjb25zdCB1c2VNZXRhS2V5ID0gdGhpcy5vcHRpb25zLnVzZU1ldGFLZXkgIT09IGZhbHNlO1xyXG4gICAgY29uc3QgbXVsdGlTZWxlY3QgPSB0aGlzLm9wdGlvbnMubXVsdGlTZWxlY3QgfHwgZmFsc2U7XHJcbiAgICBcclxuICAgIGNvbnN0IGlzTWV0YUtleVByZXNzZWQgPSBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXk7XHJcbiAgICBjb25zdCBzaG91bGRNdWx0aVNlbGVjdCA9IG11bHRpU2VsZWN0ICYmICghdXNlTWV0YUtleSB8fCBpc01ldGFLZXlQcmVzc2VkKTtcclxuICAgIFxyXG4gICAgdGhpcy50cmVlTW9kZWwuYWN0aXZhdGVOb2RlKHRoaXMubm9kZSwgc2hvdWxkTXVsdGlTZWxlY3QpO1xyXG4gICAgdGhpcy50cmVlTW9kZWwuZm9jdXNOb2RlKHRoaXMubm9kZSk7XHJcbiAgfVxyXG4gIFxyXG4gIG9uTm9kZURvdWJsZUNsaWNrKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5ub2RlLmhhc0NoaWxkcmVuKSB7XHJcbiAgICAgIHRoaXMubm9kZS50b2dnbGUoKTtcclxuICAgICAgdGhpcy50cmVlTW9kZWwuZXhwYW5kZWROb2RlSWRzLnVwZGF0ZShpZHMgPT4ge1xyXG4gICAgICAgIGNvbnN0IG5ld0lkcyA9IG5ldyBTZXQoaWRzKTtcclxuICAgICAgICBpZiAodGhpcy5ub2RlLmlzRXhwYW5kZWQoKSkge1xyXG4gICAgICAgICAgbmV3SWRzLmFkZCh0aGlzLm5vZGUuaWQpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBuZXdJZHMuZGVsZXRlKHRoaXMubm9kZS5pZCk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiBuZXdJZHM7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxuICBcclxuICBvbk5vZGVDb250ZXh0TWVudShldmVudDogTW91c2VFdmVudCk6IHZvaWQge1xyXG4gICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgIC8vIEVtaXQgY29udGV4dCBtZW51IGV2ZW50XHJcbiAgfVxyXG4gIFxyXG4gIG9uVG9nZ2xlRXhwYW5kZWQoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5ub2RlLmhhc0NoaWxkcmVuKSB7XHJcbiAgICAgIHRoaXMubm9kZS50b2dnbGUoKTtcclxuICAgICAgXHJcbiAgICAgIGlmICh0aGlzLm5vZGUuaXNFeHBhbmRlZCgpKSB7XHJcbiAgICAgICAgLy8gTG9hZCBjaGlsZHJlbiBpZiBuZWVkZWRcclxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLmdldENoaWxkcmVuICYmIHRoaXMubm9kZS5jaGlsZHJlbi5sZW5ndGggPT09IDApIHtcclxuICAgICAgICAgIHRoaXMudHJlZU1vZGVsLmxvYWRDaGlsZHJlbih0aGlzLm5vZGUpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnRyZWVNb2RlbC5leHBhbmROb2RlKHRoaXMubm9kZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy50cmVlTW9kZWwuY29sbGFwc2VOb2RlKHRoaXMubm9kZSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbiAgXHJcbiAgb25DaGVja2JveENoYW5nZShjaGVja2VkOiBib29sZWFuKTogdm9pZCB7XHJcbiAgICB0aGlzLnRyZWVNb2RlbC5zZWxlY3ROb2RlKHRoaXMubm9kZSwgdGhpcy5vcHRpb25zLm11bHRpU2VsZWN0IHx8IGZhbHNlKTtcclxuICB9XHJcbn0iXX0=
@@ -0,0 +1,90 @@
1
+ // lib/components/tree-node-checkbox/tree-node-checkbox.component.ts
2
+ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, computed, } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import * as i0 from "@angular/core";
5
+ export class TreeNodeCheckboxComponent {
6
+ node;
7
+ treeModel;
8
+ useTriState = false;
9
+ change = new EventEmitter();
10
+ isChecked = computed(() => {
11
+ return this.treeModel.selectedNodeIds().has(this.node.id);
12
+ });
13
+ isIndeterminate = computed(() => {
14
+ if (!this.useTriState || !this.node.hasChildren) {
15
+ return false;
16
+ }
17
+ const selectedIds = this.treeModel.selectedNodeIds();
18
+ const descendants = this.node.getDescendants();
19
+ if (descendants.length === 0)
20
+ return false;
21
+ const selectedCount = descendants.filter(d => selectedIds.has(d.id)).length;
22
+ return selectedCount > 0 && selectedCount < descendants.length;
23
+ });
24
+ onCheckboxClick(event) {
25
+ event.stopPropagation();
26
+ }
27
+ onCheckboxChange(event) {
28
+ event.stopPropagation();
29
+ const checked = event.target.checked;
30
+ if (this.useTriState) {
31
+ // Update node and all descendants
32
+ this.updateNodeAndDescendants(this.node, checked);
33
+ }
34
+ else {
35
+ this.change.emit(checked);
36
+ }
37
+ }
38
+ updateNodeAndDescendants(node, checked) {
39
+ this.treeModel.selectedNodeIds.update(ids => {
40
+ const newIds = new Set(ids);
41
+ if (checked) {
42
+ newIds.add(node.id);
43
+ node.getDescendants().forEach(d => newIds.add(d.id));
44
+ }
45
+ else {
46
+ newIds.delete(node.id);
47
+ node.getDescendants().forEach(d => newIds.delete(d.id));
48
+ }
49
+ return newIds;
50
+ });
51
+ this.change.emit(checked);
52
+ }
53
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeNodeCheckboxComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
54
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: TreeNodeCheckboxComponent, isStandalone: true, selector: "tree-node-checkbox", inputs: { node: "node", treeModel: "treeModel", useTriState: "useTriState" }, outputs: { change: "change" }, ngImport: i0, template: `
55
+ <div class="tree-node-checkbox"
56
+ (click)="onCheckboxClick($event)">
57
+ <input
58
+ type="checkbox"
59
+ [checked]="isChecked()"
60
+ [indeterminate]="isIndeterminate()"
61
+ (change)="onCheckboxChange($event)"
62
+ (click)="$event.stopPropagation()">
63
+ </div>
64
+ `, isInline: true, styles: [".tree-node-checkbox{display:flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0}input[type=checkbox]{cursor:pointer;width:16px;height:16px;margin:0}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
65
+ }
66
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeNodeCheckboxComponent, decorators: [{
67
+ type: Component,
68
+ args: [{ selector: 'tree-node-checkbox', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
69
+ <div class="tree-node-checkbox"
70
+ (click)="onCheckboxClick($event)">
71
+ <input
72
+ type="checkbox"
73
+ [checked]="isChecked()"
74
+ [indeterminate]="isIndeterminate()"
75
+ (change)="onCheckboxChange($event)"
76
+ (click)="$event.stopPropagation()">
77
+ </div>
78
+ `, styles: [".tree-node-checkbox{display:flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0}input[type=checkbox]{cursor:pointer;width:16px;height:16px;margin:0}\n"] }]
79
+ }], propDecorators: { node: [{
80
+ type: Input,
81
+ args: [{ required: true }]
82
+ }], treeModel: [{
83
+ type: Input,
84
+ args: [{ required: true }]
85
+ }], useTriState: [{
86
+ type: Input
87
+ }], change: [{
88
+ type: Output
89
+ }] } });
90
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS1ub2RlLWNoZWNrYm94LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NvbmNlcHRvLXVzZXItY29udHJvbHMvc3JjL2xpYi9jb25jZXB0by10cmVlL2NvbXBvbmVudHMvdHJlZS1ub2RlLWNoZWNrYm94L3RyZWUtbm9kZS1jaGVja2JveC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0VBQW9FO0FBQ3BFLE9BQU8sRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBQ1osdUJBQXVCLEVBQ3ZCLFFBQVEsR0FDVCxNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7O0FBc0MvQyxNQUFNLE9BQU8seUJBQXlCO0lBQ1QsSUFBSSxDQUFZO0lBQ2hCLFNBQVMsQ0FBYTtJQUN4QyxXQUFXLEdBQUcsS0FBSyxDQUFDO0lBQ25CLE1BQU0sR0FBRyxJQUFJLFlBQVksRUFBVyxDQUFDO0lBRXRDLFNBQVMsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQ2pDLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxlQUFlLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUM1RCxDQUFDLENBQUMsQ0FBQztJQUVNLGVBQWUsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQ3ZDLElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNoRCxPQUFPLEtBQUssQ0FBQztRQUNmLENBQUM7UUFFRCxNQUFNLFdBQVcsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ3JELE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUM7UUFFL0MsSUFBSSxXQUFXLENBQUMsTUFBTSxLQUFLLENBQUM7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUUzQyxNQUFNLGFBQWEsR0FBRyxXQUFXLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQzNDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUN0QixDQUFDLE1BQU0sQ0FBQztRQUVULE9BQU8sYUFBYSxHQUFHLENBQUMsSUFBSSxhQUFhLEdBQUcsV0FBVyxDQUFDLE1BQU0sQ0FBQztJQUNqRSxDQUFDLENBQUMsQ0FBQztJQUVILGVBQWUsQ0FBQyxLQUFpQjtRQUMvQixLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7SUFDMUIsQ0FBQztJQUVELGdCQUFnQixDQUFDLEtBQVk7UUFDM0IsS0FBSyxDQUFDLGVBQWUsRUFBRSxDQUFDO1FBQ3hCLE1BQU0sT0FBTyxHQUFJLEtBQUssQ0FBQyxNQUEyQixDQUFDLE9BQU8sQ0FBQztRQUUzRCxJQUFJLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUNyQixrQ0FBa0M7WUFDbEMsSUFBSSxDQUFDLHdCQUF3QixDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDcEQsQ0FBQzthQUFNLENBQUM7WUFDTixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM1QixDQUFDO0lBQ0gsQ0FBQztJQUVPLHdCQUF3QixDQUFDLElBQWMsRUFBRSxPQUFnQjtRQUMvRCxJQUFJLENBQUMsU0FBUyxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFDMUMsTUFBTSxNQUFNLEdBQUcsSUFBSSxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7WUFFNUIsSUFBSSxPQUFPLEVBQUUsQ0FBQztnQkFDWixNQUFNLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDcEIsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDdkQsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2dCQUN2QixJQUFJLENBQUMsY0FBYyxFQUFFLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQztZQUMxRCxDQUFDO1lBRUQsT0FBTyxNQUFNLENBQUM7UUFDaEIsQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM1QixDQUFDO3dHQTNEVSx5QkFBeUI7NEZBQXpCLHlCQUF5QiwyTEE3QjFCOzs7Ozs7Ozs7O0dBVVQsK1BBWlMsWUFBWTs7NEZBK0JYLHlCQUF5QjtrQkFsQ3JDLFNBQVM7K0JBQ0Usb0JBQW9CLGNBQ2xCLElBQUksV0FDUCxDQUFDLFlBQVksQ0FBQyxtQkFDTix1QkFBdUIsQ0FBQyxNQUFNLFlBQ3JDOzs7Ozs7Ozs7O0dBVVQ7OEJBb0IwQixJQUFJO3NCQUE5QixLQUFLO3VCQUFDLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRTtnQkFDRSxTQUFTO3NCQUFuQyxLQUFLO3VCQUFDLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRTtnQkFDaEIsV0FBVztzQkFBbkIsS0FBSztnQkFDSSxNQUFNO3NCQUFmLE1BQU0iLCJzb3VyY2VzQ29udGVudCI6WyIvLyBsaWIvY29tcG9uZW50cy90cmVlLW5vZGUtY2hlY2tib3gvdHJlZS1ub2RlLWNoZWNrYm94LmNvbXBvbmVudC50c1xyXG5pbXBvcnQge1xyXG4gIENvbXBvbmVudCxcclxuICBJbnB1dCxcclxuICBPdXRwdXQsXHJcbiAgRXZlbnRFbWl0dGVyLFxyXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxyXG4gIGNvbXB1dGVkLFxyXG59IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBDb21tb25Nb2R1bGUgfSBmcm9tICdAYW5ndWxhci9jb21tb24nO1xyXG5pbXBvcnQgeyBUcmVlTm9kZSB9IGZyb20gJy4uLy4uL2NvcmUvbW9kZWxzL3RyZWUtbm9kZS5tb2RlbCc7XHJcbmltcG9ydCB7IFRyZWVNb2RlbCB9IGZyb20gJy4uLy4uL2NvcmUvbW9kZWxzL3RyZWUubW9kZWwnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICd0cmVlLW5vZGUtY2hlY2tib3gnLFxyXG4gIHN0YW5kYWxvbmU6IHRydWUsXHJcbiAgaW1wb3J0czogW0NvbW1vbk1vZHVsZV0sXHJcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXHJcbiAgdGVtcGxhdGU6IGBcclxuICAgIDxkaXYgY2xhc3M9XCJ0cmVlLW5vZGUtY2hlY2tib3hcIlxyXG4gICAgICAgICAoY2xpY2spPVwib25DaGVja2JveENsaWNrKCRldmVudClcIj5cclxuICAgICAgPGlucHV0IFxyXG4gICAgICAgIHR5cGU9XCJjaGVja2JveFwiXHJcbiAgICAgICAgW2NoZWNrZWRdPVwiaXNDaGVja2VkKClcIlxyXG4gICAgICAgIFtpbmRldGVybWluYXRlXT1cImlzSW5kZXRlcm1pbmF0ZSgpXCJcclxuICAgICAgICAoY2hhbmdlKT1cIm9uQ2hlY2tib3hDaGFuZ2UoJGV2ZW50KVwiXHJcbiAgICAgICAgKGNsaWNrKT1cIiRldmVudC5zdG9wUHJvcGFnYXRpb24oKVwiPlxyXG4gICAgPC9kaXY+XHJcbiAgYCxcclxuICBzdHlsZXM6IFtgXHJcbiAgICAudHJlZS1ub2RlLWNoZWNrYm94IHtcclxuICAgICAgZGlzcGxheTogZmxleDtcclxuICAgICAgYWxpZ24taXRlbXM6IGNlbnRlcjtcclxuICAgICAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7XHJcbiAgICAgIHdpZHRoOiAyMHB4O1xyXG4gICAgICBoZWlnaHQ6IDIwcHg7XHJcbiAgICAgIGZsZXgtc2hyaW5rOiAwO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBpbnB1dFt0eXBlPVwiY2hlY2tib3hcIl0ge1xyXG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICAgIHdpZHRoOiAxNnB4O1xyXG4gICAgICBoZWlnaHQ6IDE2cHg7XHJcbiAgICAgIG1hcmdpbjogMDtcclxuICAgIH1cclxuICBgXSxcclxufSlcclxuZXhwb3J0IGNsYXNzIFRyZWVOb2RlQ2hlY2tib3hDb21wb25lbnQge1xyXG4gIEBJbnB1dCh7IHJlcXVpcmVkOiB0cnVlIH0pIG5vZGUhOiBUcmVlTm9kZTtcclxuICBASW5wdXQoeyByZXF1aXJlZDogdHJ1ZSB9KSB0cmVlTW9kZWwhOiBUcmVlTW9kZWw7XHJcbiAgQElucHV0KCkgdXNlVHJpU3RhdGUgPSBmYWxzZTtcclxuICBAT3V0cHV0KCkgY2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxib29sZWFuPigpO1xyXG4gIFxyXG4gIHJlYWRvbmx5IGlzQ2hlY2tlZCA9IGNvbXB1dGVkKCgpID0+IHtcclxuICAgIHJldHVybiB0aGlzLnRyZWVNb2RlbC5zZWxlY3RlZE5vZGVJZHMoKS5oYXModGhpcy5ub2RlLmlkKTtcclxuICB9KTtcclxuICBcclxuICByZWFkb25seSBpc0luZGV0ZXJtaW5hdGUgPSBjb21wdXRlZCgoKSA9PiB7XHJcbiAgICBpZiAoIXRoaXMudXNlVHJpU3RhdGUgfHwgIXRoaXMubm9kZS5oYXNDaGlsZHJlbikge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIGNvbnN0IHNlbGVjdGVkSWRzID0gdGhpcy50cmVlTW9kZWwuc2VsZWN0ZWROb2RlSWRzKCk7XHJcbiAgICBjb25zdCBkZXNjZW5kYW50cyA9IHRoaXMubm9kZS5nZXREZXNjZW5kYW50cygpO1xyXG4gICAgXHJcbiAgICBpZiAoZGVzY2VuZGFudHMubGVuZ3RoID09PSAwKSByZXR1cm4gZmFsc2U7XHJcbiAgICBcclxuICAgIGNvbnN0IHNlbGVjdGVkQ291bnQgPSBkZXNjZW5kYW50cy5maWx0ZXIoZCA9PiBcclxuICAgICAgc2VsZWN0ZWRJZHMuaGFzKGQuaWQpXHJcbiAgICApLmxlbmd0aDtcclxuICAgIFxyXG4gICAgcmV0dXJuIHNlbGVjdGVkQ291bnQgPiAwICYmIHNlbGVjdGVkQ291bnQgPCBkZXNjZW5kYW50cy5sZW5ndGg7XHJcbiAgfSk7XHJcbiAgXHJcbiAgb25DaGVja2JveENsaWNrKGV2ZW50OiBNb3VzZUV2ZW50KTogdm9pZCB7XHJcbiAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcclxuICB9XHJcbiAgXHJcbiAgb25DaGVja2JveENoYW5nZShldmVudDogRXZlbnQpOiB2b2lkIHtcclxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgY29uc3QgY2hlY2tlZCA9IChldmVudC50YXJnZXQgYXMgSFRNTElucHV0RWxlbWVudCkuY2hlY2tlZDtcclxuICAgIFxyXG4gICAgaWYgKHRoaXMudXNlVHJpU3RhdGUpIHtcclxuICAgICAgLy8gVXBkYXRlIG5vZGUgYW5kIGFsbCBkZXNjZW5kYW50c1xyXG4gICAgICB0aGlzLnVwZGF0ZU5vZGVBbmREZXNjZW5kYW50cyh0aGlzLm5vZGUsIGNoZWNrZWQpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5jaGFuZ2UuZW1pdChjaGVja2VkKTtcclxuICAgIH1cclxuICB9XHJcbiAgXHJcbiAgcHJpdmF0ZSB1cGRhdGVOb2RlQW5kRGVzY2VuZGFudHMobm9kZTogVHJlZU5vZGUsIGNoZWNrZWQ6IGJvb2xlYW4pOiB2b2lkIHtcclxuICAgIHRoaXMudHJlZU1vZGVsLnNlbGVjdGVkTm9kZUlkcy51cGRhdGUoaWRzID0+IHtcclxuICAgICAgY29uc3QgbmV3SWRzID0gbmV3IFNldChpZHMpO1xyXG4gICAgICBcclxuICAgICAgaWYgKGNoZWNrZWQpIHtcclxuICAgICAgICBuZXdJZHMuYWRkKG5vZGUuaWQpO1xyXG4gICAgICAgIG5vZGUuZ2V0RGVzY2VuZGFudHMoKS5mb3JFYWNoKGQgPT4gbmV3SWRzLmFkZChkLmlkKSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbmV3SWRzLmRlbGV0ZShub2RlLmlkKTtcclxuICAgICAgICBub2RlLmdldERlc2NlbmRhbnRzKCkuZm9yRWFjaChkID0+IG5ld0lkcy5kZWxldGUoZC5pZCkpO1xyXG4gICAgICB9XHJcbiAgICAgIFxyXG4gICAgICByZXR1cm4gbmV3SWRzO1xyXG4gICAgfSk7XHJcbiAgICBcclxuICAgIHRoaXMuY2hhbmdlLmVtaXQoY2hlY2tlZCk7XHJcbiAgfVxyXG59Il19
@@ -0,0 +1,65 @@
1
+ // lib/components/tree-node-content/tree-node-content.component.ts
2
+ import { Component, Input, ChangeDetectionStrategy, } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@angular/common";
6
+ export class TreeNodeContentComponent {
7
+ node;
8
+ treeModel;
9
+ template;
10
+ displayField = 'name';
11
+ NgOnInit() {
12
+ console.log("Tree node:", this.node);
13
+ }
14
+ get templateContext() {
15
+ console.log("Tree node:", this.node);
16
+ return {
17
+ $implicit: this.node,
18
+ node: this.node,
19
+ treeModel: this.treeModel,
20
+ };
21
+ }
22
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeNodeContentComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
23
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: TreeNodeContentComponent, isStandalone: true, selector: "tree-node-content", inputs: { node: "node", treeModel: "treeModel", template: "template", displayField: "displayField" }, ngImport: i0, template: `
24
+ @if (template) {
25
+ <ng-container
26
+ *ngTemplateOutlet="template; context: templateContext">
27
+ </ng-container>
28
+ } @else {
29
+ <span class="tree-node-content-default">
30
+ @if (node.icon) {
31
+ <img [src]="node.icon" alt="" class="tree-node-icon" />
32
+ }
33
+ <span class="tree-node-text">{{ node.data[displayField] }}</span>
34
+ </span>
35
+ }
36
+ `, isInline: true, styles: [".tree-node-content-default{flex:1;padding:0 4px;display:flex;align-items:center;gap:6px;overflow:hidden;-webkit-user-select:none;user-select:none}.tree-node-icon{width:16px;height:16px;flex-shrink:0;object-fit:contain}.tree-node-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
37
+ }
38
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeNodeContentComponent, decorators: [{
39
+ type: Component,
40
+ args: [{ selector: 'tree-node-content', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
41
+ @if (template) {
42
+ <ng-container
43
+ *ngTemplateOutlet="template; context: templateContext">
44
+ </ng-container>
45
+ } @else {
46
+ <span class="tree-node-content-default">
47
+ @if (node.icon) {
48
+ <img [src]="node.icon" alt="" class="tree-node-icon" />
49
+ }
50
+ <span class="tree-node-text">{{ node.data[displayField] }}</span>
51
+ </span>
52
+ }
53
+ `, styles: [".tree-node-content-default{flex:1;padding:0 4px;display:flex;align-items:center;gap:6px;overflow:hidden;-webkit-user-select:none;user-select:none}.tree-node-icon{width:16px;height:16px;flex-shrink:0;object-fit:contain}.tree-node-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n"] }]
54
+ }], propDecorators: { node: [{
55
+ type: Input,
56
+ args: [{ required: true }]
57
+ }], treeModel: [{
58
+ type: Input,
59
+ args: [{ required: true }]
60
+ }], template: [{
61
+ type: Input
62
+ }], displayField: [{
63
+ type: Input
64
+ }] } });
65
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS1ub2RlLWNvbnRlbnQuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvY29uY2VwdG8tdXNlci1jb250cm9scy9zcmMvbGliL2NvbmNlcHRvLXRyZWUvY29tcG9uZW50cy90cmVlLW5vZGUtY29udGVudC90cmVlLW5vZGUtY29udGVudC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsa0VBQWtFO0FBQ2xFLE9BQU8sRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUVMLHVCQUF1QixHQUN4QixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7OztBQWdEL0MsTUFBTSxPQUFPLHdCQUF3QjtJQUNSLElBQUksQ0FBWTtJQUNoQixTQUFTLENBQWE7SUFDeEMsUUFBUSxDQUFvQjtJQUM1QixZQUFZLEdBQUcsTUFBTSxDQUFDO0lBRS9CLFFBQVE7UUFDTixPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDdkMsQ0FBQztJQUVELElBQUksZUFBZTtRQUNqQixPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksRUFBRSxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDckMsT0FBTztZQUNMLFNBQVMsRUFBRSxJQUFJLENBQUMsSUFBSTtZQUNwQixJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUk7WUFDZixTQUFTLEVBQUUsSUFBSSxDQUFDLFNBQVM7U0FDMUIsQ0FBQztJQUNKLENBQUM7d0dBakJVLHdCQUF3Qjs0RkFBeEIsd0JBQXdCLG1MQXZDekI7Ozs7Ozs7Ozs7Ozs7R0FhVCwrV0FmUyxZQUFZOzs0RkF5Q1gsd0JBQXdCO2tCQTVDcEMsU0FBUzsrQkFDRSxtQkFBbUIsY0FDakIsSUFBSSxXQUNQLENBQUMsWUFBWSxDQUFDLG1CQUNOLHVCQUF1QixDQUFDLE1BQU0sWUFDckM7Ozs7Ozs7Ozs7Ozs7R0FhVDs4QkEyQjBCLElBQUk7c0JBQTlCLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQUNFLFNBQVM7c0JBQW5DLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQUNoQixRQUFRO3NCQUFoQixLQUFLO2dCQUNHLFlBQVk7c0JBQXBCLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBsaWIvY29tcG9uZW50cy90cmVlLW5vZGUtY29udGVudC90cmVlLW5vZGUtY29udGVudC5jb21wb25lbnQudHNcclxuaW1wb3J0IHtcclxuICBDb21wb25lbnQsXHJcbiAgSW5wdXQsXHJcbiAgVGVtcGxhdGVSZWYsXHJcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IFRyZWVOb2RlIH0gZnJvbSAnLi4vLi4vY29yZS9tb2RlbHMvdHJlZS1ub2RlLm1vZGVsJztcclxuaW1wb3J0IHsgVHJlZU1vZGVsIH0gZnJvbSAnLi4vLi4vY29yZS9tb2RlbHMvdHJlZS5tb2RlbCc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ3RyZWUtbm9kZS1jb250ZW50JyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtDb21tb25Nb2R1bGVdLFxyXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICBAaWYgKHRlbXBsYXRlKSB7XHJcbiAgICAgIDxuZy1jb250YWluZXJcclxuICAgICAgICAqbmdUZW1wbGF0ZU91dGxldD1cInRlbXBsYXRlOyBjb250ZXh0OiB0ZW1wbGF0ZUNvbnRleHRcIj5cclxuICAgICAgPC9uZy1jb250YWluZXI+XHJcbiAgICB9IEBlbHNlIHtcclxuICAgICAgPHNwYW4gY2xhc3M9XCJ0cmVlLW5vZGUtY29udGVudC1kZWZhdWx0XCI+XHJcbiAgICAgICAgQGlmIChub2RlLmljb24pIHtcclxuICAgICAgICAgIDxpbWcgW3NyY109XCJub2RlLmljb25cIiBhbHQ9XCJcIiBjbGFzcz1cInRyZWUtbm9kZS1pY29uXCIgLz5cclxuICAgICAgICB9XHJcbiAgICAgICAgPHNwYW4gY2xhc3M9XCJ0cmVlLW5vZGUtdGV4dFwiPnt7IG5vZGUuZGF0YVtkaXNwbGF5RmllbGRdIH19PC9zcGFuPlxyXG4gICAgICA8L3NwYW4+XHJcbiAgICB9XHJcbiAgYCxcclxuICBzdHlsZXM6IFtgXHJcbiAgICAudHJlZS1ub2RlLWNvbnRlbnQtZGVmYXVsdCB7XHJcbiAgICAgIGZsZXg6IDE7XHJcbiAgICAgIHBhZGRpbmc6IDAgNHB4O1xyXG4gICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICBhbGlnbi1pdGVtczogY2VudGVyO1xyXG4gICAgICBnYXA6IDZweDtcclxuICAgICAgb3ZlcmZsb3c6IGhpZGRlbjtcclxuICAgICAgdXNlci1zZWxlY3Q6IG5vbmU7XHJcbiAgICB9XHJcblxyXG4gICAgLnRyZWUtbm9kZS1pY29uIHtcclxuICAgICAgd2lkdGg6IDE2cHg7XHJcbiAgICAgIGhlaWdodDogMTZweDtcclxuICAgICAgZmxleC1zaHJpbms6IDA7XHJcbiAgICAgIG9iamVjdC1maXQ6IGNvbnRhaW47XHJcbiAgICB9XHJcblxyXG4gICAgLnRyZWUtbm9kZS10ZXh0IHtcclxuICAgICAgb3ZlcmZsb3c6IGhpZGRlbjtcclxuICAgICAgdGV4dC1vdmVyZmxvdzogZWxsaXBzaXM7XHJcbiAgICAgIHdoaXRlLXNwYWNlOiBub3dyYXA7XHJcbiAgICB9XHJcbiAgYF0sXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBUcmVlTm9kZUNvbnRlbnRDb21wb25lbnQge1xyXG4gIEBJbnB1dCh7IHJlcXVpcmVkOiB0cnVlIH0pIG5vZGUhOiBUcmVlTm9kZTtcclxuICBASW5wdXQoeyByZXF1aXJlZDogdHJ1ZSB9KSB0cmVlTW9kZWwhOiBUcmVlTW9kZWw7XHJcbiAgQElucHV0KCkgdGVtcGxhdGU/OiBUZW1wbGF0ZVJlZjxhbnk+O1xyXG4gIEBJbnB1dCgpIGRpc3BsYXlGaWVsZCA9ICduYW1lJztcclxuICBcclxuICBOZ09uSW5pdCgpe1xyXG4gICAgY29uc29sZS5sb2coXCJUcmVlIG5vZGU6XCIsIHRoaXMubm9kZSk7XHJcbiAgfVxyXG5cclxuICBnZXQgdGVtcGxhdGVDb250ZXh0KCkge1xyXG4gICAgY29uc29sZS5sb2coXCJUcmVlIG5vZGU6XCIsIHRoaXMubm9kZSk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAkaW1wbGljaXQ6IHRoaXMubm9kZSxcclxuICAgICAgbm9kZTogdGhpcy5ub2RlLFxyXG4gICAgICB0cmVlTW9kZWw6IHRoaXMudHJlZU1vZGVsLFxyXG4gICAgfTtcclxuICB9XHJcbn0iXX0=
@@ -0,0 +1,74 @@
1
+ // lib/components/tree-node-expander/tree-node-expander.component.ts
2
+ import { Component, Input, Output, EventEmitter, ChangeDetectionStrategy, } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import * as i0 from "@angular/core";
5
+ export class TreeNodeExpanderComponent {
6
+ node;
7
+ treeModel;
8
+ toggle = new EventEmitter();
9
+ onExpanderClick(event) {
10
+ event.stopPropagation();
11
+ this.toggle.emit();
12
+ }
13
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeNodeExpanderComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
14
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: TreeNodeExpanderComponent, isStandalone: true, selector: "tree-node-expander", inputs: { node: "node", treeModel: "treeModel" }, outputs: { toggle: "toggle" }, ngImport: i0, template: `
15
+ <div class="tree-node-expander"
16
+ [class.tree-node-expander-loading]="node.isLoading()"
17
+ (click)="onExpanderClick($event)">
18
+ @if (node.isLoading()) {
19
+ <span class="expander-spinner"></span>
20
+ } @else if (node.hasChildren) {
21
+ <svg
22
+ class="expander-icon"
23
+ [class.expander-icon-expanded]="node.isExpanded()"
24
+ width="16"
25
+ height="16"
26
+ viewBox="0 0 16 16">
27
+ <path d="M6 4l4 4-4 4"
28
+ fill="none"
29
+ stroke="currentColor"
30
+ stroke-width="2"
31
+ stroke-linecap="round"/>
32
+ </svg>
33
+ } @else {
34
+ <span class="expander-placeholder"></span>
35
+ }
36
+ </div>
37
+ `, isInline: true, styles: [".tree-node-expander{display:flex;align-items:center;justify-content:center;width:20px;height:20px;cursor:pointer;border-radius:3px;transition:background-color .15s;flex-shrink:0}.tree-node-expander:hover{background-color:#0000000d}.expander-icon{transition:transform .2s ease;transform:rotate(0)}.expander-icon-expanded{transform:rotate(90deg)}.expander-placeholder{width:16px;height:16px}.expander-spinner{display:inline-block;width:14px;height:14px;border:2px solid #f3f3f3;border-top:2px solid #2196f3;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
38
+ }
39
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeNodeExpanderComponent, decorators: [{
40
+ type: Component,
41
+ args: [{ selector: 'tree-node-expander', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: `
42
+ <div class="tree-node-expander"
43
+ [class.tree-node-expander-loading]="node.isLoading()"
44
+ (click)="onExpanderClick($event)">
45
+ @if (node.isLoading()) {
46
+ <span class="expander-spinner"></span>
47
+ } @else if (node.hasChildren) {
48
+ <svg
49
+ class="expander-icon"
50
+ [class.expander-icon-expanded]="node.isExpanded()"
51
+ width="16"
52
+ height="16"
53
+ viewBox="0 0 16 16">
54
+ <path d="M6 4l4 4-4 4"
55
+ fill="none"
56
+ stroke="currentColor"
57
+ stroke-width="2"
58
+ stroke-linecap="round"/>
59
+ </svg>
60
+ } @else {
61
+ <span class="expander-placeholder"></span>
62
+ }
63
+ </div>
64
+ `, styles: [".tree-node-expander{display:flex;align-items:center;justify-content:center;width:20px;height:20px;cursor:pointer;border-radius:3px;transition:background-color .15s;flex-shrink:0}.tree-node-expander:hover{background-color:#0000000d}.expander-icon{transition:transform .2s ease;transform:rotate(0)}.expander-icon-expanded{transform:rotate(90deg)}.expander-placeholder{width:16px;height:16px}.expander-spinner{display:inline-block;width:14px;height:14px;border:2px solid #f3f3f3;border-top:2px solid #2196f3;border-radius:50%;animation:spin 1s linear infinite}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
65
+ }], propDecorators: { node: [{
66
+ type: Input,
67
+ args: [{ required: true }]
68
+ }], treeModel: [{
69
+ type: Input,
70
+ args: [{ required: true }]
71
+ }], toggle: [{
72
+ type: Output
73
+ }] } });
74
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS1ub2RlLWV4cGFuZGVyLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NvbmNlcHRvLXVzZXItY29udHJvbHMvc3JjL2xpYi9jb25jZXB0by10cmVlL2NvbXBvbmVudHMvdHJlZS1ub2RlLWV4cGFuZGVyL3RyZWUtbm9kZS1leHBhbmRlci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsb0VBQW9FO0FBQ3BFLE9BQU8sRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBQ1osdUJBQXVCLEdBQ3hCLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQzs7QUFnRi9DLE1BQU0sT0FBTyx5QkFBeUI7SUFDVCxJQUFJLENBQVk7SUFDaEIsU0FBUyxDQUFhO0lBQ3ZDLE1BQU0sR0FBRyxJQUFJLFlBQVksRUFBUSxDQUFDO0lBRTVDLGVBQWUsQ0FBQyxLQUFpQjtRQUMvQixLQUFLLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDeEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNyQixDQUFDO3dHQVJVLHlCQUF5Qjs0RkFBekIseUJBQXlCLCtKQXZFMUI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBdUJULDRyQkF6QlMsWUFBWTs7NEZBeUVYLHlCQUF5QjtrQkE1RXJDLFNBQVM7K0JBQ0Usb0JBQW9CLGNBQ2xCLElBQUksV0FDUCxDQUFDLFlBQVksQ0FBQyxtQkFDTix1QkFBdUIsQ0FBQyxNQUFNLFlBQ3JDOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCVDs4QkFpRDBCLElBQUk7c0JBQTlCLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQUNFLFNBQVM7c0JBQW5DLEtBQUs7dUJBQUMsRUFBRSxRQUFRLEVBQUUsSUFBSSxFQUFFO2dCQUNmLE1BQU07c0JBQWYsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbIi8vIGxpYi9jb21wb25lbnRzL3RyZWUtbm9kZS1leHBhbmRlci90cmVlLW5vZGUtZXhwYW5kZXIuY29tcG9uZW50LnRzXHJcbmltcG9ydCB7XHJcbiAgQ29tcG9uZW50LFxyXG4gIElucHV0LFxyXG4gIE91dHB1dCxcclxuICBFdmVudEVtaXR0ZXIsXHJcbiAgQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3ksXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IFRyZWVOb2RlIH0gZnJvbSAnLi4vLi4vY29yZS9tb2RlbHMvdHJlZS1ub2RlLm1vZGVsJztcclxuaW1wb3J0IHsgVHJlZU1vZGVsIH0gZnJvbSAnLi4vLi4vY29yZS9tb2RlbHMvdHJlZS5tb2RlbCc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ3RyZWUtbm9kZS1leHBhbmRlcicsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlXSxcclxuICBjaGFuZ2VEZXRlY3Rpb246IENoYW5nZURldGVjdGlvblN0cmF0ZWd5Lk9uUHVzaCxcclxuICB0ZW1wbGF0ZTogYFxyXG4gICAgPGRpdiBjbGFzcz1cInRyZWUtbm9kZS1leHBhbmRlclwiXHJcbiAgICAgICAgIFtjbGFzcy50cmVlLW5vZGUtZXhwYW5kZXItbG9hZGluZ109XCJub2RlLmlzTG9hZGluZygpXCJcclxuICAgICAgICAgKGNsaWNrKT1cIm9uRXhwYW5kZXJDbGljaygkZXZlbnQpXCI+XHJcbiAgICAgIEBpZiAobm9kZS5pc0xvYWRpbmcoKSkge1xyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwiZXhwYW5kZXItc3Bpbm5lclwiPjwvc3Bhbj5cclxuICAgICAgfSBAZWxzZSBpZiAobm9kZS5oYXNDaGlsZHJlbikge1xyXG4gICAgICAgIDxzdmcgXHJcbiAgICAgICAgICBjbGFzcz1cImV4cGFuZGVyLWljb25cIlxyXG4gICAgICAgICAgW2NsYXNzLmV4cGFuZGVyLWljb24tZXhwYW5kZWRdPVwibm9kZS5pc0V4cGFuZGVkKClcIlxyXG4gICAgICAgICAgd2lkdGg9XCIxNlwiIFxyXG4gICAgICAgICAgaGVpZ2h0PVwiMTZcIiBcclxuICAgICAgICAgIHZpZXdCb3g9XCIwIDAgMTYgMTZcIj5cclxuICAgICAgICAgIDxwYXRoIGQ9XCJNNiA0bDQgNC00IDRcIiBcclxuICAgICAgICAgICAgICAgIGZpbGw9XCJub25lXCIgXHJcbiAgICAgICAgICAgICAgICBzdHJva2U9XCJjdXJyZW50Q29sb3JcIiBcclxuICAgICAgICAgICAgICAgIHN0cm9rZS13aWR0aD1cIjJcIiBcclxuICAgICAgICAgICAgICAgIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIi8+XHJcbiAgICAgICAgPC9zdmc+XHJcbiAgICAgIH0gQGVsc2Uge1xyXG4gICAgICAgIDxzcGFuIGNsYXNzPVwiZXhwYW5kZXItcGxhY2Vob2xkZXJcIj48L3NwYW4+XHJcbiAgICAgIH1cclxuICAgIDwvZGl2PlxyXG4gIGAsXHJcbiAgc3R5bGVzOiBbYFxyXG4gICAgLnRyZWUtbm9kZS1leHBhbmRlciB7XHJcbiAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xyXG4gICAgICB3aWR0aDogMjBweDtcclxuICAgICAgaGVpZ2h0OiAyMHB4O1xyXG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICAgIGJvcmRlci1yYWRpdXM6IDNweDtcclxuICAgICAgdHJhbnNpdGlvbjogYmFja2dyb3VuZC1jb2xvciAwLjE1cztcclxuICAgICAgZmxleC1zaHJpbms6IDA7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIC50cmVlLW5vZGUtZXhwYW5kZXI6aG92ZXIge1xyXG4gICAgICBiYWNrZ3JvdW5kLWNvbG9yOiByZ2JhKDAsIDAsIDAsIDAuMDUpO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICAuZXhwYW5kZXItaWNvbiB7XHJcbiAgICAgIHRyYW5zaXRpb246IHRyYW5zZm9ybSAwLjJzIGVhc2U7XHJcbiAgICAgIHRyYW5zZm9ybTogcm90YXRlKDBkZWcpO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICAuZXhwYW5kZXItaWNvbi1leHBhbmRlZCB7XHJcbiAgICAgIHRyYW5zZm9ybTogcm90YXRlKDkwZGVnKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgLmV4cGFuZGVyLXBsYWNlaG9sZGVyIHtcclxuICAgICAgd2lkdGg6IDE2cHg7XHJcbiAgICAgIGhlaWdodDogMTZweDtcclxuICAgIH1cclxuICAgIFxyXG4gICAgLmV4cGFuZGVyLXNwaW5uZXIge1xyXG4gICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2s7XHJcbiAgICAgIHdpZHRoOiAxNHB4O1xyXG4gICAgICBoZWlnaHQ6IDE0cHg7XHJcbiAgICAgIGJvcmRlcjogMnB4IHNvbGlkICNmM2YzZjM7XHJcbiAgICAgIGJvcmRlci10b3A6IDJweCBzb2xpZCAjMjE5NmYzO1xyXG4gICAgICBib3JkZXItcmFkaXVzOiA1MCU7XHJcbiAgICAgIGFuaW1hdGlvbjogc3BpbiAxcyBsaW5lYXIgaW5maW5pdGU7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIEBrZXlmcmFtZXMgc3BpbiB7XHJcbiAgICAgIDAlIHsgdHJhbnNmb3JtOiByb3RhdGUoMGRlZyk7IH1cclxuICAgICAgMTAwJSB7IHRyYW5zZm9ybTogcm90YXRlKDM2MGRlZyk7IH1cclxuICAgIH1cclxuICBgXSxcclxufSlcclxuZXhwb3J0IGNsYXNzIFRyZWVOb2RlRXhwYW5kZXJDb21wb25lbnQge1xyXG4gIEBJbnB1dCh7IHJlcXVpcmVkOiB0cnVlIH0pIG5vZGUhOiBUcmVlTm9kZTtcclxuICBASW5wdXQoeyByZXF1aXJlZDogdHJ1ZSB9KSB0cmVlTW9kZWwhOiBUcmVlTW9kZWw7XHJcbiAgQE91dHB1dCgpIHRvZ2dsZSA9IG5ldyBFdmVudEVtaXR0ZXI8dm9pZD4oKTtcclxuICBcclxuICBvbkV4cGFuZGVyQ2xpY2soZXZlbnQ6IE1vdXNlRXZlbnQpOiB2b2lkIHtcclxuICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xyXG4gICAgdGhpcy50b2dnbGUuZW1pdCgpO1xyXG4gIH1cclxufSJdfQ==