refactor(devtools): use responsive split for the components tab by hawkgs · Pull Request #70563 · angular/angular · GitHub
Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@

import {
Component,
afterRenderEffect,
ElementRef,
inject,
input,
output,
Expand Down Expand Up @@ -114,14 +112,9 @@ export class DirectiveExplorerComponent {
readonly toggleInspector = output<void>();

readonly directiveForest = viewChild.required(DirectiveForestComponent);
readonly splitElementRef = viewChild.required(SplitComponent, {read: ElementRef});
readonly directiveForestSplitArea = viewChild.required('directiveForestSplitArea', {
read: ElementRef,
});

readonly currentSelectedElement = signal<IndexedNode | null>(null);
readonly forest = signal<DevToolsNode[]>([]);
readonly splitDirection = signal<'horizontal' | 'vertical'>('horizontal');
readonly parents = signal<FlatNode[] | null>(null);

readonly signalsOpen = signal(false);
Expand All @@ -141,9 +134,17 @@ export class DirectiveExplorerComponent {

protected readonly externallySelectedSignalNodeId = signal<{id: string} | null>(null);

protected readonly responsiveSplitConfig: ResponsiveSplitConfig = {
// Responsible for spliting behavior of the explorer and the props pane.
protected readonly tabSplitConfig: ResponsiveSplitConfig = {
defaultDirection: 'horizontal',
widthBreakpoint: '<500px',
breakpointDirection: 'vertical',
};

// Responsive for spliting behavior of the forest and the signal graph pane.
protected readonly forestSplitConfig: ResponsiveSplitConfig = {
defaultDirection: 'vertical',
aspectRatioBreakpoint: 1.5,
aspectRatioBreakpoint: '>=1.5',
breakpointDirection: 'horizontal',
};

Expand All @@ -165,27 +166,6 @@ export class DirectiveExplorerComponent {
private readonly currentElementPos = computed(() => this.currentSelectedElement()?.position);

constructor() {
afterRenderEffect((cleanup) => {
const splitElement = this.splitElementRef().nativeElement;
const directiveForestSplitArea = this.directiveForestSplitArea().nativeElement;
const resizeObserver = new ResizeObserver((entries) => {
this.refreshHydrationNodeHighlightsIfNeeded();

const resizedEntry = entries[0];
if (resizedEntry.target === splitElement) {
this.splitDirection.set(
resizedEntry.contentRect.width <= 500 ? 'vertical' : 'horizontal',
);
}
});

resizeObserver.observe(splitElement);
resizeObserver.observe(directiveForestSplitArea);
cleanup(() => {
resizeObserver.disconnect();
});
});

this.subscribeToBackendEvents();
this.refresh();
this.signalGraph.listen(this.currentElementPos);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ export class InjectorTreeComponent {

protected readonly responsiveSplitConfig: ResponsiveSplitConfig = {
defaultDirection: 'vertical',
aspectRatioBreakpoint: 1.5,
aspectRatioBreakpoint: '>=1.5',
breakpointDirection: 'horizontal',
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,20 @@ class TestComponent {
readonly split = viewChild.required(SplitComponent);
readonly host = viewChild.required<ElementRef>('host');

readonly config: ResponsiveSplitConfig = {
defaultDirection: 'horizontal',
aspectRatioBreakpoint: 1.5,
breakpointDirection: 'vertical',
};
config!: ResponsiveSplitConfig;
}

async function initTestComponent(
config: ResponsiveSplitConfig,
width: number,
height: number,
): Promise<{host: DebugElement; split: SplitComponent}> {
TestBed.resetTestingModule();
TestBed.configureTestingModule({
providers: [{provide: WINDOW, useValue: {...window, ResizeObserver: ResizeObserverMockImpl}}],
});
const fixture = TestBed.createComponent(TestComponent);
fixture.componentInstance.config = config;
await fixture.whenStable();

const host = fixture.debugElement.query(By.css('as-split'));
Expand All @@ -110,27 +109,97 @@ describe('responsive-split', () => {
jasmine.clock().install();
});

it('should use horizontal direction (ratio == 1)', async () => {
const {split} = await initTestComponent(200, 200);
describe('aspectRatioBreakpoint', () => {
const config: ResponsiveSplitConfig = {
defaultDirection: 'horizontal',
aspectRatioBreakpoint: '>=1.5',
breakpointDirection: 'vertical',
};

expect(split.direction()).toEqual('horizontal');
});
it('should use horizontal direction (ratio == 1)', async () => {
const {split} = await initTestComponent(config, 200, 200);

it('should use horizontal direction (ratio == 1.49)', async () => {
const {split} = await initTestComponent(299, 200);
expect(split.direction()).toEqual('horizontal');
});

expect(split.direction()).toEqual('horizontal');
});
it('should use horizontal direction (ratio == 1.49)', async () => {
const {split} = await initTestComponent(config, 299, 200);

expect(split.direction()).toEqual('horizontal');
});

it('should use vertical direction (ratio == 1.5)', async () => {
const {split} = await initTestComponent(350, 200);
it('should use vertical direction (ratio == 1.5)', async () => {
const {split} = await initTestComponent(config, 350, 200);

expect(split.direction()).toEqual('vertical');
expect(split.direction()).toEqual('vertical');
});

it('should use vertical direction (ratio == 2)', async () => {
const {split} = await initTestComponent(config, 400, 200);

expect(split.direction()).toEqual('vertical');
});
});

it('should use vertical direction (ratio == 2)', async () => {
const {split} = await initTestComponent(400, 200);
describe('widthBreakpoint', () => {
const config: ResponsiveSplitConfig = {
defaultDirection: 'horizontal',
widthBreakpoint: '<500px',
breakpointDirection: 'vertical',
};

it('should use horizontal direction (width == 600)', async () => {
const {split} = await initTestComponent(config, 600, 200);

expect(split.direction()).toEqual('horizontal');
});

it('should use horizontal direction (width == 500)', async () => {
const {split} = await initTestComponent(config, 500, 200);

expect(split.direction()).toEqual('horizontal');
});

it('should use vertical direction (width == 499)', async () => {
const {split} = await initTestComponent(config, 499, 200);

expect(split.direction()).toEqual('vertical');
});

it('should use vertical direction (width == 300)', async () => {
const {split} = await initTestComponent(config, 300, 200);

expect(split.direction()).toEqual('vertical');
});
});

expect(split.direction()).toEqual('vertical');
describe('Breakpoint operators', () => {
it('should support the `>` operator (aspect ratio)', async () => {
const config: ResponsiveSplitConfig = {
defaultDirection: 'horizontal',
aspectRatioBreakpoint: '>2',
breakpointDirection: 'vertical',
};

const atBoundary = await initTestComponent(config, 400, 200); // ratio == 2
expect(atBoundary.split.direction()).toEqual('horizontal');

const pastBoundary = await initTestComponent(config, 420, 200); // ratio == 2.1
expect(pastBoundary.split.direction()).toEqual('vertical');
});

it('should support the `<=` operator (width)', async () => {
const config: ResponsiveSplitConfig = {
defaultDirection: 'horizontal',
widthBreakpoint: '<=300',
breakpointDirection: 'vertical',
};

const atBoundary = await initTestComponent(config, 300, 200);
expect(atBoundary.split.direction()).toEqual('vertical');

const pastBoundary = await initTestComponent(config, 301, 200);
expect(pastBoundary.split.direction()).toEqual('horizontal');
});
});
});