diff --git a/apps/components-testing-app/src/app/components/dimension/bounding-client-rect-page.component.html b/apps/components-testing-app/src/app/components/dimension/bounding-client-rect-page.component.html new file mode 100644 index 00000000..d5c20e91 --- /dev/null +++ b/apps/components-testing-app/src/app/components/dimension/bounding-client-rect-page.component.html @@ -0,0 +1,20 @@ +
+ + diff --git a/apps/components-testing-app/src/app/components/dimension/bounding-client-rect-page.component.scss b/apps/components-testing-app/src/app/components/dimension/bounding-client-rect-page.component.scss new file mode 100644 index 00000000..edee87a0 --- /dev/null +++ b/apps/components-testing-app/src/app/components/dimension/bounding-client-rect-page.component.scss @@ -0,0 +1,30 @@ +:host { + > div.testee { + position: absolute; + background-color: blue; + } + + > aside { + position: fixed; + top: 0; + right: 0; + display: flex; + flex-direction: column; + gap: 2em; + padding: 1em; + + > section { + display: grid; + grid-template-columns: auto 1fr; + gap: .25em 1em; + + > header { + font-weight: bold; + } + + > header, > button.apply { + grid-column: 1/-1; + } + } + } +} diff --git a/apps/components-testing-app/src/app/components/dimension/bounding-client-rect-page.component.ts b/apps/components-testing-app/src/app/components/dimension/bounding-client-rect-page.component.ts new file mode 100644 index 00000000..1a138b95 --- /dev/null +++ b/apps/components-testing-app/src/app/components/dimension/bounding-client-rect-page.component.ts @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2018-2024 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import {Component, DoCheck, effect, ElementRef, inject, NgZone, OnInit, signal, viewChild} from '@angular/core'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {boundingClientRect} from '@scion/components/dimension'; + +@Component({ + selector: 'app-bounding-client-rect-page', + templateUrl: './dimension-page.component.html', + styleUrl: './bounding-client-rect-page.component.scss', + imports: [ + FormsModule, + ReactiveFormsModule, + ], +}) +export class BoundingClientRectPageComponent implements OnInit, DoCheck { + + private _testee = viewChild.required>('testee'); + private _boundingBox = boundingClientRect(this._testee); + private applyButton = viewChild('apply_button', {read: ElementRef}); + private zone = inject(NgZone); + + protected properties = { + x: signal('0px'), + y: signal('0px'), + width: signal('100px'), + height: signal('100px'), + }; + + protected testeeBoundingBox = { + x: signal(undefined), + y: signal(undefined), + width: signal(undefined), + height: signal(undefined), + }; + + constructor() { + effect(() => { + const boundingBox = this._boundingBox(); + this.testeeBoundingBox.x.set(boundingBox.x); + this.testeeBoundingBox.y.set(boundingBox.y); + this.testeeBoundingBox.width.set(boundingBox.width); + this.testeeBoundingBox.height.set(boundingBox.height); + }); + } + + public ngOnInit(): void { + this.applyProperties(); + this.zone.runOutsideAngular(() => { + this.applyButton()!.nativeElement.addEventListener('click', () => this.applyProperties()); + }); + } + + public ngDoCheck(): void { + console.log('[BoundingClientRectPageComponent] Angular change detection cycle'); + } + + public applyProperties(): void { + this._testee().nativeElement.style.left = this.properties.x(); + this._testee().nativeElement.style.top = this.properties.y(); + this._testee().nativeElement.style.width = this.properties.width(); + this._testee().nativeElement.style.height = this.properties.height(); + } +} diff --git a/apps/components-testing-app/src/app/components/dimension/dimension-page.component.html b/apps/components-testing-app/src/app/components/dimension/dimension-page.component.html new file mode 100644 index 00000000..d5c20e91 --- /dev/null +++ b/apps/components-testing-app/src/app/components/dimension/dimension-page.component.html @@ -0,0 +1,20 @@ +
+ + diff --git a/apps/components-testing-app/src/app/components/dimension/dimension-page.component.scss b/apps/components-testing-app/src/app/components/dimension/dimension-page.component.scss new file mode 100644 index 00000000..edee87a0 --- /dev/null +++ b/apps/components-testing-app/src/app/components/dimension/dimension-page.component.scss @@ -0,0 +1,30 @@ +:host { + > div.testee { + position: absolute; + background-color: blue; + } + + > aside { + position: fixed; + top: 0; + right: 0; + display: flex; + flex-direction: column; + gap: 2em; + padding: 1em; + + > section { + display: grid; + grid-template-columns: auto 1fr; + gap: .25em 1em; + + > header { + font-weight: bold; + } + + > header, > button.apply { + grid-column: 1/-1; + } + } + } +} diff --git a/apps/components-testing-app/src/app/components/dimension/dimension-page.component.ts b/apps/components-testing-app/src/app/components/dimension/dimension-page.component.ts new file mode 100644 index 00000000..dc84bcdc --- /dev/null +++ b/apps/components-testing-app/src/app/components/dimension/dimension-page.component.ts @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2018-2024 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import {ChangeDetectionStrategy, Component, DoCheck, effect, ElementRef, inject, NgZone, OnInit, signal, viewChild} from '@angular/core'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; +import {boundingClientRect} from '@scion/components/dimension'; + +@Component({ + selector: 'app-dimension-page', + templateUrl: './dimension-page.component.html', + styleUrl: './dimension-page.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + FormsModule, + ReactiveFormsModule, + ], +}) +export class DimensionPageComponent implements OnInit, DoCheck { + + private _testee = viewChild.required>('testee'); + private _boundingBox = boundingClientRect(this._testee); + private applyButton = viewChild('apply_button', {read: ElementRef}); + + protected properties = { + x: signal('0px'), + y: signal('0px'), + width: signal('100px'), + height: signal('100px'), + }; + + protected testeeBoundingBox = { + x: signal(undefined), + y: signal(undefined), + width: signal(undefined), + height: signal(undefined), + }; + private zone = inject(NgZone); + + constructor() { + effect(() => { + const boundingBox = this._boundingBox(); + this.testeeBoundingBox.x.set(boundingBox.x); + this.testeeBoundingBox.y.set(boundingBox.y); + this.testeeBoundingBox.width.set(boundingBox.width); + this.testeeBoundingBox.height.set(boundingBox.height); + }); + } + + public ngOnInit(): void { + this.applyProperties(); + this.zone.runOutsideAngular(() => { + this.applyButton()!.nativeElement.addEventListener('click', () => this.applyProperties()); + }); + } + + public ngDoCheck(): void { + console.log('[BoundingClientRectPageComponent] Angular change detection cycle'); + } + + public applyProperties(): void { + this._testee().nativeElement.style.left = this.properties.x(); + this._testee().nativeElement.style.top = this.properties.y(); + this._testee().nativeElement.style.width = this.properties.width(); + this._testee().nativeElement.style.height = this.properties.height(); + } +} diff --git a/apps/components-testing-app/src/app/components/dimension/routes.ts b/apps/components-testing-app/src/app/components/dimension/routes.ts new file mode 100644 index 00000000..379e5f68 --- /dev/null +++ b/apps/components-testing-app/src/app/components/dimension/routes.ts @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2018-2022 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import {Routes} from '@angular/router'; +import {BoundingClientRectPageComponent} from './bounding-client-rect-page.component'; + +export default [ + {path: 'bounding-client-rect', component: BoundingClientRectPageComponent}, +] satisfies Routes; diff --git a/apps/components-testing-app/src/app/components/routes.ts b/apps/components-testing-app/src/app/components/routes.ts index 8caf2cb1..f952ea1d 100644 --- a/apps/components-testing-app/src/app/components/routes.ts +++ b/apps/components-testing-app/src/app/components/routes.ts @@ -19,4 +19,8 @@ export default [ path: 'sci-sashbox', loadChildren: () => import('./sci-sashbox/routes'), }, + { + path: 'dimension', + loadChildren: () => import('./dimension/routes'), + }, ] satisfies Routes; diff --git a/projects/scion/components.e2e/src/components/dimension/bounding-client-rect-page.e2e-spec.ts b/projects/scion/components.e2e/src/components/dimension/bounding-client-rect-page.e2e-spec.ts new file mode 100644 index 00000000..daa34589 --- /dev/null +++ b/projects/scion/components.e2e/src/components/dimension/bounding-client-rect-page.e2e-spec.ts @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2018-2024 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import {test} from '../../fixtures'; +import {waitUntilStable} from '../../helper/testing.utils'; +import {expect} from '@playwright/test'; +import {BoundingClientRectPagePO} from './bounding-client-rect-page.po'; + +test.describe('@scion/components/dimension/boundingClientRect', () => { + + test.only('should not run Angular change detection when changing element size', async ({page, consoleLogs}) => { + const testPage = new BoundingClientRectPagePO(page); + await testPage.navigate(); + + // Set element size to 200x200 pixel. + await testPage.enterProperties({x: '0', y: '0', width: '200px', height: '200px'}); + + // Clear console logs. + await waitUntilStable(() => consoleLogs.get().length); + consoleLogs.clear(); + + // Apply properties. + await testPage.applyProperties(); + await expect(testPage.testeeBoundingBox.width).toHaveText('200'); + + // Expect Angular not to run change detection when changing element size. + await waitUntilStable(() => consoleLogs.get().length); + await expect.poll(() => consoleLogs.get({message: '[BoundingClientRectPageComponent] Angular change detection cycle'})).toHaveLength(0); + }); +}); diff --git a/projects/scion/components.e2e/src/components/dimension/bounding-client-rect-page.po.ts b/projects/scion/components.e2e/src/components/dimension/bounding-client-rect-page.po.ts new file mode 100644 index 00000000..793f3de7 --- /dev/null +++ b/projects/scion/components.e2e/src/components/dimension/bounding-client-rect-page.po.ts @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2018-2022 Swiss Federal Railways + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + */ + +import {Locator, Page} from '@playwright/test'; + +const PATH = '/#/components/dimension/bounding-client-rect'; + +export class BoundingClientRectPagePO { + + private readonly _locator: Locator; + + public readonly testeeBoundingBox: { + x: Locator; + y: Locator; + width: Locator; + height: Locator; + }; + + constructor(private _page: Page) { + this._locator = _page.locator('app-bounding-client-rect-page'); + this.testeeBoundingBox = { + x: this._locator.locator('section.e2e-testee-bounding-box span.e2e-x'), + y: this._locator.locator('section.e2e-testee-bounding-box span.e2e-y'), + width: this._locator.locator('section.e2e-testee-bounding-box span.e2e-width'), + height: this._locator.locator('section.e2e-testee-bounding-box span.e2e-height'), + }; + } + + public async navigate(): Promise { + await this._page.goto(PATH); + } + + public async enterProperties(properties: {x: string; y: string; width: string; height: string;}): Promise { + await this._locator.locator('section.e2e-properties input.e2e-x').fill(properties.x); + await this._locator.locator('section.e2e-properties input.e2e-y').fill(properties.y); + await this._locator.locator('section.e2e-properties input.e2e-width').fill(properties.width); + await this._locator.locator('section.e2e-properties input.e2e-height').fill(properties.height); + await this._locator.press('Tab'); + } + + public async applyProperties(): Promise { + await this._locator.locator('section.e2e-properties button.e2e-apply').click(); + } + + public async resizeWindow(viewportSize: {width?: number; height?: number}): Promise { + await this._page.setViewportSize({ + width: viewportSize.width ?? this._page.viewportSize()!.width, + height: viewportSize.height ?? this._page.viewportSize()!.height, + }); + } +} diff --git a/projects/scion/components.e2e/src/components/sci-viewport/overlap/viewport-overlap.e2e-spec.ts b/projects/scion/components.e2e/src/components/sci-viewport/overlap/viewport-overlap.e2e-spec.ts index f6466e01..a5c2a34a 100644 --- a/projects/scion/components.e2e/src/components/sci-viewport/overlap/viewport-overlap.e2e-spec.ts +++ b/projects/scion/components.e2e/src/components/sci-viewport/overlap/viewport-overlap.e2e-spec.ts @@ -19,6 +19,6 @@ test.describe('sci-viewport/overlap', () => { await overlapPO.navigate(); await overlapPO.clickAdjacentElement(); - await expect(await consoleLogs.get({filter: /ViewportOverlapPageComponent/})).toHaveLength(1); + await expect(await consoleLogs.get({message: /ViewportOverlapPageComponent/})).toHaveLength(1); }); }); diff --git a/projects/scion/components.e2e/src/console-logs.ts b/projects/scion/components.e2e/src/console-logs.ts index 23be4bb7..a04cda66 100644 --- a/projects/scion/components.e2e/src/console-logs.ts +++ b/projects/scion/components.e2e/src/console-logs.ts @@ -9,34 +9,31 @@ */ import {ConsoleMessage, Page} from '@playwright/test'; -import {BehaviorSubject, debounceTime, firstValueFrom} from 'rxjs'; /** * Collects messages logged to the browser console. */ export class ConsoleLogs { - private _messages$ = new BehaviorSubject([]); + private _messages = new Array(); constructor(private _page: Page) { this._page.on('console', this.onConsole); } - public async get(options?: {severity?: Severity; filter?: RegExp; consume?: boolean; probeInterval?: number}): Promise { - // Wait for log messages to become stable since received asynchronously. - const messages = await firstValueFrom(this._messages$.pipe(debounceTime(options?.probeInterval ?? 500))); + public contains(filter?: {severity?: Severity; message?: RegExp | string}): boolean { + return this.get(filter).length > 0; + } - if (options?.consume) { - this._messages$.next([]); - } - return messages - .filter(message => options?.severity === undefined || message.type() === options.severity) + public get(filter?: {severity?: Severity; message?: RegExp | string}): string[] { + return this._messages + .filter(message => filter?.severity === undefined || message.type() === filter.severity) .map(message => message.text()) - .filter(message => options?.filter === undefined || message.match(options.filter)); + .filter(message => filter?.message === undefined || filterMessage(message, filter.message)); } - public async clear(): Promise { - await this.get({consume: true}); + public clear(): void { + this._messages.length = 0; } public dispose(): void { @@ -44,10 +41,17 @@ export class ConsoleLogs { } private onConsole = (message: ConsoleMessage): void => { - this._messages$.next([...this._messages$.value, message]); + this._messages.push(message); }; } +function filterMessage(message: string, filter: string | RegExp): boolean { + if (typeof filter === 'string') { + return message.includes(filter); + } + return message.match(filter) !== null; +} + /** * @see ConsoleMessage#type */ diff --git a/projects/scion/components.e2e/src/helper/testing.utils.ts b/projects/scion/components.e2e/src/helper/testing.utils.ts index 188002ac..d4abfecb 100644 --- a/projects/scion/components.e2e/src/helper/testing.utils.ts +++ b/projects/scion/components.e2e/src/helper/testing.utils.ts @@ -9,6 +9,7 @@ */ import {Locator} from '@playwright/test'; +import {exhaustMap, filter, firstValueFrom, map, pairwise, timer} from 'rxjs'; /** * Returns `true` if given element is the active element. @@ -41,6 +42,25 @@ export function fromRect(rect: DOMRectInit | null): DomRect { }; } +/** + * Waits for a value to become stable. + * This function returns the value if it hasn't changed during `probeInterval` (defaults to 100ms). + */ +export async function waitUntilStable(value: () => Promise | A, options?: {isStable?: (previous: A, current: A) => boolean; probeInterval?: number}): Promise { + if (options?.probeInterval === 0) { + return value(); + } + + const value$ = timer(0, options?.probeInterval ?? 100) + .pipe( + exhaustMap(async () => await value()), + pairwise(), + filter(([previous, current]) => options?.isStable ? options.isStable(previous, current) : previous === current), + map(([previous]) => previous), + ); + return firstValueFrom(value$); +} + /** * Position and size of an element. */ diff --git a/projects/scion/components.e2e/src/toolkit/observable/bounding-client-rect/bounding-client-rect-page.e2e-spec.ts b/projects/scion/components.e2e/src/toolkit/observable/bounding-client-rect/bounding-client-rect-page.e2e-spec.ts index 5ab22ad9..dfe62bd1 100644 --- a/projects/scion/components.e2e/src/toolkit/observable/bounding-client-rect/bounding-client-rect-page.e2e-spec.ts +++ b/projects/scion/components.e2e/src/toolkit/observable/bounding-client-rect/bounding-client-rect-page.e2e-spec.ts @@ -11,6 +11,7 @@ import {test} from '../../../fixtures'; import {expect} from '@playwright/test'; import {BoundingClientRectPagePO} from './bounding-client-rect-page.po'; +import {waitUntilStable} from '../../../helper/testing.utils'; test.describe('@scion/toolkit/observable/fromBoundingClientRect$', () => { @@ -22,14 +23,36 @@ test.describe('@scion/toolkit/observable/fromBoundingClientRect$', () => { // Set element size to 100x100 pixel. await testPage.enterProperties({x: '0', y: '0', width: '100px', height: '100px'}); + await testPage.applyProperties(); await expect(testPage.testeeBoundingBox.width).toHaveText('100'); // Set element width to 100% and expect the bounding box to be updated. await testPage.enterProperties({x: '0', y: '0', width: '100%', height: '100px'}); + await testPage.applyProperties(); await expect(testPage.testeeBoundingBox.width).toHaveText(`${initialWindowWidth}`); // Increase window width by 200px and expect the bounding box to be updated. await testPage.resizeWindow({width: initialWindowWidth + 200}); await expect(testPage.testeeBoundingBox.width).toHaveText(`${initialWindowWidth + 200}`); }); + + test('should not run Angular change detection when changing element size', async ({page, consoleLogs}) => { + const testPage = new BoundingClientRectPagePO(page); + await testPage.navigate(); + + // Set element size to 200x200 pixel. + await testPage.enterProperties({x: '0', y: '0', width: '200px', height: '200px'}); + + // Clear console logs. + await waitUntilStable(() => consoleLogs.get().length); + consoleLogs.clear(); + + // Apply properties. + await testPage.applyProperties(); + await expect(testPage.testeeBoundingBox.width).toHaveText('200'); + + // Expect Angular not to run additional change detection when changing element size. (One change detection cycle is triggered by pressing the button) + await waitUntilStable(() => consoleLogs.get().length); + await expect.poll(() => consoleLogs.get({message: '[BoundingClientRectPageComponent] Angular change detection cycle'})).toHaveLength(1); + }); }); diff --git a/projects/scion/components.e2e/src/toolkit/observable/bounding-client-rect/bounding-client-rect-page.po.ts b/projects/scion/components.e2e/src/toolkit/observable/bounding-client-rect/bounding-client-rect-page.po.ts index 0f35d467..e159d071 100644 --- a/projects/scion/components.e2e/src/toolkit/observable/bounding-client-rect/bounding-client-rect-page.po.ts +++ b/projects/scion/components.e2e/src/toolkit/observable/bounding-client-rect/bounding-client-rect-page.po.ts @@ -37,11 +37,15 @@ export class BoundingClientRectPagePO { await this._page.goto(PATH); } - public async enterProperties(properties: {x: string; y: string; width: string; height: string}): Promise { + public async enterProperties(properties: {x: string; y: string; width: string; height: string;}): Promise { await this._locator.locator('section.e2e-properties input.e2e-x').fill(properties.x); await this._locator.locator('section.e2e-properties input.e2e-y').fill(properties.y); await this._locator.locator('section.e2e-properties input.e2e-width').fill(properties.width); await this._locator.locator('section.e2e-properties input.e2e-height').fill(properties.height); + await this._locator.press('Tab'); + } + + public async applyProperties(): Promise { await this._locator.locator('section.e2e-properties button.e2e-apply').click(); } diff --git a/projects/scion/components/dimension/src/bounding-client-rect.signal.spec.ts b/projects/scion/components/dimension/src/bounding-client-rect.signal.spec.ts index 7fb8a9b8..a40cb483 100644 --- a/projects/scion/components/dimension/src/bounding-client-rect.signal.spec.ts +++ b/projects/scion/components/dimension/src/bounding-client-rect.signal.spec.ts @@ -9,7 +9,7 @@ */ import {ComponentFixtureAutoDetect, TestBed} from '@angular/core/testing'; -import {Component, computed, createEnvironmentInjector, effect, ElementRef, EnvironmentInjector, Injector, runInInjectionContext, signal, Signal, viewChild} from '@angular/core'; +import {Component, computed, createEnvironmentInjector, DoCheck, effect, ElementRef, EnvironmentInjector, Injector, runInInjectionContext, signal, Signal, viewChild} from '@angular/core'; import {firstValueFrom, mergeMap, NEVER, race, throwError, timer} from 'rxjs'; import {toObservable} from '@angular/core/rxjs-interop'; import {first} from 'rxjs/operators'; @@ -527,6 +527,75 @@ describe('Bounding Client Rect Signal', () => { await expectAsync(waitForSignalChange(boundingBox, {timeout: 500})).toBeRejected(); }); + xit('should not trigger change detection cycle', async () => { + TestBed.configureTestingModule({ + providers: [ + {provide: ComponentFixtureAutoDetect, useValue: true}, + ], + teardown: { + destroyAfterEach: false, + }, + }); + + @Component({ + selector: 'spec-component', + template: ` +
+ `, + styles: ` + div.testee { + position: relative; + width: 300px; + height: 150px; + box-sizing: border-box; + border: 1px solid red; + background-color: blue; + } + `, + }) + class TestComponent implements DoCheck { + public testee = viewChild.required>('testee'); + + ngDoCheck(): void { + console.log('[TestComponent] Angular change detection cycle'); + } + } + + const fixture = TestBed.createComponent(TestComponent); + const boundingBox = TestBed.runInInjectionContext(() => boundingClientRect(fixture.componentInstance.testee())); + const {x, y} = boundingBox(); + + // Spy console. + console.log('>>> spy console'); + spyOn(console, 'log').and.callThrough(); + + // Expect initial bounding box. + expect(boundingBox()).toEqual(jasmine.objectContaining({ + width: 300, + height: 150, + x, + y, + })); + + // Change size. + setSize(fixture.componentInstance.testee(), {width: 200, height: 100}); + await waitForSignalChange(boundingBox); + expect(boundingBox()).toEqual(jasmine.objectContaining({ + width: 200, + height: 100, + x: x + 10, + y: y + 10, + })); + + // Expect no change detection cycle to be triggered. + expect(console.log).not.toHaveBeenCalledWith('[TestComponent] Angular change detection cycle'); + + fixture.detectChanges(); + + // Expect no change detection cycle to be triggered. + expect(console.log).not.toHaveBeenCalledWith('[TestComponent] Angular change detection cycle'); + }); + it('should error if called from within a reactive context', () => { const boundingBox = computed(() => boundingClientRect(document.body)); expect(() => boundingBox()).toThrowError(/boundingClientRect\(\) cannot be called from within a reactive context/); diff --git a/projects/scion/components/dimension/src/bounding-client-rect.signal.ts b/projects/scion/components/dimension/src/bounding-client-rect.signal.ts index c4f0f2c1..954a0352 100644 --- a/projects/scion/components/dimension/src/bounding-client-rect.signal.ts +++ b/projects/scion/components/dimension/src/bounding-client-rect.signal.ts @@ -59,7 +59,7 @@ export function boundingClientRect(elementLike: HTMLElement | ElementRef subscription.unsubscribe()); }); - }, {injector}); + }, {injector, forceRoot: true}); // Create root effect to not trigger change detection cycle on bounding box change. // Create signal that recomputes each time the bounding box changes. return computed(() => { diff --git a/tsconfig.json b/tsconfig.json index d03b4869..c38b8120 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -22,17 +22,17 @@ "ES2022", "dom" ], - "paths": { - "@scion/toolkit/*": [ - "./dist/scion/toolkit/*" - ], - "@scion/components/*": [ - "./dist/scion/components/*" - ], - "@scion/components.internal/*": [ - "./dist/scion/components.internal/*" - ] - } + // "paths": { + // "@scion/toolkit/*": [ + // "./dist/scion/toolkit/*" + // ], + // "@scion/components/*": [ + // "./dist/scion/components/*" + // ], + // "@scion/components.internal/*": [ + // "./dist/scion/components.internal/*" + // ] + // } /* * ======================================+ * | PATH-OVERRIDE-FOR-DEVELOPMENT | @@ -40,80 +40,80 @@ * | DO NOT ACTIVATE FOR PRODUCTION! | * +=====================================+ */ - // "paths": { - // "@scion/components/dimension": [ - // "./projects/scion/components/dimension/src/public_api" - // ], - // "@scion/components/sashbox": [ - // "./projects/scion/components/sashbox/src/public_api" - // ], - // "@scion/components/splitter": [ - // "./projects/scion/components/splitter/src/public_api" - // ], - // "@scion/components/throbber": [ - // "./projects/scion/components/throbber/src/public_api" - // ], - // "@scion/components/viewport": [ - // "./projects/scion/components/viewport/src/public_api" - // ], - // "@scion/toolkit/bean-manager": [ - // "./projects/scion/toolkit/bean-manager/src/public_api" - // ], - // "@scion/toolkit/crypto": [ - // "./projects/scion/toolkit/crypto/src/public_api" - // ], - // "@scion/toolkit/observable": [ - // "./projects/scion/toolkit/observable/src/public_api" - // ], - // "@scion/toolkit/operators": [ - // "./projects/scion/toolkit/operators/src/public_api" - // ], - // "@scion/toolkit/storage": [ - // "./projects/scion/toolkit/storage/src/public_api" - // ], - // "@scion/toolkit/testing": [ - // "./projects/scion/toolkit/testing/src/public_api" - // ], - // "@scion/toolkit/util": [ - // "./projects/scion/toolkit/util/src/public_api" - // ], - // "@scion/toolkit/uuid": [ - // "./projects/scion/toolkit/uuid/src/public_api" - // ], - // "@scion/components.internal/accordion": [ - // "./projects/scion/components.internal/accordion/src/public_api" - // ], - // "@scion/components.internal/checkbox": [ - // "./projects/scion/components.internal/checkbox/src/public_api" - // ], - // "@scion/components.internal/filter-field": [ - // "./projects/scion/components.internal/filter-field/src/public_api" - // ], - // "@scion/components.internal/form-field": [ - // "./projects/scion/components.internal/form-field/src/public_api" - // ], - // "@scion/components.internal/list": [ - // "./projects/scion/components.internal/list/src/public_api" - // ], - // "@scion/components.internal/key-value-field": [ - // "./projects/scion/components.internal/key-value-field/src/public_api" - // ], - // "@scion/components.internal/key-value": [ - // "./projects/scion/components.internal/key-value/src/public_api" - // ], - // "@scion/components.internal/qualifier-chip-list": [ - // "./projects/scion/components.internal/qualifier-chip-list/src/public_api" - // ], - // "@scion/components.internal/tabbar": [ - // "./projects/scion/components.internal/tabbar/src/public_api" - // ], - // "@scion/components.internal/toggle-button": [ - // "./projects/scion/components.internal/toggle-button/src/public_api" - // ], - // "@scion/components.internal/material-icon": [ - // "./projects/scion/components.internal/material-icon/src/public_api" - // ], - // } + "paths": { + "@scion/components/dimension": [ + "./projects/scion/components/dimension/src/public_api" + ], + "@scion/components/sashbox": [ + "./projects/scion/components/sashbox/src/public_api" + ], + "@scion/components/splitter": [ + "./projects/scion/components/splitter/src/public_api" + ], + "@scion/components/throbber": [ + "./projects/scion/components/throbber/src/public_api" + ], + "@scion/components/viewport": [ + "./projects/scion/components/viewport/src/public_api" + ], + "@scion/toolkit/bean-manager": [ + "./projects/scion/toolkit/bean-manager/src/public_api" + ], + "@scion/toolkit/crypto": [ + "./projects/scion/toolkit/crypto/src/public_api" + ], + "@scion/toolkit/observable": [ + "./projects/scion/toolkit/observable/src/public_api" + ], + "@scion/toolkit/operators": [ + "./projects/scion/toolkit/operators/src/public_api" + ], + "@scion/toolkit/storage": [ + "./projects/scion/toolkit/storage/src/public_api" + ], + "@scion/toolkit/testing": [ + "./projects/scion/toolkit/testing/src/public_api" + ], + "@scion/toolkit/util": [ + "./projects/scion/toolkit/util/src/public_api" + ], + "@scion/toolkit/uuid": [ + "./projects/scion/toolkit/uuid/src/public_api" + ], + "@scion/components.internal/accordion": [ + "./projects/scion/components.internal/accordion/src/public_api" + ], + "@scion/components.internal/checkbox": [ + "./projects/scion/components.internal/checkbox/src/public_api" + ], + "@scion/components.internal/filter-field": [ + "./projects/scion/components.internal/filter-field/src/public_api" + ], + "@scion/components.internal/form-field": [ + "./projects/scion/components.internal/form-field/src/public_api" + ], + "@scion/components.internal/list": [ + "./projects/scion/components.internal/list/src/public_api" + ], + "@scion/components.internal/key-value-field": [ + "./projects/scion/components.internal/key-value-field/src/public_api" + ], + "@scion/components.internal/key-value": [ + "./projects/scion/components.internal/key-value/src/public_api" + ], + "@scion/components.internal/qualifier-chip-list": [ + "./projects/scion/components.internal/qualifier-chip-list/src/public_api" + ], + "@scion/components.internal/tabbar": [ + "./projects/scion/components.internal/tabbar/src/public_api" + ], + "@scion/components.internal/toggle-button": [ + "./projects/scion/components.internal/toggle-button/src/public_api" + ], + "@scion/components.internal/material-icon": [ + "./projects/scion/components.internal/material-icon/src/public_api" + ] + } }, "angularCompilerOptions": { "enableI18nLegacyMessageIdFormat": false,