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,230 @@
1
+ // lib/components/tree-root/tree-root.component.ts
2
+ import { Component, Input, Output, EventEmitter, HostListener, signal, contentChild, TemplateRef, ChangeDetectionStrategy, } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import { TreeModel } from '../../core/models/tree.model';
5
+ import { DEFAULT_TREE_OPTIONS } from '../../core/models/tree-options.model';
6
+ import { TreeNodeComponent } from '../tree-node/tree-node.component';
7
+ import { TreeViewportComponent } from '../tree-viewport/tree-viewport.component';
8
+ import { TreeNodeTemplateDirective } from '../../directives/tree-node-template.directive';
9
+ import * as i0 from "@angular/core";
10
+ export class TreeRootComponent {
11
+ nodes = [];
12
+ options = {};
13
+ initialized = new EventEmitter();
14
+ toggleExpanded = new EventEmitter();
15
+ activate = new EventEmitter();
16
+ deactivate = new EventEmitter();
17
+ select = new EventEmitter();
18
+ deselect = new EventEmitter();
19
+ focus = new EventEmitter();
20
+ blur = new EventEmitter();
21
+ moveNode = new EventEmitter();
22
+ loadChildren = new EventEmitter();
23
+ treeEvent = new EventEmitter();
24
+ // Content queries
25
+ nodeTemplate = contentChild(TreeNodeTemplateDirective, {
26
+ read: TemplateRef
27
+ });
28
+ treeModel;
29
+ mergedOptions;
30
+ isFocused = signal(false);
31
+ eventsSubscription;
32
+ ngOnInit() {
33
+ this.initializeTreeModel();
34
+ }
35
+ ngOnChanges(changes) {
36
+ if (changes['options'] && !changes['options'].firstChange) {
37
+ this.initializeTreeModel();
38
+ }
39
+ if (changes['nodes'] && !changes['nodes'].firstChange) {
40
+ this.treeModel.setData(this.nodes);
41
+ }
42
+ }
43
+ initializeTreeModel() {
44
+ // Unsubscribe from previous subscription if exists
45
+ this.eventsSubscription?.unsubscribe();
46
+ this.mergedOptions = {
47
+ ...DEFAULT_TREE_OPTIONS,
48
+ ...this.options,
49
+ };
50
+ this.treeModel = new TreeModel(this.mergedOptions);
51
+ this.treeModel.setData(this.nodes);
52
+ // Subscribe to tree events
53
+ this.eventsSubscription = this.treeModel.events$.subscribe(event => {
54
+ this.handleTreeEvent(event);
55
+ });
56
+ }
57
+ ngOnDestroy() {
58
+ // Clean up subscription
59
+ this.eventsSubscription?.unsubscribe();
60
+ }
61
+ handleTreeEvent(event) {
62
+ this.treeEvent.emit(event);
63
+ switch (event.type) {
64
+ case 'initialized':
65
+ this.initialized.emit(event);
66
+ break;
67
+ case 'expand':
68
+ case 'collapse':
69
+ this.toggleExpanded.emit(event);
70
+ break;
71
+ case 'activate':
72
+ this.activate.emit(event);
73
+ break;
74
+ case 'deactivate':
75
+ this.deactivate.emit(event);
76
+ break;
77
+ case 'select':
78
+ this.select.emit(event);
79
+ break;
80
+ case 'deselect':
81
+ this.deselect.emit(event);
82
+ break;
83
+ case 'focus':
84
+ this.focus.emit(event);
85
+ break;
86
+ case 'blur':
87
+ this.blur.emit(event);
88
+ break;
89
+ case 'moveNode':
90
+ this.moveNode.emit(event);
91
+ break;
92
+ case 'loadChildren':
93
+ this.loadChildren.emit(event);
94
+ break;
95
+ }
96
+ }
97
+ // Keyboard navigation
98
+ onKeydown(event) {
99
+ if (!this.isFocused())
100
+ return;
101
+ const key = event.key;
102
+ const isRtl = this.options.rtl;
103
+ switch (key) {
104
+ case 'ArrowDown':
105
+ this.treeModel.focusNextNode();
106
+ event.preventDefault();
107
+ break;
108
+ case 'ArrowUp':
109
+ this.treeModel.focusPreviousNode();
110
+ event.preventDefault();
111
+ break;
112
+ case 'ArrowRight':
113
+ isRtl ? this.treeModel.focusDrillUp() : this.treeModel.focusDrillDown();
114
+ event.preventDefault();
115
+ break;
116
+ case 'ArrowLeft':
117
+ isRtl ? this.treeModel.focusDrillDown() : this.treeModel.focusDrillUp();
118
+ event.preventDefault();
119
+ break;
120
+ case 'Enter':
121
+ case ' ':
122
+ const focused = this.treeModel.focusedNode();
123
+ if (focused) {
124
+ this.treeModel.activateNode(focused);
125
+ }
126
+ event.preventDefault();
127
+ break;
128
+ }
129
+ }
130
+ onFocus() {
131
+ this.isFocused.set(true);
132
+ }
133
+ onBlur() {
134
+ this.isFocused.set(false);
135
+ }
136
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeRootComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
137
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: TreeRootComponent, isStandalone: true, selector: "tree-root", inputs: { nodes: "nodes", options: "options" }, outputs: { initialized: "initialized", toggleExpanded: "toggleExpanded", activate: "activate", deactivate: "deactivate", select: "select", deselect: "deselect", focus: "focus", blur: "blur", moveNode: "moveNode", loadChildren: "loadChildren", treeEvent: "treeEvent" }, host: { listeners: { "keydown": "onKeydown($event)", "focus": "onFocus()", "blur": "onBlur()" }, properties: { "class.tree-focused": "isFocused()" } }, queries: [{ propertyName: "nodeTemplate", first: true, predicate: TreeNodeTemplateDirective, descendants: true, read: TemplateRef, isSignal: true }], usesOnChanges: true, ngImport: i0, template: `
138
+ <div
139
+ class="tree-container"
140
+ [class.tree-rtl]="mergedOptions?.rtl"
141
+ tabindex="0">
142
+
143
+ @if (mergedOptions?.useVirtualScroll) {
144
+ <tree-viewport
145
+ [treeModel]="treeModel"
146
+ [options]="mergedOptions"
147
+ [nodeTemplate]="nodeTemplate()">
148
+ </tree-viewport>
149
+ } @else {
150
+ @for (root of treeModel.roots(); track root.id) {
151
+ <tree-node
152
+ [node]="root"
153
+ [treeModel]="treeModel"
154
+ [options]="mergedOptions"
155
+ [nodeTemplate]="nodeTemplate()">
156
+ </tree-node>
157
+ }
158
+ }
159
+ </div>
160
+ `, isInline: true, styles: [".tree-container{width:100%;height:100%;outline:none}.tree-rtl{direction:rtl}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: TreeNodeComponent, selector: "tree-node", inputs: ["node", "treeModel", "options", "nodeTemplate"] }, { kind: "component", type: TreeViewportComponent, selector: "tree-viewport", inputs: ["treeModel", "options", "nodeTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
161
+ }
162
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeRootComponent, decorators: [{
163
+ type: Component,
164
+ args: [{ selector: 'tree-root', standalone: true, imports: [
165
+ CommonModule,
166
+ TreeNodeComponent,
167
+ TreeViewportComponent,
168
+ ], changeDetection: ChangeDetectionStrategy.OnPush, template: `
169
+ <div
170
+ class="tree-container"
171
+ [class.tree-rtl]="mergedOptions?.rtl"
172
+ tabindex="0">
173
+
174
+ @if (mergedOptions?.useVirtualScroll) {
175
+ <tree-viewport
176
+ [treeModel]="treeModel"
177
+ [options]="mergedOptions"
178
+ [nodeTemplate]="nodeTemplate()">
179
+ </tree-viewport>
180
+ } @else {
181
+ @for (root of treeModel.roots(); track root.id) {
182
+ <tree-node
183
+ [node]="root"
184
+ [treeModel]="treeModel"
185
+ [options]="mergedOptions"
186
+ [nodeTemplate]="nodeTemplate()">
187
+ </tree-node>
188
+ }
189
+ }
190
+ </div>
191
+ `, host: {
192
+ '[class.tree-focused]': 'isFocused()',
193
+ }, styles: [".tree-container{width:100%;height:100%;outline:none}.tree-rtl{direction:rtl}\n"] }]
194
+ }], propDecorators: { nodes: [{
195
+ type: Input
196
+ }], options: [{
197
+ type: Input
198
+ }], initialized: [{
199
+ type: Output
200
+ }], toggleExpanded: [{
201
+ type: Output
202
+ }], activate: [{
203
+ type: Output
204
+ }], deactivate: [{
205
+ type: Output
206
+ }], select: [{
207
+ type: Output
208
+ }], deselect: [{
209
+ type: Output
210
+ }], focus: [{
211
+ type: Output
212
+ }], blur: [{
213
+ type: Output
214
+ }], moveNode: [{
215
+ type: Output
216
+ }], loadChildren: [{
217
+ type: Output
218
+ }], treeEvent: [{
219
+ type: Output
220
+ }], onKeydown: [{
221
+ type: HostListener,
222
+ args: ['keydown', ['$event']]
223
+ }], onFocus: [{
224
+ type: HostListener,
225
+ args: ['focus']
226
+ }], onBlur: [{
227
+ type: HostListener,
228
+ args: ['blur']
229
+ }] } });
230
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS1yb290LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2NvbmNlcHRvLXVzZXItY29udHJvbHMvc3JjL2xpYi9jb25jZXB0by10cmVlL2NvbXBvbmVudHMvdHJlZS1yb290L3RyZWUtcm9vdC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsa0RBQWtEO0FBQ2xELE9BQU8sRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUNMLE1BQU0sRUFDTixZQUFZLEVBS1osWUFBWSxFQUNaLE1BQU0sRUFDTixZQUFZLEVBQ1osV0FBVyxFQUNYLHVCQUF1QixHQUN4QixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFFL0MsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQ3pELE9BQU8sRUFBZSxvQkFBb0IsRUFBRSxNQUFNLHNDQUFzQyxDQUFDO0FBRXpGLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3JFLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDBDQUEwQyxDQUFDO0FBQ2pGLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLCtDQUErQyxDQUFDOztBQWtEMUYsTUFBTSxPQUFPLGlCQUFpQjtJQUNuQixLQUFLLEdBQVUsRUFBRSxDQUFDO0lBQ2xCLE9BQU8sR0FBeUIsRUFBRSxDQUFDO0lBRWxDLFdBQVcsR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQzVDLGNBQWMsR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQy9DLFFBQVEsR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQ3pDLFVBQVUsR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQzNDLE1BQU0sR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQ3ZDLFFBQVEsR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQ3pDLEtBQUssR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQ3RDLElBQUksR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQ3JDLFFBQVEsR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQ3pDLFlBQVksR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBQzdDLFNBQVMsR0FBRyxJQUFJLFlBQVksRUFBYSxDQUFDO0lBRXBELGtCQUFrQjtJQUNULFlBQVksR0FBRyxZQUFZLENBQUMseUJBQXlCLEVBQUU7UUFDOUQsSUFBSSxFQUFFLFdBQVc7S0FDbEIsQ0FBQyxDQUFDO0lBRUgsU0FBUyxDQUFhO0lBQ3RCLGFBQWEsQ0FBZTtJQUM1QixTQUFTLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBRWxCLGtCQUFrQixDQUFnQjtJQUUxQyxRQUFRO1FBQ04sSUFBSSxDQUFDLG1CQUFtQixFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVELFdBQVcsQ0FBQyxPQUFzQjtRQUNoQyxJQUFJLE9BQU8sQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxXQUFXLEVBQUUsQ0FBQztZQUMxRCxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUM3QixDQUFDO1FBRUQsSUFBSSxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDdEQsSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ3JDLENBQUM7SUFDSCxDQUFDO0lBRU8sbUJBQW1CO1FBQ3pCLG1EQUFtRDtRQUNuRCxJQUFJLENBQUMsa0JBQWtCLEVBQUUsV0FBVyxFQUFFLENBQUM7UUFFdkMsSUFBSSxDQUFDLGFBQWEsR0FBRztZQUNuQixHQUFHLG9CQUFvQjtZQUN2QixHQUFHLElBQUksQ0FBQyxPQUFPO1NBQ2hCLENBQUM7UUFFRixJQUFJLENBQUMsU0FBUyxHQUFHLElBQUksU0FBUyxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsQ0FBQztRQUNuRCxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFbkMsMkJBQTJCO1FBQzNCLElBQUksQ0FBQyxrQkFBa0IsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsS0FBSyxDQUFDLEVBQUU7WUFDakUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM5QixDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRCxXQUFXO1FBQ1Qsd0JBQXdCO1FBQ3hCLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxXQUFXLEVBQUUsQ0FBQztJQUN6QyxDQUFDO0lBRU8sZUFBZSxDQUFDLEtBQWdCO1FBQ3RDLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTNCLFFBQVEsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ25CLEtBQUssYUFBYTtnQkFDaEIsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQzdCLE1BQU07WUFDUixLQUFLLFFBQVEsQ0FBQztZQUNkLEtBQUssVUFBVTtnQkFDYixJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDaEMsTUFBTTtZQUNSLEtBQUssVUFBVTtnQkFDYixJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDMUIsTUFBTTtZQUNSLEtBQUssWUFBWTtnQkFDZixJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDNUIsTUFBTTtZQUNSLEtBQUssUUFBUTtnQkFDWCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDeEIsTUFBTTtZQUNSLEtBQUssVUFBVTtnQkFDYixJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDMUIsTUFBTTtZQUNSLEtBQUssT0FBTztnQkFDVixJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDdkIsTUFBTTtZQUNSLEtBQUssTUFBTTtnQkFDVCxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDdEIsTUFBTTtZQUNSLEtBQUssVUFBVTtnQkFDYixJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztnQkFDMUIsTUFBTTtZQUNSLEtBQUssY0FBYztnQkFDakIsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQzlCLE1BQU07UUFDVixDQUFDO0lBQ0gsQ0FBQztJQUVELHNCQUFzQjtJQUV0QixTQUFTLENBQUMsS0FBb0I7UUFDNUIsSUFBSSxDQUFDLElBQUksQ0FBQyxTQUFTLEVBQUU7WUFBRSxPQUFPO1FBRTlCLE1BQU0sR0FBRyxHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUM7UUFDdEIsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUM7UUFFL0IsUUFBUSxHQUFHLEVBQUUsQ0FBQztZQUNaLEtBQUssV0FBVztnQkFDZCxJQUFJLENBQUMsU0FBUyxDQUFDLGFBQWEsRUFBRSxDQUFDO2dCQUMvQixLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU07WUFDUixLQUFLLFNBQVM7Z0JBQ1osSUFBSSxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsRUFBRSxDQUFDO2dCQUNuQyxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU07WUFDUixLQUFLLFlBQVk7Z0JBQ2YsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFlBQVksRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRSxDQUFDO2dCQUN4RSxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU07WUFDUixLQUFLLFdBQVc7Z0JBQ2QsS0FBSyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUN4RSxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUM7Z0JBQ3ZCLE1BQU07WUFDUixLQUFLLE9BQU8sQ0FBQztZQUNiLEtBQUssR0FBRztnQkFDTixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRSxDQUFDO2dCQUM3QyxJQUFJLE9BQU8sRUFBRSxDQUFDO29CQUNaLElBQUksQ0FBQyxTQUFTLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO2dCQUN2QyxDQUFDO2dCQUNELEtBQUssQ0FBQyxjQUFjLEVBQUUsQ0FBQztnQkFDdkIsTUFBTTtRQUNWLENBQUM7SUFDSCxDQUFDO0lBR0QsT0FBTztRQUNMLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzNCLENBQUM7SUFHRCxNQUFNO1FBQ0osSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDNUIsQ0FBQzt3R0FsSlUsaUJBQWlCOzRGQUFqQixpQkFBaUIsb2tCQWlCUyx5QkFBeUIsMkJBQ3RELFdBQVcsa0VBekRUOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXVCVCx1SkE1QkMsWUFBWSwrQkFDWixpQkFBaUIsZ0hBQ2pCLHFCQUFxQjs7NEZBMENaLGlCQUFpQjtrQkFoRDdCLFNBQVM7K0JBQ0UsV0FBVyxjQUNULElBQUksV0FDUDt3QkFDUCxZQUFZO3dCQUNaLGlCQUFpQjt3QkFDakIscUJBQXFCO3FCQUN0QixtQkFDZ0IsdUJBQXVCLENBQUMsTUFBTSxZQUNyQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0F1QlQsUUFZSzt3QkFDSixzQkFBc0IsRUFBRSxhQUFhO3FCQUN0Qzs4QkFHUSxLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUVJLFdBQVc7c0JBQXBCLE1BQU07Z0JBQ0csY0FBYztzQkFBdkIsTUFBTTtnQkFDRyxRQUFRO3NCQUFqQixNQUFNO2dCQUNHLFVBQVU7c0JBQW5CLE1BQU07Z0JBQ0csTUFBTTtzQkFBZixNQUFNO2dCQUNHLFFBQVE7c0JBQWpCLE1BQU07Z0JBQ0csS0FBSztzQkFBZCxNQUFNO2dCQUNHLElBQUk7c0JBQWIsTUFBTTtnQkFDRyxRQUFRO3NCQUFqQixNQUFNO2dCQUNHLFlBQVk7c0JBQXJCLE1BQU07Z0JBQ0csU0FBUztzQkFBbEIsTUFBTTtnQkEwRlAsU0FBUztzQkFEUixZQUFZO3VCQUFDLFNBQVMsRUFBRSxDQUFDLFFBQVEsQ0FBQztnQkFvQ25DLE9BQU87c0JBRE4sWUFBWTt1QkFBQyxPQUFPO2dCQU1yQixNQUFNO3NCQURMLFlBQVk7dUJBQUMsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbIi8vIGxpYi9jb21wb25lbnRzL3RyZWUtcm9vdC90cmVlLXJvb3QuY29tcG9uZW50LnRzXHJcbmltcG9ydCB7XHJcbiAgQ29tcG9uZW50LFxyXG4gIElucHV0LFxyXG4gIE91dHB1dCxcclxuICBFdmVudEVtaXR0ZXIsXHJcbiAgT25Jbml0LFxyXG4gIE9uQ2hhbmdlcyxcclxuICBPbkRlc3Ryb3ksXHJcbiAgU2ltcGxlQ2hhbmdlcyxcclxuICBIb3N0TGlzdGVuZXIsXHJcbiAgc2lnbmFsLFxyXG4gIGNvbnRlbnRDaGlsZCxcclxuICBUZW1wbGF0ZVJlZixcclxuICBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneSxcclxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgQ29tbW9uTW9kdWxlIH0gZnJvbSAnQGFuZ3VsYXIvY29tbW9uJztcclxuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IFRyZWVNb2RlbCB9IGZyb20gJy4uLy4uL2NvcmUvbW9kZWxzL3RyZWUubW9kZWwnO1xyXG5pbXBvcnQgeyBUcmVlT3B0aW9ucywgREVGQVVMVF9UUkVFX09QVElPTlMgfSBmcm9tICcuLi8uLi9jb3JlL21vZGVscy90cmVlLW9wdGlvbnMubW9kZWwnO1xyXG5pbXBvcnQgeyBUcmVlRXZlbnQgfSBmcm9tICcuLi8uLi9jb3JlL21vZGVscy90cmVlLWV2ZW50cy5tb2RlbCc7XHJcbmltcG9ydCB7IFRyZWVOb2RlQ29tcG9uZW50IH0gZnJvbSAnLi4vdHJlZS1ub2RlL3RyZWUtbm9kZS5jb21wb25lbnQnO1xyXG5pbXBvcnQgeyBUcmVlVmlld3BvcnRDb21wb25lbnQgfSBmcm9tICcuLi90cmVlLXZpZXdwb3J0L3RyZWUtdmlld3BvcnQuY29tcG9uZW50JztcclxuaW1wb3J0IHsgVHJlZU5vZGVUZW1wbGF0ZURpcmVjdGl2ZSB9IGZyb20gJy4uLy4uL2RpcmVjdGl2ZXMvdHJlZS1ub2RlLXRlbXBsYXRlLmRpcmVjdGl2ZSc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ3RyZWUtcm9vdCcsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbXHJcbiAgICBDb21tb25Nb2R1bGUsXHJcbiAgICBUcmVlTm9kZUNvbXBvbmVudCxcclxuICAgIFRyZWVWaWV3cG9ydENvbXBvbmVudCxcclxuICBdLFxyXG4gIGNoYW5nZURldGVjdGlvbjogQ2hhbmdlRGV0ZWN0aW9uU3RyYXRlZ3kuT25QdXNoLFxyXG4gIHRlbXBsYXRlOiBgXHJcbiAgICA8ZGl2XHJcbiAgICAgIGNsYXNzPVwidHJlZS1jb250YWluZXJcIlxyXG4gICAgICBbY2xhc3MudHJlZS1ydGxdPVwibWVyZ2VkT3B0aW9ucz8ucnRsXCJcclxuICAgICAgdGFiaW5kZXg9XCIwXCI+XHJcblxyXG4gICAgICBAaWYgKG1lcmdlZE9wdGlvbnM/LnVzZVZpcnR1YWxTY3JvbGwpIHtcclxuICAgICAgICA8dHJlZS12aWV3cG9ydFxyXG4gICAgICAgICAgW3RyZWVNb2RlbF09XCJ0cmVlTW9kZWxcIlxyXG4gICAgICAgICAgW29wdGlvbnNdPVwibWVyZ2VkT3B0aW9uc1wiXHJcbiAgICAgICAgICBbbm9kZVRlbXBsYXRlXT1cIm5vZGVUZW1wbGF0ZSgpXCI+XHJcbiAgICAgICAgPC90cmVlLXZpZXdwb3J0PlxyXG4gICAgICB9IEBlbHNlIHtcclxuICAgICAgICBAZm9yIChyb290IG9mIHRyZWVNb2RlbC5yb290cygpOyB0cmFjayByb290LmlkKSB7XHJcbiAgICAgICAgICA8dHJlZS1ub2RlXHJcbiAgICAgICAgICAgIFtub2RlXT1cInJvb3RcIlxyXG4gICAgICAgICAgICBbdHJlZU1vZGVsXT1cInRyZWVNb2RlbFwiXHJcbiAgICAgICAgICAgIFtvcHRpb25zXT1cIm1lcmdlZE9wdGlvbnNcIlxyXG4gICAgICAgICAgICBbbm9kZVRlbXBsYXRlXT1cIm5vZGVUZW1wbGF0ZSgpXCI+XHJcbiAgICAgICAgICA8L3RyZWUtbm9kZT5cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIDwvZGl2PlxyXG4gIGAsXHJcbiAgc3R5bGVzOiBbYFxyXG4gICAgLnRyZWUtY29udGFpbmVyIHtcclxuICAgICAgd2lkdGg6IDEwMCU7XHJcbiAgICAgIGhlaWdodDogMTAwJTtcclxuICAgICAgb3V0bGluZTogbm9uZTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgLnRyZWUtcnRsIHtcclxuICAgICAgZGlyZWN0aW9uOiBydGw7XHJcbiAgICB9XHJcbiAgYF0sXHJcbiAgaG9zdDoge1xyXG4gICAgJ1tjbGFzcy50cmVlLWZvY3VzZWRdJzogJ2lzRm9jdXNlZCgpJyxcclxuICB9LFxyXG59KVxyXG5leHBvcnQgY2xhc3MgVHJlZVJvb3RDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQsIE9uQ2hhbmdlcywgT25EZXN0cm95IHtcclxuICBASW5wdXQoKSBub2RlczogYW55W10gPSBbXTtcclxuICBASW5wdXQoKSBvcHRpb25zOiBQYXJ0aWFsPFRyZWVPcHRpb25zPiA9IHt9O1xyXG4gIFxyXG4gIEBPdXRwdXQoKSBpbml0aWFsaXplZCA9IG5ldyBFdmVudEVtaXR0ZXI8VHJlZUV2ZW50PigpO1xyXG4gIEBPdXRwdXQoKSB0b2dnbGVFeHBhbmRlZCA9IG5ldyBFdmVudEVtaXR0ZXI8VHJlZUV2ZW50PigpO1xyXG4gIEBPdXRwdXQoKSBhY3RpdmF0ZSA9IG5ldyBFdmVudEVtaXR0ZXI8VHJlZUV2ZW50PigpO1xyXG4gIEBPdXRwdXQoKSBkZWFjdGl2YXRlID0gbmV3IEV2ZW50RW1pdHRlcjxUcmVlRXZlbnQ+KCk7XHJcbiAgQE91dHB1dCgpIHNlbGVjdCA9IG5ldyBFdmVudEVtaXR0ZXI8VHJlZUV2ZW50PigpO1xyXG4gIEBPdXRwdXQoKSBkZXNlbGVjdCA9IG5ldyBFdmVudEVtaXR0ZXI8VHJlZUV2ZW50PigpO1xyXG4gIEBPdXRwdXQoKSBmb2N1cyA9IG5ldyBFdmVudEVtaXR0ZXI8VHJlZUV2ZW50PigpO1xyXG4gIEBPdXRwdXQoKSBibHVyID0gbmV3IEV2ZW50RW1pdHRlcjxUcmVlRXZlbnQ+KCk7XHJcbiAgQE91dHB1dCgpIG1vdmVOb2RlID0gbmV3IEV2ZW50RW1pdHRlcjxUcmVlRXZlbnQ+KCk7XHJcbiAgQE91dHB1dCgpIGxvYWRDaGlsZHJlbiA9IG5ldyBFdmVudEVtaXR0ZXI8VHJlZUV2ZW50PigpO1xyXG4gIEBPdXRwdXQoKSB0cmVlRXZlbnQgPSBuZXcgRXZlbnRFbWl0dGVyPFRyZWVFdmVudD4oKTtcclxuICBcclxuICAvLyBDb250ZW50IHF1ZXJpZXNcclxuICByZWFkb25seSBub2RlVGVtcGxhdGUgPSBjb250ZW50Q2hpbGQoVHJlZU5vZGVUZW1wbGF0ZURpcmVjdGl2ZSwge1xyXG4gICAgcmVhZDogVGVtcGxhdGVSZWZcclxuICB9KTtcclxuICBcclxuICB0cmVlTW9kZWwhOiBUcmVlTW9kZWw7XHJcbiAgbWVyZ2VkT3B0aW9ucyE6IFRyZWVPcHRpb25zO1xyXG4gIGlzRm9jdXNlZCA9IHNpZ25hbChmYWxzZSk7XHJcblxyXG4gIHByaXZhdGUgZXZlbnRzU3Vic2NyaXB0aW9uPzogU3Vic2NyaXB0aW9uO1xyXG4gIFxyXG4gIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5pbml0aWFsaXplVHJlZU1vZGVsKCk7XHJcbiAgfVxyXG4gIFxyXG4gIG5nT25DaGFuZ2VzKGNoYW5nZXM6IFNpbXBsZUNoYW5nZXMpOiB2b2lkIHtcclxuICAgIGlmIChjaGFuZ2VzWydvcHRpb25zJ10gJiYgIWNoYW5nZXNbJ29wdGlvbnMnXS5maXJzdENoYW5nZSkge1xyXG4gICAgICB0aGlzLmluaXRpYWxpemVUcmVlTW9kZWwoKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgaWYgKGNoYW5nZXNbJ25vZGVzJ10gJiYgIWNoYW5nZXNbJ25vZGVzJ10uZmlyc3RDaGFuZ2UpIHtcclxuICAgICAgdGhpcy50cmVlTW9kZWwuc2V0RGF0YSh0aGlzLm5vZGVzKTtcclxuICAgIH1cclxuICB9XHJcbiAgXHJcbiAgcHJpdmF0ZSBpbml0aWFsaXplVHJlZU1vZGVsKCk6IHZvaWQge1xyXG4gICAgLy8gVW5zdWJzY3JpYmUgZnJvbSBwcmV2aW91cyBzdWJzY3JpcHRpb24gaWYgZXhpc3RzXHJcbiAgICB0aGlzLmV2ZW50c1N1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcclxuXHJcbiAgICB0aGlzLm1lcmdlZE9wdGlvbnMgPSB7XHJcbiAgICAgIC4uLkRFRkFVTFRfVFJFRV9PUFRJT05TLFxyXG4gICAgICAuLi50aGlzLm9wdGlvbnMsXHJcbiAgICB9O1xyXG5cclxuICAgIHRoaXMudHJlZU1vZGVsID0gbmV3IFRyZWVNb2RlbCh0aGlzLm1lcmdlZE9wdGlvbnMpO1xyXG4gICAgdGhpcy50cmVlTW9kZWwuc2V0RGF0YSh0aGlzLm5vZGVzKTtcclxuXHJcbiAgICAvLyBTdWJzY3JpYmUgdG8gdHJlZSBldmVudHNcclxuICAgIHRoaXMuZXZlbnRzU3Vic2NyaXB0aW9uID0gdGhpcy50cmVlTW9kZWwuZXZlbnRzJC5zdWJzY3JpYmUoZXZlbnQgPT4ge1xyXG4gICAgICB0aGlzLmhhbmRsZVRyZWVFdmVudChldmVudCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xyXG4gICAgLy8gQ2xlYW4gdXAgc3Vic2NyaXB0aW9uXHJcbiAgICB0aGlzLmV2ZW50c1N1YnNjcmlwdGlvbj8udW5zdWJzY3JpYmUoKTtcclxuICB9XHJcbiAgXHJcbiAgcHJpdmF0ZSBoYW5kbGVUcmVlRXZlbnQoZXZlbnQ6IFRyZWVFdmVudCk6IHZvaWQge1xyXG4gICAgdGhpcy50cmVlRXZlbnQuZW1pdChldmVudCk7XHJcbiAgICBcclxuICAgIHN3aXRjaCAoZXZlbnQudHlwZSkge1xyXG4gICAgICBjYXNlICdpbml0aWFsaXplZCc6XHJcbiAgICAgICAgdGhpcy5pbml0aWFsaXplZC5lbWl0KGV2ZW50KTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAnZXhwYW5kJzpcclxuICAgICAgY2FzZSAnY29sbGFwc2UnOlxyXG4gICAgICAgIHRoaXMudG9nZ2xlRXhwYW5kZWQuZW1pdChldmVudCk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgJ2FjdGl2YXRlJzpcclxuICAgICAgICB0aGlzLmFjdGl2YXRlLmVtaXQoZXZlbnQpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdkZWFjdGl2YXRlJzpcclxuICAgICAgICB0aGlzLmRlYWN0aXZhdGUuZW1pdChldmVudCk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgJ3NlbGVjdCc6XHJcbiAgICAgICAgdGhpcy5zZWxlY3QuZW1pdChldmVudCk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgJ2Rlc2VsZWN0JzpcclxuICAgICAgICB0aGlzLmRlc2VsZWN0LmVtaXQoZXZlbnQpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdmb2N1cyc6XHJcbiAgICAgICAgdGhpcy5mb2N1cy5lbWl0KGV2ZW50KTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAnYmx1cic6XHJcbiAgICAgICAgdGhpcy5ibHVyLmVtaXQoZXZlbnQpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdtb3ZlTm9kZSc6XHJcbiAgICAgICAgdGhpcy5tb3ZlTm9kZS5lbWl0KGV2ZW50KTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAnbG9hZENoaWxkcmVuJzpcclxuICAgICAgICB0aGlzLmxvYWRDaGlsZHJlbi5lbWl0KGV2ZW50KTtcclxuICAgICAgICBicmVhaztcclxuICAgIH1cclxuICB9XHJcbiAgXHJcbiAgLy8gS2V5Ym9hcmQgbmF2aWdhdGlvblxyXG4gIEBIb3N0TGlzdGVuZXIoJ2tleWRvd24nLCBbJyRldmVudCddKVxyXG4gIG9uS2V5ZG93bihldmVudDogS2V5Ym9hcmRFdmVudCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLmlzRm9jdXNlZCgpKSByZXR1cm47XHJcbiAgICBcclxuICAgIGNvbnN0IGtleSA9IGV2ZW50LmtleTtcclxuICAgIGNvbnN0IGlzUnRsID0gdGhpcy5vcHRpb25zLnJ0bDtcclxuICAgIFxyXG4gICAgc3dpdGNoIChrZXkpIHtcclxuICAgICAgY2FzZSAnQXJyb3dEb3duJzpcclxuICAgICAgICB0aGlzLnRyZWVNb2RlbC5mb2N1c05leHROb2RlKCk7XHJcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAnQXJyb3dVcCc6XHJcbiAgICAgICAgdGhpcy50cmVlTW9kZWwuZm9jdXNQcmV2aW91c05vZGUoKTtcclxuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdBcnJvd1JpZ2h0JzpcclxuICAgICAgICBpc1J0bCA/IHRoaXMudHJlZU1vZGVsLmZvY3VzRHJpbGxVcCgpIDogdGhpcy50cmVlTW9kZWwuZm9jdXNEcmlsbERvd24oKTtcclxuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdBcnJvd0xlZnQnOlxyXG4gICAgICAgIGlzUnRsID8gdGhpcy50cmVlTW9kZWwuZm9jdXNEcmlsbERvd24oKSA6IHRoaXMudHJlZU1vZGVsLmZvY3VzRHJpbGxVcCgpO1xyXG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgJ0VudGVyJzpcclxuICAgICAgY2FzZSAnICc6XHJcbiAgICAgICAgY29uc3QgZm9jdXNlZCA9IHRoaXMudHJlZU1vZGVsLmZvY3VzZWROb2RlKCk7XHJcbiAgICAgICAgaWYgKGZvY3VzZWQpIHtcclxuICAgICAgICAgIHRoaXMudHJlZU1vZGVsLmFjdGl2YXRlTm9kZShmb2N1c2VkKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcclxuICAgICAgICBicmVhaztcclxuICAgIH1cclxuICB9XHJcbiAgXHJcbiAgQEhvc3RMaXN0ZW5lcignZm9jdXMnKVxyXG4gIG9uRm9jdXMoKTogdm9pZCB7XHJcbiAgICB0aGlzLmlzRm9jdXNlZC5zZXQodHJ1ZSk7XHJcbiAgfVxyXG4gIFxyXG4gIEBIb3N0TGlzdGVuZXIoJ2JsdXInKVxyXG4gIG9uQmx1cigpOiB2b2lkIHtcclxuICAgIHRoaXMuaXNGb2N1c2VkLnNldChmYWxzZSk7XHJcbiAgfVxyXG59Il19
@@ -0,0 +1,216 @@
1
+ // lib/components/tree-viewport/tree-viewport.component.ts
2
+ import { Component, Input, ViewChild, ChangeDetectionStrategy, signal, computed, effect, } from '@angular/core';
3
+ import { CommonModule } from '@angular/common';
4
+ import { TreeNodeComponent } from '../tree-node/tree-node.component';
5
+ import { fromEvent, Subject, takeUntil } from 'rxjs';
6
+ import { debounceTime } from 'rxjs/operators';
7
+ import * as i0 from "@angular/core";
8
+ export class TreeViewportComponent {
9
+ treeModel;
10
+ options;
11
+ nodeTemplate;
12
+ scrollContainer;
13
+ destroy$ = new Subject();
14
+ scrollTop = signal(0);
15
+ viewportHeight = signal(0);
16
+ flattenedNodes = computed(() => {
17
+ return this.treeModel.flattenedNodes();
18
+ });
19
+ totalHeight = computed(() => {
20
+ const nodes = this.flattenedNodes();
21
+ const nodeHeight = this.options.nodeHeight || 22;
22
+ if (typeof nodeHeight === 'number') {
23
+ return nodes.length * nodeHeight;
24
+ }
25
+ return nodes.reduce((sum, node) => sum + nodeHeight(node), 0);
26
+ });
27
+ visibleRange = computed(() => {
28
+ const scrollTop = this.scrollTop();
29
+ const viewportHeight = this.viewportHeight();
30
+ const nodes = this.flattenedNodes();
31
+ const nodeHeight = this.options.nodeHeight || 22;
32
+ const bufferAmount = this.options.bufferAmount || 5;
33
+ let startIndex = 0;
34
+ let accumulatedHeight = 0;
35
+ // Find start index
36
+ for (let i = 0; i < nodes.length; i++) {
37
+ const height = typeof nodeHeight === 'number'
38
+ ? nodeHeight
39
+ : nodeHeight(nodes[i]);
40
+ if (accumulatedHeight + height > scrollTop) {
41
+ startIndex = Math.max(0, i - bufferAmount);
42
+ break;
43
+ }
44
+ accumulatedHeight += height;
45
+ }
46
+ // Find end index
47
+ let endIndex = startIndex;
48
+ accumulatedHeight = 0;
49
+ for (let i = startIndex; i < nodes.length; i++) {
50
+ const height = typeof nodeHeight === 'number'
51
+ ? nodeHeight
52
+ : nodeHeight(nodes[i]);
53
+ accumulatedHeight += height;
54
+ if (accumulatedHeight > viewportHeight + (bufferAmount * (typeof nodeHeight === 'number' ? nodeHeight : 22))) {
55
+ endIndex = i;
56
+ break;
57
+ }
58
+ }
59
+ if (endIndex === startIndex) {
60
+ endIndex = nodes.length;
61
+ }
62
+ return { startIndex, endIndex };
63
+ });
64
+ visibleNodes = computed(() => {
65
+ const range = this.visibleRange();
66
+ const nodes = this.flattenedNodes();
67
+ return nodes.slice(range.startIndex, range.endIndex);
68
+ });
69
+ paddingTop = computed(() => {
70
+ const range = this.visibleRange();
71
+ const nodes = this.flattenedNodes();
72
+ const nodeHeight = this.options.nodeHeight || 22;
73
+ let height = 0;
74
+ for (let i = 0; i < range.startIndex; i++) {
75
+ height += typeof nodeHeight === 'number'
76
+ ? nodeHeight
77
+ : nodeHeight(nodes[i]);
78
+ }
79
+ return height;
80
+ });
81
+ paddingBottom = computed(() => {
82
+ const range = this.visibleRange();
83
+ const nodes = this.flattenedNodes();
84
+ const nodeHeight = this.options.nodeHeight || 22;
85
+ const totalHeight = this.totalHeight();
86
+ let visibleHeight = this.paddingTop();
87
+ for (let i = range.startIndex; i < range.endIndex; i++) {
88
+ visibleHeight += typeof nodeHeight === 'number'
89
+ ? nodeHeight
90
+ : nodeHeight(nodes[i]);
91
+ }
92
+ return Math.max(0, totalHeight - visibleHeight);
93
+ });
94
+ constructor() {
95
+ // Update viewport when tree changes
96
+ effect(() => {
97
+ this.flattenedNodes(); // Subscribe to changes
98
+ this.updateViewport();
99
+ });
100
+ }
101
+ ngOnInit() {
102
+ this.setupScrollListener();
103
+ this.updateViewportHeight();
104
+ }
105
+ ngOnDestroy() {
106
+ this.destroy$.next();
107
+ this.destroy$.complete();
108
+ }
109
+ setupScrollListener() {
110
+ fromEvent(this.scrollContainer.nativeElement, 'scroll')
111
+ .pipe(debounceTime(10), takeUntil(this.destroy$))
112
+ .subscribe(() => {
113
+ this.onScroll();
114
+ });
115
+ }
116
+ updateViewportHeight() {
117
+ const height = this.scrollContainer.nativeElement.clientHeight;
118
+ this.viewportHeight.set(height);
119
+ }
120
+ onScroll() {
121
+ const scrollTop = this.scrollContainer.nativeElement.scrollTop;
122
+ this.scrollTop.set(scrollTop);
123
+ }
124
+ updateViewport() {
125
+ // Force recalculation
126
+ this.scrollTop.set(this.scrollContainer.nativeElement.scrollTop);
127
+ }
128
+ scrollToNode(node) {
129
+ const nodes = this.flattenedNodes();
130
+ const index = nodes.findIndex(n => n.id === node.id);
131
+ if (index === -1)
132
+ return;
133
+ const nodeHeight = this.options.nodeHeight || 22;
134
+ let targetScrollTop = 0;
135
+ for (let i = 0; i < index; i++) {
136
+ targetScrollTop += typeof nodeHeight === 'number'
137
+ ? nodeHeight
138
+ : nodeHeight(nodes[i]);
139
+ }
140
+ this.scrollContainer.nativeElement.scrollTop = targetScrollTop;
141
+ }
142
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeViewportComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
143
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.13", type: TreeViewportComponent, isStandalone: true, selector: "tree-viewport", inputs: { treeModel: "treeModel", options: "options", nodeTemplate: "nodeTemplate" }, viewQueries: [{ propertyName: "scrollContainer", first: true, predicate: ["scrollContainer"], descendants: true, static: true }], ngImport: i0, template: `
144
+ <div
145
+ #scrollContainer
146
+ class="tree-viewport-container"
147
+ [style.height.px]="options.scrollContainerHeight || 400"
148
+ (scroll)="onScroll()">
149
+
150
+ <div class="tree-viewport-content"
151
+ [style.height.px]="totalHeight()">
152
+
153
+ <div class="tree-viewport-padding-top"
154
+ [style.height.px]="paddingTop()">
155
+ </div>
156
+
157
+ @for (node of visibleNodes(); track node.id) {
158
+ <tree-node
159
+ [node]="node"
160
+ [treeModel]="treeModel"
161
+ [options]="options"
162
+ [nodeTemplate]="nodeTemplate">
163
+ </tree-node>
164
+ }
165
+
166
+ <div class="tree-viewport-padding-bottom"
167
+ [style.height.px]="paddingBottom()">
168
+ </div>
169
+ </div>
170
+ </div>
171
+ `, isInline: true, styles: [".tree-viewport-container{overflow-y:auto;overflow-x:hidden;position:relative}.tree-viewport-content{position:relative;width:100%}.tree-viewport-padding-top,.tree-viewport-padding-bottom{width:100%}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: TreeNodeComponent, selector: "tree-node", inputs: ["node", "treeModel", "options", "nodeTemplate"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
172
+ }
173
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: TreeViewportComponent, decorators: [{
174
+ type: Component,
175
+ args: [{ selector: 'tree-viewport', standalone: true, imports: [CommonModule, TreeNodeComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: `
176
+ <div
177
+ #scrollContainer
178
+ class="tree-viewport-container"
179
+ [style.height.px]="options.scrollContainerHeight || 400"
180
+ (scroll)="onScroll()">
181
+
182
+ <div class="tree-viewport-content"
183
+ [style.height.px]="totalHeight()">
184
+
185
+ <div class="tree-viewport-padding-top"
186
+ [style.height.px]="paddingTop()">
187
+ </div>
188
+
189
+ @for (node of visibleNodes(); track node.id) {
190
+ <tree-node
191
+ [node]="node"
192
+ [treeModel]="treeModel"
193
+ [options]="options"
194
+ [nodeTemplate]="nodeTemplate">
195
+ </tree-node>
196
+ }
197
+
198
+ <div class="tree-viewport-padding-bottom"
199
+ [style.height.px]="paddingBottom()">
200
+ </div>
201
+ </div>
202
+ </div>
203
+ `, styles: [".tree-viewport-container{overflow-y:auto;overflow-x:hidden;position:relative}.tree-viewport-content{position:relative;width:100%}.tree-viewport-padding-top,.tree-viewport-padding-bottom{width:100%}\n"] }]
204
+ }], ctorParameters: () => [], propDecorators: { treeModel: [{
205
+ type: Input,
206
+ args: [{ required: true }]
207
+ }], options: [{
208
+ type: Input,
209
+ args: [{ required: true }]
210
+ }], nodeTemplate: [{
211
+ type: Input
212
+ }], scrollContainer: [{
213
+ type: ViewChild,
214
+ args: ['scrollContainer', { static: true }]
215
+ }] } });
216
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHJlZS12aWV3cG9ydC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jb25jZXB0by11c2VyLWNvbnRyb2xzL3NyYy9saWIvY29uY2VwdG8tdHJlZS9jb21wb25lbnRzL3RyZWUtdmlld3BvcnQvdHJlZS12aWV3cG9ydC5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsMERBQTBEO0FBQzFELE9BQU8sRUFDTCxTQUFTLEVBQ1QsS0FBSyxFQUdMLFNBQVMsRUFFVCx1QkFBdUIsRUFDdkIsTUFBTSxFQUNOLFFBQVEsRUFFUixNQUFNLEdBQ1AsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBSS9DLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBQ3JFLE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUNyRCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7O0FBc0Q5QyxNQUFNLE9BQU8scUJBQXFCO0lBQ0wsU0FBUyxDQUFhO0lBQ3RCLE9BQU8sQ0FBZTtJQUN4QyxZQUFZLENBQW9CO0lBR3pDLGVBQWUsQ0FBMkI7SUFFbEMsUUFBUSxHQUFHLElBQUksT0FBTyxFQUFRLENBQUM7SUFFOUIsU0FBUyxHQUFHLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN0QixjQUFjLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBRTNCLGNBQWMsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQ3RDLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUN6QyxDQUFDLENBQUMsQ0FBQztJQUVNLFdBQVcsR0FBRyxRQUFRLENBQUMsR0FBRyxFQUFFO1FBQ25DLE1BQU0sS0FBSyxH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Q0FBQztJQUNqRSxDQUFDO3dHQTdLVSxxQkFBcUI7NEZBQXJCLHFCQUFxQixpU0EvQ3RCOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNEJULGdSQTlCUyxZQUFZLCtCQUFFLGlCQUFpQjs7NEZBaUQ5QixxQkFBcUI7a0JBcERqQyxTQUFTOytCQUNFLGVBQWUsY0FDYixJQUFJLFdBQ1AsQ0FBQyxZQUFZLEVBQUUsaUJBQWlCLENBQUMsbUJBQ3pCLHVCQUF1QixDQUFDLE1BQU0sWUFDckM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0E0QlQ7d0RBb0IwQixTQUFTO3NCQUFuQyxLQUFLO3VCQUFDLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRTtnQkFDRSxPQUFPO3NCQUFqQyxLQUFLO3VCQUFDLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRTtnQkFDaEIsWUFBWTtzQkFBcEIsS0FBSztnQkFHTixlQUFlO3NCQURkLFNBQVM7dUJBQUMsaUJBQWlCLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiLy8gbGliL2NvbXBvbmVudHMvdHJlZS12aWV3cG9ydC90cmVlLXZpZXdwb3J0LmNvbXBvbmVudC50c1xyXG5pbXBvcnQge1xyXG4gIENvbXBvbmVudCxcclxuICBJbnB1dCxcclxuICBPbkluaXQsXHJcbiAgT25EZXN0cm95LFxyXG4gIFZpZXdDaGlsZCxcclxuICBFbGVtZW50UmVmLFxyXG4gIENoYW5nZURldGVjdGlvblN0cmF0ZWd5LFxyXG4gIHNpZ25hbCxcclxuICBjb21wdXRlZCxcclxuICBUZW1wbGF0ZVJlZixcclxuICBlZmZlY3QsXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IFRyZWVNb2RlbCB9IGZyb20gJy4uLy4uL2NvcmUvbW9kZWxzL3RyZWUubW9kZWwnO1xyXG5pbXBvcnQgeyBUcmVlTm9kZSB9IGZyb20gJy4uLy4uL2NvcmUvbW9kZWxzL3RyZWUtbm9kZS5tb2RlbCc7XHJcbmltcG9ydCB7IFRyZWVPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29yZS9tb2RlbHMvdHJlZS1vcHRpb25zLm1vZGVsJztcclxuaW1wb3J0IHsgVHJlZU5vZGVDb21wb25lbnQgfSBmcm9tICcuLi90cmVlLW5vZGUvdHJlZS1ub2RlLmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IGZyb21FdmVudCwgU3ViamVjdCwgdGFrZVVudGlsIH0gZnJvbSAncnhqcyc7XHJcbmltcG9ydCB7IGRlYm91bmNlVGltZSB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuXHJcbkBDb21wb25lbnQoe1xyXG4gIHNlbGVjdG9yOiAndHJlZS12aWV3cG9ydCcsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbQ29tbW9uTW9kdWxlLCBUcmVlTm9kZUNvbXBvbmVudF0sXHJcbiAgY2hhbmdlRGV0ZWN0aW9uOiBDaGFuZ2VEZXRlY3Rpb25TdHJhdGVneS5PblB1c2gsXHJcbiAgdGVtcGxhdGU6IGBcclxuICAgIDxkaXYgXHJcbiAgICAgICNzY3JvbGxDb250YWluZXJcclxuICAgICAgY2xhc3M9XCJ0cmVlLXZpZXdwb3J0LWNvbnRhaW5lclwiXHJcbiAgICAgIFtzdHlsZS5oZWlnaHQucHhdPVwib3B0aW9ucy5zY3JvbGxDb250YWluZXJIZWlnaHQgfHwgNDAwXCJcclxuICAgICAgKHNjcm9sbCk9XCJvblNjcm9sbCgpXCI+XHJcbiAgICAgIFxyXG4gICAgICA8ZGl2IGNsYXNzPVwidHJlZS12aWV3cG9ydC1jb250ZW50XCJcclxuICAgICAgICAgICBbc3R5bGUuaGVpZ2h0LnB4XT1cInRvdGFsSGVpZ2h0KClcIj5cclxuICAgICAgICBcclxuICAgICAgICA8ZGl2IGNsYXNzPVwidHJlZS12aWV3cG9ydC1wYWRkaW5nLXRvcFwiXHJcbiAgICAgICAgICAgICBbc3R5bGUuaGVpZ2h0LnB4XT1cInBhZGRpbmdUb3AoKVwiPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICAgIFxyXG4gICAgICAgIEBmb3IgKG5vZGUgb2YgdmlzaWJsZU5vZGVzKCk7IHRyYWNrIG5vZGUuaWQpIHtcclxuICAgICAgICAgIDx0cmVlLW5vZGVcclxuICAgICAgICAgICAgW25vZGVdPVwibm9kZVwiXHJcbiAgICAgICAgICAgIFt0cmVlTW9kZWxdPVwidHJlZU1vZGVsXCJcclxuICAgICAgICAgICAgW29wdGlvbnNdPVwib3B0aW9uc1wiXHJcbiAgICAgICAgICAgIFtub2RlVGVtcGxhdGVdPVwibm9kZVRlbXBsYXRlXCI+XHJcbiAgICAgICAgICA8L3RyZWUtbm9kZT5cclxuICAgICAgICB9XHJcbiAgICAgICAgXHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInRyZWUtdmlld3BvcnQtcGFkZGluZy1ib3R0b21cIlxyXG4gICAgICAgICAgICAgW3N0eWxlLmhlaWdodC5weF09XCJwYWRkaW5nQm90dG9tKClcIj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgPC9kaXY+XHJcbiAgICA8L2Rpdj5cclxuICBgLFxyXG4gIHN0eWxlczogW2BcclxuICAgIC50cmVlLXZpZXdwb3J0LWNvbnRhaW5lciB7XHJcbiAgICAgIG92ZXJmbG93LXk6IGF1dG87XHJcbiAgICAgIG92ZXJmbG93LXg6IGhpZGRlbjtcclxuICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICAudHJlZS12aWV3cG9ydC1jb250ZW50IHtcclxuICAgICAgcG9zaXRpb246IHJlbGF0aXZlO1xyXG4gICAgICB3aWR0aDogMTAwJTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgLnRyZWUtdmlld3BvcnQtcGFkZGluZy10b3AsXHJcbiAgICAudHJlZS12aWV3cG9ydC1wYWRkaW5nLWJvdHRvbSB7XHJcbiAgICAgIHdpZHRoOiAxMDAlO1xyXG4gICAgfVxyXG4gIGBdLFxyXG59KVxyXG5leHBvcnQgY2xhc3MgVHJlZVZpZXdwb3J0Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkRlc3Ryb3kge1xyXG4gIEBJbnB1dCh7IHJlcXVpcmVkOiB0cnVlIH0pIHRyZWVNb2RlbCE6IFRyZWVNb2RlbDtcclxuICBASW5wdXQoeyByZXF1aXJlZDogdHJ1ZSB9KSBvcHRpb25zITogVHJlZU9wdGlvbnM7XHJcbiAgQElucHV0KCkgbm9kZVRlbXBsYXRlPzogVGVtcGxhdGVSZWY8YW55PjtcclxuICBcclxuICBAVmlld0NoaWxkKCdzY3JvbGxDb250YWluZXInLCB7IHN0YXRpYzogdHJ1ZSB9KSBcclxuICBzY3JvbGxDb250YWluZXIhOiBFbGVtZW50UmVmPEhUTUxFbGVtZW50PjtcclxuICBcclxuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcclxuICBcclxuICByZWFkb25seSBzY3JvbGxUb3AgPSBzaWduYWwoMCk7XHJcbiAgcmVhZG9ubHkgdmlld3BvcnRIZWlnaHQgPSBzaWduYWwoMCk7XHJcbiAgXHJcbiAgcmVhZG9ubHkgZmxhdHRlbmVkTm9kZXMgPSBjb21wdXRlZCgoKSA9PiB7XHJcbiAgICByZXR1cm4gdGhpcy50cmVlTW9kZWwuZmxhdHRlbmVkTm9kZXMoKTtcclxuICB9KTtcclxuICBcclxuICByZWFkb25seSB0b3RhbEhlaWdodCA9IGNvbXB1dGVkKCgpID0+IHtcclxuICAgIGNvbnN0IG5vZGVzID0gdGhpcy5mbGF0dGVuZWROb2RlcygpO1xyXG4gICAgY29uc3Qgbm9kZUhlaWdodCA9IHRoaXMub3B0aW9ucy5ub2RlSGVpZ2h0IHx8IDIyO1xyXG4gICAgXHJcbiAgICBpZiAodHlwZW9mIG5vZGVIZWlnaHQgPT09ICdudW1iZXInKSB7XHJcbiAgICAgIHJldHVybiBub2Rlcy5sZW5ndGggKiBub2RlSGVpZ2h0O1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICByZXR1cm4gbm9kZXMucmVkdWNlKChzdW0sIG5vZGUpID0+IHN1bSArIG5vZGVIZWlnaHQobm9kZSksIDApO1xyXG4gIH0pO1xyXG4gIFxyXG4gIHJlYWRvbmx5IHZpc2libGVSYW5nZSA9IGNvbXB1dGVkKCgpID0+IHtcclxuICAgIGNvbnN0IHNjcm9sbFRvcCA9IHRoaXMuc2Nyb2xsVG9wKCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IHRoaXMudmlld3BvcnRIZWlnaHQoKTtcclxuICAgIGNvbnN0IG5vZGVzID0gdGhpcy5mbGF0dGVuZWROb2RlcygpO1xyXG4gICAgY29uc3Qgbm9kZUhlaWdodCA9IHRoaXMub3B0aW9ucy5ub2RlSGVpZ2h0IHx8IDIyO1xyXG4gICAgY29uc3QgYnVmZmVyQW1vdW50ID0gdGhpcy5vcHRpb25zLmJ1ZmZlckFtb3VudCB8fCA1O1xyXG4gICAgXHJcbiAgICBsZXQgc3RhcnRJbmRleCA9IDA7XHJcbiAgICBsZXQgYWNjdW11bGF0ZWRIZWlnaHQgPSAwO1xyXG4gICAgXHJcbiAgICAvLyBGaW5kIHN0YXJ0IGluZGV4XHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIGNvbnN0IGhlaWdodCA9IHR5cGVvZiBub2RlSGVpZ2h0ID09PSAnbnVtYmVyJyBcclxuICAgICAgICA/IG5vZGVIZWlnaHQgXHJcbiAgICAgICAgOiBub2RlSGVpZ2h0KG5vZGVzW2ldKTtcclxuICAgICAgXHJcbiAgICAgIGlmIChhY2N1bXVsYXRlZEhlaWdodCArIGhlaWdodCA+IHNjcm9sbFRvcCkge1xyXG4gICAgICAgIHN0YXJ0SW5kZXggPSBNYXRoLm1heCgwLCBpIC0gYnVmZmVyQW1vdW50KTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgfVxyXG4gICAgICBhY2N1bXVsYXRlZEhlaWdodCArPSBoZWlnaHQ7XHJcbiAgICB9XHJcbiAgICBcclxuICAgIC8vIEZpbmQgZW5kIGluZGV4XHJcbiAgICBsZXQgZW5kSW5kZXggPSBzdGFydEluZGV4O1xyXG4gICAgYWNjdW11bGF0ZWRIZWlnaHQgPSAwO1xyXG4gICAgXHJcbiAgICBmb3IgKGxldCBpID0gc3RhcnRJbmRleDsgaSA8IG5vZGVzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICAgIGNvbnN0IGhlaWdodCA9IHR5cGVvZiBub2RlSGVpZ2h0ID09PSAnbnVtYmVyJ1xyXG4gICAgICAgID8gbm9kZUhlaWdodFxyXG4gICAgICAgIDogbm9kZUhlaWdodChub2Rlc1tpXSk7XHJcbiAgICAgIFxyXG4gICAgICBhY2N1bXVsYXRlZEhlaWdodCArPSBoZWlnaHQ7XHJcbiAgICAgIFxyXG4gICAgICBpZiAoYWNjdW11bGF0ZWRIZWlnaHQgPiB2aWV3cG9ydEhlaWdodCArIChidWZmZXJBbW91bnQgKiAodHlwZW9mIG5vZGVIZWlnaHQgPT09ICdudW1iZXInID8gbm9kZUhlaWdodCA6IDIyKSkpIHtcclxuICAgICAgICBlbmRJbmRleCA9IGk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIFxyXG4gICAgaWYgKGVuZEluZGV4ID09PSBzdGFydEluZGV4KSB7XHJcbiAgICAgIGVuZEluZGV4ID0gbm9kZXMubGVuZ3RoO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICByZXR1cm4geyBzdGFydEluZGV4LCBlbmRJbmRleCB9O1xyXG4gIH0pO1xyXG4gIFxyXG4gIHJlYWRvbmx5IHZpc2libGVOb2RlcyA9IGNvbXB1dGVkKCgpID0+IHtcclxuICAgIGNvbnN0IHJhbmdlID0gdGhpcy52aXNpYmxlUmFuZ2UoKTtcclxuICAgIGNvbnN0IG5vZGVzID0gdGhpcy5mbGF0dGVuZWROb2RlcygpO1xyXG4gICAgcmV0dXJuIG5vZGVzLnNsaWNlKHJhbmdlLnN0YXJ0SW5kZXgsIHJhbmdlLmVuZEluZGV4KTtcclxuICB9KTtcclxuICBcclxuICByZWFkb25seSBwYWRkaW5nVG9wID0gY29tcHV0ZWQoKCkgPT4ge1xyXG4gICAgY29uc3QgcmFuZ2UgPSB0aGlzLnZpc2libGVSYW5nZSgpO1xyXG4gICAgY29uc3Qgbm9kZXMgPSB0aGlzLmZsYXR0ZW5lZE5vZGVzKCk7XHJcbiAgICBjb25zdCBub2RlSGVpZ2h0ID0gdGhpcy5vcHRpb25zLm5vZGVIZWlnaHQgfHwgMjI7XHJcbiAgICBcclxuICAgIGxldCBoZWlnaHQgPSAwO1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCByYW5nZS5zdGFydEluZGV4OyBpKyspIHtcclxuICAgICAgaGVpZ2h0ICs9IHR5cGVvZiBub2RlSGVpZ2h0ID09PSAnbnVtYmVyJyBcclxuICAgICAgICA/IG5vZGVIZWlnaHQgXHJcbiAgICAgICAgOiBub2RlSGVpZ2h0KG5vZGVzW2ldKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgcmV0dXJuIGhlaWdodDtcclxuICB9KTtcclxuICBcclxuICByZWFkb25seSBwYWRkaW5nQm90dG9tID0gY29tcHV0ZWQoKCkgPT4ge1xyXG4gICAgY29uc3QgcmFuZ2UgPSB0aGlzLnZpc2libGVSYW5nZSgpO1xyXG4gICAgY29uc3Qgbm9kZXMgPSB0aGlzLmZsYXR0ZW5lZE5vZGVzKCk7XHJcbiAgICBjb25zdCBub2RlSGVpZ2h0ID0gdGhpcy5vcHRpb25zLm5vZGVIZWlnaHQgfHwgMjI7XHJcbiAgICBjb25zdCB0b3RhbEhlaWdodCA9IHRoaXMudG90YWxIZWlnaHQoKTtcclxuICAgIFxyXG4gICAgbGV0IHZpc2libGVIZWlnaHQgPSB0aGlzLnBhZGRpbmdUb3AoKTtcclxuICAgIFxyXG4gICAgZm9yIChsZXQgaSA9IHJhbmdlLnN0YXJ0SW5kZXg7IGkgPCByYW5nZS5lbmRJbmRleDsgaSsrKSB7XHJcbiAgICAgIHZpc2libGVIZWlnaHQgKz0gdHlwZW9mIG5vZGVIZWlnaHQgPT09ICdudW1iZXInXHJcbiAgICAgICAgPyBub2RlSGVpZ2h0XHJcbiAgICAgICAgOiBub2RlSGVpZ2h0KG5vZGVzW2ldKTtcclxuICAgIH1cclxuICAgIFxyXG4gICAgcmV0dXJuIE1hdGgubWF4KDAsIHRvdGFsSGVpZ2h0IC0gdmlzaWJsZUhlaWdodCk7XHJcbiAgfSk7XHJcbiAgXHJcbiAgY29uc3RydWN0b3IoKSB7XHJcbiAgICAvLyBVcGRhdGUgdmlld3BvcnQgd2hlbiB0cmVlIGNoYW5nZXNcclxuICAgIGVmZmVjdCgoKSA9PiB7XHJcbiAgICAgIHRoaXMuZmxhdHRlbmVkTm9kZXMoKTsgLy8gU3Vic2NyaWJlIHRvIGNoYW5nZXNcclxuICAgICAgdGhpcy51cGRhdGVWaWV3cG9ydCgpO1xyXG4gICAgfSk7XHJcbiAgfVxyXG4gIFxyXG4gIG5nT25Jbml0KCk6IHZvaWQge1xyXG4gICAgdGhpcy5zZXR1cFNjcm9sbExpc3RlbmVyKCk7XHJcbiAgICB0aGlzLnVwZGF0ZVZpZXdwb3J0SGVpZ2h0KCk7XHJcbiAgfVxyXG4gIFxyXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xyXG4gICAgdGhpcy5kZXN0cm95JC5uZXh0KCk7XHJcbiAgICB0aGlzLmRlc3Ryb3kkLmNvbXBsZXRlKCk7XHJcbiAgfVxyXG4gIFxyXG4gIHByaXZhdGUgc2V0dXBTY3JvbGxMaXN0ZW5lcigpOiB2b2lkIHtcclxuICAgIGZyb21FdmVudCh0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LCAnc2Nyb2xsJylcclxuICAgICAgLnBpcGUoXHJcbiAgICAgICAgZGVib3VuY2VUaW1lKDEwKSxcclxuICAgICAgICB0YWtlVW50aWwodGhpcy5kZXN0cm95JClcclxuICAgICAgKVxyXG4gICAgICAuc3Vic2NyaWJlKCgpID0+IHtcclxuICAgICAgICB0aGlzLm9uU2Nyb2xsKCk7XHJcbiAgICAgIH0pO1xyXG4gIH1cclxuICBcclxuICBwcml2YXRlIHVwZGF0ZVZpZXdwb3J0SGVpZ2h0KCk6IHZvaWQge1xyXG4gICAgY29uc3QgaGVpZ2h0ID0gdGhpcy5zY3JvbGxDb250YWluZXIubmF0aXZlRWxlbWVudC5jbGllbnRIZWlnaHQ7XHJcbiAgICB0aGlzLnZpZXdwb3J0SGVpZ2h0LnNldChoZWlnaHQpO1xyXG4gIH1cclxuICBcclxuICBvblNjcm9sbCgpOiB2b2lkIHtcclxuICAgIGNvbnN0IHNjcm9sbFRvcCA9IHRoaXMuc2Nyb2xsQ29udGFpbmVyLm5hdGl2ZUVsZW1lbnQuc2Nyb2xsVG9wO1xyXG4gICAgdGhpcy5zY3JvbGxUb3Auc2V0KHNjcm9sbFRvcCk7XHJcbiAgfVxyXG4gIFxyXG4gIHByaXZhdGUgdXBkYXRlVmlld3BvcnQoKTogdm9pZCB7XHJcbiAgICAvLyBGb3JjZSByZWNhbGN1bGF0aW9uXHJcbiAgICB0aGlzLnNjcm9sbFRvcC5zZXQodGhpcy5zY3JvbGxDb250YWluZXIubmF0aXZlRWxlbWVudC5zY3JvbGxUb3ApO1xyXG4gIH1cclxuICBcclxuICBzY3JvbGxUb05vZGUobm9kZTogVHJlZU5vZGUpOiB2b2lkIHtcclxuICAgIGNvbnN0IG5vZGVzID0gdGhpcy5mbGF0dGVuZWROb2RlcygpO1xyXG4gICAgY29uc3QgaW5kZXggPSBub2Rlcy5maW5kSW5kZXgobiA9PiBuLmlkID09PSBub2RlLmlkKTtcclxuICAgIFxyXG4gICAgaWYgKGluZGV4ID09PSAtMSkgcmV0dXJuO1xyXG4gICAgXHJcbiAgICBjb25zdCBub2RlSGVpZ2h0ID0gdGhpcy5vcHRpb25zLm5vZGVIZWlnaHQgfHwgMjI7XHJcbiAgICBsZXQgdGFyZ2V0U2Nyb2xsVG9wID0gMDtcclxuICAgIFxyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBpbmRleDsgaSsrKSB7XHJcbiAgICAgIHRhcmdldFNjcm9sbFRvcCArPSB0eXBlb2Ygbm9kZUhlaWdodCA9PT0gJ251bWJlcidcclxuICAgICAgICA/IG5vZGVIZWlnaHRcclxuICAgICAgICA6IG5vZGVIZWlnaHQobm9kZXNbaV0pO1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICB0aGlzLnNjcm9sbENvbnRhaW5lci5uYXRpdmVFbGVtZW50LnNjcm9sbFRvcCA9IHRhcmdldFNjcm9sbFRvcDtcclxuICB9XHJcbn0iXX0=