Skip to content

Commit

Permalink
feat: Configurable media component (#19067)
Browse files Browse the repository at this point in the history
  • Loading branch information
rmch91 authored Oct 18, 2024
1 parent 6d20b3b commit 1499ec5
Show file tree
Hide file tree
Showing 17 changed files with 1,030 additions and 113 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Component, Input, Pipe, PipeTransform } from '@angular/core';
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import {
FeatureConfigService,
I18nTestingModule,
ImageType,
Product,
Expand Down Expand Up @@ -64,6 +65,7 @@ describe('ConfiguratorOverviewBundleAttributeComponent', () => {
let component: ConfiguratorOverviewBundleAttributeComponent;
let fixture: ComponentFixture<ConfiguratorOverviewBundleAttributeComponent>;
let htmlElem: HTMLElement;
let featureConfigService: FeatureConfigService;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
Expand All @@ -73,7 +75,10 @@ describe('ConfiguratorOverviewBundleAttributeComponent', () => {
MockConfiguratorPriceComponent,
MockNumericPipe,
],
providers: [{ provide: ProductService, useClass: MockProductService }],
providers: [
{ provide: ProductService, useClass: MockProductService },
FeatureConfigService,
],
}).compileComponents();
}));

Expand All @@ -83,6 +88,7 @@ describe('ConfiguratorOverviewBundleAttributeComponent', () => {
);
component = fixture.componentInstance;
htmlElem = fixture.nativeElement;
featureConfigService = TestBed.inject(FeatureConfigService);
});

beforeEach(() => {
Expand Down Expand Up @@ -142,6 +148,8 @@ describe('ConfiguratorOverviewBundleAttributeComponent', () => {

describe('product image', () => {
it('should be visible if primary', () => {
spyOn(featureConfigService, 'isEnabled').and.returnValue(true);

product$.next(mockProduct);

fixture.detectChanges();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,35 @@ export interface FeatureTogglesInterface {
* in the future together with this feature toggle.
*/
allPageMetaResolversEnabledInCsr?: boolean;

/**
* When enabled, allows to provide extended formats and media queries for <picture> element if used in MediaComponent.
*
* Important: After activation default HTML element in MediaComponent will be `<img>`
* Only BannerComponent has passed `'picture'` value. If you need to use `<picture>` HTML element
* you need to pass `[elementType]="'picture'"` to `<cx-media>`
*
* For proper work requires `pictureElementFormats` provided in media config:
* ```ts
* provideConfig({
* pictureElementFormats: {
* mediaQueries: {
* 'max-width': '767px',
* ...
* },
* width: 50,
* height: 50,
* },
* })
* ```
*
* After activating this toggle, new inputs in `MediaComponent` — specifically
* `width`, `height`, and `sizes` — will be passed to the template as HTML attributes.
*
* Toggle activates `@Input() elementType: 'img' | 'picture' = 'img'` in `MediaComponent`
*
*/
useExtendedMediaComponentConfiguration?: boolean;
}

export const defaultFeatureToggles: Required<FeatureTogglesInterface> = {
Expand Down Expand Up @@ -738,4 +767,5 @@ export const defaultFeatureToggles: Required<FeatureTogglesInterface> = {
enableConsecutiveCharactersPasswordRequirement: false,
enablePasswordsCannotMatchInPasswordUpdateForm: false,
allPageMetaResolversEnabledInCsr: false,
useExtendedMediaComponentConfiguration: false,
};
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,7 @@ export function navigateToPDPInCustomerInterest(productCode: string) {
cy.get('.cx-product-interests-product-item').within(() => {
cy.get('.cx-code').should('contain', productCode);
cy.get(
'.cx-product-interests-product-image-link > .is-initialized > picture'
'.cx-product-interests-product-image-link > .is-initialized > img'
).click();
});
}
Expand Down
12 changes: 2 additions & 10 deletions projects/storefrontapp/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,13 @@ import { translationChunksConfig, translations } from '@spartacus/assets';
import {
I18nConfig,
OccConfig,
provideConfig,
RoutingConfig,
TestConfigModule,
provideConfig,
} from '@spartacus/core';
import { StoreFinderConfig } from '@spartacus/storefinder/core';
import { GOOGLE_MAPS_DEVELOPMENT_KEY_CONFIG } from '@spartacus/storefinder/root';
import {
AppRoutingModule,
StorefrontComponent,
USE_LEGACY_MEDIA_COMPONENT,
} from '@spartacus/storefront';
import { AppRoutingModule, StorefrontComponent } from '@spartacus/storefront';
import { environment } from '../environments/environment';
import { TestOutletModule } from '../test-outlets/test-outlet.module';
import { SpartacusModule } from './spartacus/spartacus.module';
Expand Down Expand Up @@ -94,10 +90,6 @@ if (!environment.production) {
// without a key, for development or demo purposes.
googleMaps: { apiKey: GOOGLE_MAPS_DEVELOPMENT_KEY_CONFIG },
}),
{
provide: USE_LEGACY_MEDIA_COMPONENT,
useValue: false,
},
],
bootstrap: [StorefrontComponent],
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ if (environment.cpq) {
enableConsecutiveCharactersPasswordRequirement: true,
enablePasswordsCannotMatchInPasswordUpdateForm: true,
allPageMetaResolversEnabledInCsr: true,
useExtendedMediaComponentConfiguration: true,
};
return appFeatureToggles;
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@
>
</cx-generic-link>
<p class="headline" *ngIf="data.headline" [innerHTML]="data.headline"></p>
<cx-media [container]="getImage(data)"></cx-media>
<cx-media
*cxFeature="'useExtendedMediaComponentConfiguration'"
[container]="getImage(data)"
[elementType]="'picture'"
></cx-media>
<cx-media
*cxFeature="'!useExtendedMediaComponentConfiguration'"
[container]="getImage(data)"
></cx-media>
<p class="content" *ngIf="data.content" [innerHTML]="data.content"></p>
</ng-container>
</ng-container>
Expand All @@ -21,14 +29,30 @@
[target]="getTarget(data)"
>
<p class="headline" *ngIf="data.headline" [innerHTML]="data.headline"></p>
<cx-media [container]="getImage(data)"></cx-media>
<cx-media
*cxFeature="'useExtendedMediaComponentConfiguration'"
[container]="getImage(data)"
[elementType]="'picture'"
></cx-media>
<cx-media
*cxFeature="'!useExtendedMediaComponentConfiguration'"
[container]="getImage(data)"
></cx-media>
<p class="content" *ngIf="data.content" [innerHTML]="data.content"></p>
</cx-generic-link>
</ng-container>
<ng-container *ngIf="!routerLink">
<div class="no-link">
<p class="headline" *ngIf="data.headline" [innerHTML]="data.headline"></p>
<cx-media [container]="getImage(data)"></cx-media>
<cx-media
*cxFeature="'useExtendedMediaComponentConfiguration'"
[container]="getImage(data)"
[elementType]="'picture'"
></cx-media>
<cx-media
*cxFeature="'!useExtendedMediaComponentConfiguration'"
[container]="getImage(data)"
></cx-media>
<p class="content" *ngIf="data.content" [innerHTML]="data.content"></p>
</div>
</ng-container>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
SemanticPathService,
UrlCommand,
} from '@spartacus/core';
import { MockFeatureDirective } from 'projects/storefrontlib/shared/test/mock-feature-directive';
import { BehaviorSubject, Observable, of } from 'rxjs';
import { CmsComponentData } from '../../../cms-structure/page/model/cms-component-data';
import { GenericLinkComponent } from '../../../shared/components/generic-link/generic-link.component';
Expand Down Expand Up @@ -81,7 +82,12 @@ describe('BannerComponent', () => {
beforeEach(() => {
TestBed.configureTestingModule({
imports: [RouterTestingModule, FeaturesConfigModule],
declarations: [BannerComponent, MockMediaComponent, GenericLinkComponent],
declarations: [
BannerComponent,
MockMediaComponent,
GenericLinkComponent,
MockFeatureDirective,
],
providers: [
{
provide: CmsComponentData,
Expand Down
15 changes: 15 additions & 0 deletions projects/storefrontlib/recipes/config/default-media.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,19 @@ export const mediaConfig: MediaConfig = {
product: { width: 284 },
zoom: { width: 515 },
},
pictureElementFormats: {
mobile: {
mediaQueries: '(max-width: 767px)',
},
tablet: {
mediaQueries: '(min-width: 768px) and (max-width: 1024px)',
},
desktop: {
mediaQueries: '(min-width: 1025px) and (max-width: 1439px)',
},
widescreen: {
mediaQueries: '(min-width: 1440px)',
},
},
pictureFormatsOrder: ['widescreen', 'desktop', 'tablet', 'mobile'],
};
111 changes: 80 additions & 31 deletions projects/storefrontlib/shared/components/media/media.component.html
Original file line number Diff line number Diff line change
@@ -1,36 +1,85 @@
<ng-container *ngIf="!!media">
<picture *ngIf="media.srcset && !isLegacy; else legacyImgTmp">
<source
*ngFor="
let source of media!.srcset! | cxMediaSources;
trackBy: trackByMedia
<ng-container *cxFeature="'useExtendedMediaComponentConfiguration'">
<picture
*ngIf="
!!media?.sources?.length && elementType !== 'img';
else imageElementTmp
"
[srcset]="source.srcset"
[media]="source.media"
/>
>
<source
*ngFor="let source of media.sources; trackBy: trackByMedia"
[media]="source.media"
[srcset]="source.srcset"
[attr.width]="source.width"
[attr.height]="source.height"
/>

<img
[loading]="loading"
[alt]="media.alt"
[title]="media.alt"
[src]="media.src"
[attr.role]="media.role"
(load)="loadHandler()"
(error)="errorHandler()"
/>
</picture>
<img
[loading]="loading"
[alt]="media.alt"
[title]="media.alt"
[src]="media.src"
[attr.role]="media.role"
[attr.width]="width"
[attr.height]="height"
[attr.sizes]="sizes"
(load)="loadHandler()"
(error)="errorHandler()"
/>
</picture>

<ng-template #legacyImgTmp>
<img
*ngIf="media.src"
[loading]="loading"
[alt]="media.alt"
[title]="media.alt"
[src]="media.src"
[srcset]="media?.srcset || media.src"
[attr.role]="media.role"
(load)="loadHandler()"
(error)="errorHandler()"
/>
</ng-template>
<ng-template #imageElementTmp>
<img
*ngIf="media.src"
[loading]="loading"
[alt]="media.alt"
[title]="media.alt"
[src]="media.src"
[srcset]="media.srcset || media.src"
[attr.role]="media.role"
[attr.width]="width"
[attr.height]="height"
[attr.sizes]="sizes"
(load)="loadHandler()"
(error)="errorHandler()"
/>
</ng-template>
</ng-container>

<ng-container *cxFeature="'!useExtendedMediaComponentConfiguration'">
<picture *ngIf="media.srcset && !isLegacy; else legacyImgTmp">
<source
*ngFor="
let source of media!.srcset! | cxMediaSources;
trackBy: trackByMedia
"
[srcset]="source.srcset"
[media]="source.media"
/>

<img
[loading]="loading"
[alt]="media.alt"
[title]="media.alt"
[src]="media.src"
[attr.role]="media.role"
(load)="loadHandler()"
(error)="errorHandler()"
/>
</picture>

<ng-template #legacyImgTmp>
<img
*ngIf="media.src"
[loading]="loading"
[alt]="media.alt"
[title]="media.alt"
[src]="media.src"
[srcset]="media?.srcset || media.src"
[attr.role]="media.role"
(load)="loadHandler()"
(error)="errorHandler()"
/>
</ng-template>
</ng-container>
</ng-container>
Loading

0 comments on commit 1499ec5

Please sign in to comment.