diff --git a/libs/components/indicators/src/lib/modules/illustration/illustration.component.html b/libs/components/indicators/src/lib/modules/illustration/illustration.component.html index 53b292a1b9..0806eb0584 100644 --- a/libs/components/indicators/src/lib/modules/illustration/illustration.component.html +++ b/libs/components/indicators/src/lib/modules/illustration/illustration.component.html @@ -4,6 +4,9 @@ loading="lazy" [attr.data-sky-illustration-name]="name()" [height]="pixelSize()" + [ngClass]="{ + 'sky-illustration-img-loaded': !!url() + }" [src]="url()" [width]="pixelSize()" /> diff --git a/libs/components/indicators/src/lib/modules/illustration/illustration.component.spec.ts b/libs/components/indicators/src/lib/modules/illustration/illustration.component.spec.ts index 2ba5c2168d..ba46885b7c 100644 --- a/libs/components/indicators/src/lib/modules/illustration/illustration.component.spec.ts +++ b/libs/components/indicators/src/lib/modules/illustration/illustration.component.spec.ts @@ -20,13 +20,16 @@ describe('Illustration', () => { provideResolver: boolean, name: string, size: SkyIllustrationSize, + resolver?: { + resolveUrl: (url: string) => Promise; + }, ): void { const providers: Provider[] = []; if (provideResolver) { providers.push({ provide: SkyIllustrationResolverService, - useClass: SkyIllustrationTestResolverService, + useFactory: () => resolver ?? new SkyIllustrationTestResolverService(), }); } @@ -50,6 +53,17 @@ describe('Illustration', () => { expect(getImgEl()?.getAttribute(name)).toBe(expectedValue); } + function validateImageVisibility(expectedVisible: boolean): void { + const imgEl = getImgEl(); + let visibility: string | undefined; + + if (imgEl) { + visibility = getComputedStyle(imgEl).visibility; + } + + expect(visibility).toBe(expectedVisible ? 'visible' : 'hidden'); + } + function detectUrlChanges(): void { fixture.detectChanges(); @@ -101,6 +115,33 @@ describe('Illustration', () => { await expectAsync(fixture.nativeElement).toBeAccessible(); }); + + it('should be hidden until the URL is resolved', fakeAsync(async () => { + // TODO: Use the more concise Promise.withResolvers() when it's available in TypeScript + // to avoid this awkward workaround for strict type checking. + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/withResolvers + let resolveUrl = (_: string): void => void _; + + const resolvePromise = new Promise( + (resolve) => (resolveUrl = resolve), + ); + + setupTest(true, 'test', 'sm', { + resolveUrl: () => resolvePromise, + }); + + detectUrlChanges(); + + validateImageVisibility(false); + + resolveUrl('https://example.com/success.svg'); + + detectUrlChanges(); + + validateImageVisibility(true); + + await resolvePromise; + })); }); describe('without resolver provided', () => { diff --git a/libs/components/indicators/src/lib/modules/illustration/illustration.default.component.scss b/libs/components/indicators/src/lib/modules/illustration/illustration.default.component.scss index 10b86f6eab..d3f89941a3 100644 --- a/libs/components/indicators/src/lib/modules/illustration/illustration.default.component.scss +++ b/libs/components/indicators/src/lib/modules/illustration/illustration.default.component.scss @@ -6,4 +6,8 @@ @include mixins.sky-component('default', '.sky-illustration-img') { display: block; + + &[src=''] { + visibility: hidden; + } } diff --git a/libs/components/indicators/src/lib/modules/illustration/illustration.modern.component.scss b/libs/components/indicators/src/lib/modules/illustration/illustration.modern.component.scss index e6ba64893b..1bc468a515 100644 --- a/libs/components/indicators/src/lib/modules/illustration/illustration.modern.component.scss +++ b/libs/components/indicators/src/lib/modules/illustration/illustration.modern.component.scss @@ -6,4 +6,8 @@ @include mixins.sky-component('modern', '.sky-illustration-img') { display: block; + + &[src=''] { + visibility: hidden; + } }