mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(devtools): Use OnPush on all components (#62610)
The end goal is to move the devtools app to zoneless. PR Close #62610
This commit is contained in:
committed by
Andrew Kushnir
parent
a5b45ca2f6
commit
5aa69ff0a2
@@ -6,7 +6,15 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, computed, inject, input, output, signal} from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
inject,
|
||||
input,
|
||||
output,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {MatMenu, MatMenuItem, MatMenuTrigger} from '@angular/material/menu';
|
||||
import {MatSlideToggle} from '@angular/material/slide-toggle';
|
||||
@@ -54,6 +62,7 @@ type Tab = 'Components' | 'Profiler' | 'Router Tree' | 'Injector Tree';
|
||||
MatSlideToggle,
|
||||
],
|
||||
providers: [TabUpdate],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DevToolsTabsComponent {
|
||||
readonly isHydrationEnabled = input(false);
|
||||
|
||||
+2
@@ -16,6 +16,7 @@ import {
|
||||
output,
|
||||
signal,
|
||||
viewChild,
|
||||
ChangeDetectionStrategy,
|
||||
} from '@angular/core';
|
||||
import {
|
||||
ComponentExplorerView,
|
||||
@@ -98,6 +99,7 @@ const sameDirectives = (a: IndexedNode, b: IndexedNode) => {
|
||||
SignalsTabComponent,
|
||||
ResponsiveSplitDirective,
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DirectiveExplorerComponent {
|
||||
readonly showCommentNodes = input(false);
|
||||
|
||||
+2
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
effect,
|
||||
@@ -25,6 +26,7 @@ import {MatIcon} from '@angular/material/icon';
|
||||
templateUrl: './breadcrumbs.component.html',
|
||||
styleUrls: ['./breadcrumbs.component.scss'],
|
||||
imports: [MatIcon],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class BreadcrumbsComponent {
|
||||
readonly parents = input.required<FlatNode[]>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, input, output} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, input, output} from '@angular/core';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
|
||||
export type FilterMatch = {
|
||||
@@ -44,6 +44,7 @@ const genericSearchGenerator: FilterFnGenerator = (filter: string) => {
|
||||
templateUrl: './filter.component.html',
|
||||
styleUrls: ['./filter.component.scss'],
|
||||
imports: [MatIcon],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FilterComponent {
|
||||
readonly filter = output<FilterFn>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, computed, input} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, computed, input} from '@angular/core';
|
||||
import {MatToolbar} from '@angular/material/toolbar';
|
||||
import {DeferInfo} from '../../../../../../../protocol';
|
||||
|
||||
@@ -15,6 +15,7 @@ import {DeferInfo} from '../../../../../../../protocol';
|
||||
selector: 'ng-defer-view',
|
||||
styleUrls: ['./defer-view.component.scss'],
|
||||
imports: [MatToolbar],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DeferViewComponent {
|
||||
readonly defer = input.required<NonNullable<DeferInfo>>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, input, output} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, input, output} from '@angular/core';
|
||||
import {DirectivePosition} from '../../../../../../protocol';
|
||||
|
||||
import {IndexedNode} from '../directive-forest/index-forest';
|
||||
@@ -20,6 +20,7 @@ import {DeferViewComponent} from './defer-view/defer-view.component';
|
||||
templateUrl: './property-tab.component.html',
|
||||
styleUrls: ['./property-tab.component.scss'],
|
||||
imports: [PropertyTabHeaderComponent, PropertyTabBodyComponent, DeferViewComponent],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PropertyTabComponent {
|
||||
readonly currentSelectedElement = input.required<IndexedNode | null>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, input} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, input} from '@angular/core';
|
||||
import {SerializedInjectedService} from '../../../../../../../protocol';
|
||||
import {ResolutionPathComponent} from './resolution-path/resolution-path.component';
|
||||
import {MatTooltip} from '@angular/material/tooltip';
|
||||
@@ -17,6 +17,7 @@ import {MatExpansionModule} from '@angular/material/expansion';
|
||||
templateUrl: './dependency-viewer.component.html',
|
||||
styleUrl: './dependency-viewer.component.scss',
|
||||
imports: [MatExpansionModule, MatTooltip, ResolutionPathComponent],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DependencyViewerComponent {
|
||||
readonly dependency = input.required<SerializedInjectedService>();
|
||||
|
||||
+2
@@ -15,6 +15,7 @@ import {
|
||||
output,
|
||||
signal,
|
||||
viewChild,
|
||||
ChangeDetectionStrategy,
|
||||
} from '@angular/core';
|
||||
import {FormsModule} from '@angular/forms';
|
||||
import {ContainerType} from '../../../../../../../protocol';
|
||||
@@ -40,6 +41,7 @@ const parseValue = (value: EditorResult): EditorResult => {
|
||||
selector: 'ng-property-editor',
|
||||
styleUrls: ['./property-editor.component.scss'],
|
||||
imports: [FormsModule],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PropertyEditorComponent {
|
||||
readonly key = input.required<string>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, computed, input, output} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, computed, input, output} from '@angular/core';
|
||||
import {PropType} from '../../../../../../../protocol';
|
||||
|
||||
import {FlatNode} from '../../property-resolver/element-property-resolver';
|
||||
@@ -15,6 +15,7 @@ import {FlatNode} from '../../property-resolver/element-property-resolver';
|
||||
selector: 'ng-property-preview',
|
||||
templateUrl: './property-preview.component.html',
|
||||
styleUrls: ['./property-preview.component.scss'],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PropertyPreviewComponent {
|
||||
readonly node = input.required<FlatNode>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, computed, input, output} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, computed, input, output} from '@angular/core';
|
||||
import {DirectivePosition} from '../../../../../../../protocol';
|
||||
|
||||
import {IndexedNode} from '../../directive-forest/index-forest';
|
||||
@@ -18,6 +18,7 @@ import {PropertyViewComponent} from './property-view.component';
|
||||
selector: 'ng-property-tab-body',
|
||||
styleUrls: ['./property-tab-body.component.scss'],
|
||||
imports: [PropertyViewComponent],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PropertyTabBodyComponent {
|
||||
readonly currentSelectedElement = input.required<IndexedNode>();
|
||||
|
||||
+3
@@ -8,6 +8,7 @@
|
||||
|
||||
import {CdkDragDrop, moveItemInArray, CdkDropList, CdkDrag} from '@angular/cdk/drag-drop';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ɵFramework as Framework,
|
||||
computed,
|
||||
@@ -42,6 +43,7 @@ import {DependencyViewerComponent} from './dependency-viewer.component';
|
||||
CdkDrag,
|
||||
PropertyViewTreeComponent,
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PropertyViewBodyComponent {
|
||||
readonly controller = input.required<DirectivePropertyResolver>();
|
||||
@@ -134,6 +136,7 @@ export class PropertyViewBodyComponent {
|
||||
`,
|
||||
],
|
||||
imports: [DependencyViewerComponent],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class InjectedServicesComponent {
|
||||
readonly controller = input.required<DirectivePropertyResolver>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, computed, inject, input, output} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, computed, inject, input, output} from '@angular/core';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {MatTooltip} from '@angular/material/tooltip';
|
||||
import {MatToolbar} from '@angular/material/toolbar';
|
||||
@@ -18,6 +18,7 @@ import {FrameManager} from '../../../../application-services/frame_manager';
|
||||
templateUrl: './property-view-header.component.html',
|
||||
styleUrls: ['./property-view-header.component.scss'],
|
||||
imports: [MatToolbar, MatTooltip, MatIcon],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PropertyViewHeaderComponent {
|
||||
readonly directive = input.required<string>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, computed, inject, input, output} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, computed, inject, input, output} from '@angular/core';
|
||||
import {DirectivePosition} from '../../../../../../../protocol';
|
||||
|
||||
import {ElementPropertyResolver, FlatNode} from '../../property-resolver/element-property-resolver';
|
||||
@@ -18,6 +18,7 @@ import {PropertyViewHeaderComponent} from './property-view-header.component';
|
||||
templateUrl: './property-view.component.html',
|
||||
styleUrls: ['./property-view.component.scss'],
|
||||
imports: [PropertyViewHeaderComponent, PropertyViewBodyComponent],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class PropertyViewComponent {
|
||||
readonly directive = input.required<{name: string}>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, computed, input} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, computed, input} from '@angular/core';
|
||||
import {SerializedInjector} from '../../../../../../../../protocol';
|
||||
|
||||
export const NODE_TYPE_CLASS_MAP: {[key in SerializedInjector['type']]: string} = {
|
||||
@@ -21,6 +21,7 @@ export const NODE_TYPE_CLASS_MAP: {[key in SerializedInjector['type']]: string}
|
||||
selector: 'ng-resolution-path',
|
||||
templateUrl: './resolution-path.component.html',
|
||||
styleUrl: './resolution-path.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ResolutionPathComponent {
|
||||
readonly path = input<SerializedInjector[]>([]);
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, input} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, input} from '@angular/core';
|
||||
import {FlatTreeControl} from '@angular/cdk/tree';
|
||||
import {MatTree, MatTreeNode, MatTreeNodeDef, MatTreeNodePadding} from '@angular/material/tree';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
@@ -30,6 +30,7 @@ export interface Property {
|
||||
templateUrl: './signals-value-tree.component.html',
|
||||
imports: [MatTree, MatTreeNode, MatTreeNodeDef, MatTreeNodePadding, MatIcon],
|
||||
styleUrl: './signals-value-tree.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class SignalsValueTreeComponent {
|
||||
readonly treeControl = input.required<FlatTreeControl<FlatNode>>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, computed, inject, input, signal} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, computed, inject, input, signal} from '@angular/core';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {MatTableModule} from '@angular/material/table';
|
||||
import {MatTooltip} from '@angular/material/tooltip';
|
||||
@@ -23,6 +23,7 @@ import {ButtonComponent} from '../../../shared/button/button.component';
|
||||
templateUrl: './injector-providers.component.html',
|
||||
styleUrl: './injector-providers.component.scss',
|
||||
imports: [MatTableModule, MatIcon, MatTooltip, ButtonComponent],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class InjectorProvidersComponent {
|
||||
readonly injector = input.required<SerializedInjector>();
|
||||
|
||||
+2
@@ -8,6 +8,7 @@
|
||||
|
||||
import {
|
||||
afterRenderEffect,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
ElementRef,
|
||||
@@ -73,6 +74,7 @@ const HIERARCHY_HOR_SIZE = 50;
|
||||
host: {
|
||||
'[hidden]': 'hidden()',
|
||||
},
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class InjectorTreeComponent {
|
||||
private readonly environmentTree = viewChild<TreeVisualizerHostComponent>('environmentTree');
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, inject, signal} from '@angular/core';
|
||||
import {ChangeDetectionStrategy, Component, inject, signal} from '@angular/core';
|
||||
import {MatDialog} from '@angular/material/dialog';
|
||||
import {MatIcon} from '@angular/material/icon';
|
||||
import {MatTooltip} from '@angular/material/tooltip';
|
||||
@@ -28,6 +28,7 @@ const PROFILER_VERSION = 1;
|
||||
templateUrl: './profiler.component.html',
|
||||
styleUrls: ['./profiler.component.scss'],
|
||||
imports: [MatTooltip, MatIcon, RecordingTimelineComponent, ButtonComponent],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class ProfilerComponent {
|
||||
readonly state = signal<State>('idle');
|
||||
|
||||
+2
@@ -13,6 +13,7 @@ import {
|
||||
} from '@angular/cdk/scrolling';
|
||||
import {
|
||||
afterRenderEffect,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
ElementRef,
|
||||
@@ -70,6 +71,7 @@ function framesBoundSignal<T>(source: Signal<ProfilerFrame[]>, defaultValue: T)
|
||||
ButtonComponent,
|
||||
DecimalPipe,
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class FrameSelectorComponent {
|
||||
private readonly tabUpdate = inject(TabUpdate);
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component} from '@angular/core';
|
||||
import {Component, ChangeDetectionStrategy} from '@angular/core';
|
||||
import {MatProgressBar} from '@angular/material/progress-bar';
|
||||
|
||||
@Component({
|
||||
@@ -14,5 +14,6 @@ import {MatProgressBar} from '@angular/material/progress-bar';
|
||||
templateUrl: './recording-dialog.component.html',
|
||||
styleUrls: ['./recording-dialog.component.scss'],
|
||||
imports: [MatProgressBar],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class RecordingDialogComponent {}
|
||||
|
||||
+11
-1
@@ -6,7 +6,16 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, computed, effect, input, linkedSignal, output, signal} from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
effect,
|
||||
input,
|
||||
linkedSignal,
|
||||
output,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import {ProfilerFrame} from '../../../../../../protocol';
|
||||
import {Observable} from 'rxjs';
|
||||
|
||||
@@ -32,6 +41,7 @@ import {estimateFrameRate} from './shared/estimate-frame-rate';
|
||||
RecordingVisualizerComponent,
|
||||
VisualizerControlsComponent,
|
||||
],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class RecordingTimelineComponent {
|
||||
readonly stream = input.required<Observable<ProfilerFrame[]>>();
|
||||
|
||||
+2
-1
@@ -6,7 +6,7 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, computed, input, output} from '@angular/core';
|
||||
import {Component, computed, input, output, ChangeDetectionStrategy} from '@angular/core';
|
||||
import {ButtonComponent} from '../../shared/button/button.component';
|
||||
|
||||
export type RowType = 'text' | 'chip' | 'flag' | 'list';
|
||||
@@ -16,6 +16,7 @@ export type RowType = 'text' | 'chip' | 'flag' | 'list';
|
||||
templateUrl: './route-details-row.component.html',
|
||||
styleUrls: ['./route-details-row.component.scss'],
|
||||
imports: [ButtonComponent],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class RouteDetailsRowComponent {
|
||||
readonly label = input.required<string>();
|
||||
|
||||
+13
-4
@@ -6,8 +6,17 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {CommonModule} from '@angular/common';
|
||||
import {afterNextRender, Component, effect, inject, input, signal, viewChild} from '@angular/core';
|
||||
import {JsonPipe} from '@angular/common';
|
||||
import {
|
||||
afterNextRender,
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
effect,
|
||||
inject,
|
||||
input,
|
||||
signal,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
import {TreeVisualizerHostComponent} from '../../shared/tree-visualizer-host/tree-visualizer-host.component';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import {ApplicationOperations} from '../../application-operations/index';
|
||||
@@ -33,7 +42,7 @@ const DEFAULT_FILTER = /.^/;
|
||||
templateUrl: './router-tree.component.html',
|
||||
styleUrls: ['./router-tree.component.scss'],
|
||||
imports: [
|
||||
CommonModule,
|
||||
JsonPipe,
|
||||
TreeVisualizerHostComponent,
|
||||
SplitComponent,
|
||||
SplitAreaDirective,
|
||||
@@ -41,7 +50,7 @@ const DEFAULT_FILTER = /.^/;
|
||||
RouteDetailsRowComponent,
|
||||
ButtonComponent,
|
||||
],
|
||||
standalone: true,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class RouterTreeComponent {
|
||||
private routerTree = viewChild.required<TreeVisualizerHostComponent>('routerTree');
|
||||
|
||||
@@ -7,7 +7,15 @@
|
||||
*/
|
||||
|
||||
import {animate, style, transition, trigger} from '@angular/animations';
|
||||
import {Component, computed, inject, OnDestroy, OnInit, signal} from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
computed,
|
||||
inject,
|
||||
OnDestroy,
|
||||
OnInit,
|
||||
signal,
|
||||
} from '@angular/core';
|
||||
import {Events, MessageBus, SupportedApis} from '../../../protocol';
|
||||
import {interval} from 'rxjs';
|
||||
|
||||
@@ -55,6 +63,7 @@ const LAST_SUPPORTED_VERSION = 9;
|
||||
],
|
||||
imports: [DevToolsTabsComponent, MatTooltip, MatProgressSpinnerModule, MatTooltipModule],
|
||||
providers: [WINDOW_PROVIDER, ThemeService],
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class DevToolsComponent implements OnDestroy {
|
||||
readonly AngularStatus = AngularStatus;
|
||||
|
||||
+9
-1
@@ -6,7 +6,14 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {Component, ElementRef, input, signal, viewChild} from '@angular/core';
|
||||
import {
|
||||
ChangeDetectionStrategy,
|
||||
Component,
|
||||
ElementRef,
|
||||
input,
|
||||
signal,
|
||||
viewChild,
|
||||
} from '@angular/core';
|
||||
|
||||
let instanceIdx = 0;
|
||||
|
||||
@@ -25,6 +32,7 @@ let instanceIdx = 0;
|
||||
</svg>
|
||||
`,
|
||||
styleUrl: 'tree-visualizer-host.component.scss',
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
})
|
||||
export class TreeVisualizerHostComponent {
|
||||
readonly container = viewChild.required<ElementRef>('container');
|
||||
|
||||
Reference in New Issue
Block a user