Skip to content

Commit

Permalink
feat(sbb-lead-container): initial implementation (#2672)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeripeierSBB committed May 28, 2024
1 parent 35c7c21 commit bb1f3a8
Show file tree
Hide file tree
Showing 13 changed files with 471 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/components/core/testing/private.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export * from './private/describe-viewports.js';
export * from './private/dispatch-events.js';
export * from './private/event-objects.js';
export * from './private/fixture.js';
export * from './private/load-asset-as-base64.js';
export * from './private/platform.js';
export * from './private/type-in-element.js';
export * from './private/visual-regression-snapshot.js';
2 changes: 1 addition & 1 deletion src/components/core/testing/private/fixture.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ export async function visualRegressionFixture<T extends HTMLElement>(
const fix = await fixture<T>(
html`<div
style=${`padding: ${wrapperStyles?.padding ?? '2rem'};background-color: ${wrapperStyles?.backgroundColor ?? 'var(--sbb-color-white)'};${wrapperStyles?.focusOutlineDark ? ' --sbb-focus-outline-color: var(--sbb-focus-outline-color-dark);' : ''}`}
tabindex="1"
tabindex="0"
>
${template}
</div>`,
Expand Down
3 changes: 3 additions & 0 deletions src/components/core/testing/private/load-asset-as-base64.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export async function loadAssetAsBase64(url: string): Promise<string> {
return URL.createObjectURL(await fetch(url).then((r) => r.blob()));
}
2 changes: 1 addition & 1 deletion src/components/image/image.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
--sbb-image-border-radius: var(--sbb-border-radius-4x);
--sbb-image-aspect-ratio: auto;
--sbb-image-animation-duration: var(
--sbb-disable-animation-time,
--sbb-disable-animation-zero-time,
var(--sbb-animation-duration-4x)
);

Expand Down
1 change: 1 addition & 0 deletions src/components/lead-container.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './lead-container/lead-container.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["sbb-lead-container DOM"] =
`<sbb-lead-container>
<sbb-image
aspect-ratio="16-9"
border-radius="default"
slot="image"
>
</sbb-image>
</sbb-lead-container>
`;
/* end snapshot sbb-lead-container DOM */

snapshots["sbb-lead-container Shadow DOM"] =
`<div class="sbb-lead-container">
<div class="sbb-lead-container-image">
<slot name="image">
</slot>
</div>
<div class="sbb-lead-container-content-wrapper">
<div class="sbb-lead-container-content">
<slot>
</slot>
</div>
</div>
</div>
`;
/* end snapshot sbb-lead-container Shadow DOM */

snapshots["sbb-lead-container A11y tree Chrome"] =
`<p>
{
"role": "WebArea",
"name": ""
}
</p>
`;
/* end snapshot sbb-lead-container A11y tree Chrome */

snapshots["sbb-lead-container A11y tree Firefox"] =
`<p>
{
"role": "document",
"name": ""
}
</p>
`;
/* end snapshot sbb-lead-container A11y tree Firefox */

Binary file added src/components/lead-container/assets/lucerne.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
101 changes: 101 additions & 0 deletions src/components/lead-container/lead-container.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
@use '../core/styles' as sbb;

// Box-sizing rules contained in typography are not traversing Shadow DOM boundaries. We need to include box-sizing mixin in every component.
@include sbb.box-sizing;

:host {
display: block;

--sbb-lead-container-background-color: var(--sbb-color-white);
--sbb-lead-container-image-ratio: 2 / 1;
--sbb-lead-container-image-overlap: var(--sbb-spacing-fixed-24x);
--sbb-lead-container-padding-block: var(--sbb-spacing-responsive-l);
--sbb-lead-container-padding-inline: var(--sbb-layout-base-offset-responsive);
--sbb-lead-container-border-radius: var(--sbb-border-radius-6x);
--sbb-lead-container-image-border-radius: 0;

@include sbb.mq($from: wide) {
--sbb-lead-container-image-ratio: 21 / 9;
}

@include sbb.mq($from: ultra) {
--sbb-lead-container-image-border-radius: var(--sbb-lead-container-border-radius);
}
}

.sbb-lead-container {
padding-block-end: var(--sbb-spacing-responsive-l);
}

::slotted(sbb-image[slot='image']) {
--sbb-image-aspect-ratio: var(--sbb-lead-container-image-ratio);
--sbb-image-border-radius: var(--sbb-lead-container-image-border-radius);
}

::slotted(:is(img[slot='image'], picture[slot='image'])) {
display: block;
width: 100%;
object-fit: cover;
aspect-ratio: var(--sbb-lead-container-image-ratio);
border-radius: var(--sbb-lead-container-image-border-radius);
}

::slotted(:is(sbb-breadcrumb-group, sbb-block-link).sbb-lead-container-spacing) {
margin-block-end: var(--sbb-spacing-fixed-4x);
}

::slotted(sbb-title.sbb-lead-container-spacing) {
margin-block-start: 0;
}

::slotted(.sbb-lead-container-lead-text) {
margin-block: 0 var(--sbb-spacing-responsive-s);
}

.sbb-lead-container-image {
@include sbb.mq($from: ultra) {
max-width: calc(
var(--sbb-layout-base-page-max-width) + 2 * var(--sbb-layout-base-offset-responsive)
);
margin-inline: auto;
}
}

.sbb-lead-container-content-wrapper {
@include sbb.grid;

// In case there is a global background color set, use full width with white color until large breakpoint
background-color: var(--sbb-lead-container-background-color);

@include sbb.mq($from: large) {
background-color: transparent;
}
}

.sbb-lead-container-content {
z-index: 1;
border-radius: var(--sbb-lead-container-border-radius);
padding-block: var(--sbb-lead-container-padding-block);
background-color: var(--sbb-lead-container-background-color);
grid-column: 1 / -1;

@include sbb.mq($from: medium) {
grid-column: 2 / -2;
}

@include sbb.mq($from: large) {
margin-block-start: calc(-1 * var(--sbb-lead-container-image-overlap));
padding-inline: var(--sbb-lead-container-padding-inline);

// As the content should be aligned to the grid, we have to stretch the container by padding
margin-inline: calc(-1 * var(--sbb-lead-container-padding-inline));
}

@include sbb.mq($from: wide) {
grid-column: 3 / -3;
}

@include sbb.mq($from: ultra) {
grid-column: 4 / -4;
}
}
133 changes: 133 additions & 0 deletions src/components/lead-container/lead-container.snapshot.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { aTimeout, expect } from '@open-wc/testing';
import type { TemplateResult } from 'lit';
import { html } from 'lit/static-html.js';

import {
describeViewports,
fixture,
isVisualRegressionRun,
loadAssetAsBase64,
testA11yTreeSnapshot,
testVisualDiff,
visualRegressionFixture,
} from '../core/testing/private.js';
import { waitForCondition } from '../core/testing/wait-for-condition.js';

import type { SbbLeadContainerElement } from './lead-container.js';

import '../breadcrumb.js';
import '../image.js';
import '../link/block-link/block-link.js';
import '../title.js';
import './lead-container.js';

const leadImageUrl = import.meta.resolve('./assets/lucerne.png');
const leadImageBase64 = await loadAssetAsBase64(leadImageUrl);

describe(`sbb-lead-container`, () => {
if (!isVisualRegressionRun()) {
let element: SbbLeadContainerElement;

beforeEach(async () => {
element = await fixture(
html`<sbb-lead-container>
<sbb-image slot="image"></sbb-image>
</sbb-lead-container>`,
);
});

it('DOM', async () => {
await expect(element).dom.to.be.equalSnapshot();
});

it('Shadow DOM', async () => {
await expect(element).shadowDom.to.be.equalSnapshot();
});

testA11yTreeSnapshot();
} else {
describe('visual-regression', () => {
let root: HTMLElement;

const wrapperStyles = { backgroundColor: `var(--sbb-color-milk)`, padding: '0' };

const leadContainerTemplate = (image: TemplateResult): TemplateResult => html`
<sbb-lead-container>
<style>
p.other-content {
margin-block-end: 0;
}
</style>
${image}
<sbb-breadcrumb-group class="sbb-lead-container-spacing">
<sbb-breadcrumb href="#" icon-name="house-small" id="breadcrumb-0"></sbb-breadcrumb>
<sbb-breadcrumb href="#" id="breadcrumb-1">Level 1</sbb-breadcrumb>
</sbb-breadcrumb-group>
<sbb-block-link
icon-placement="start"
icon-name="chevron-small-left-small"
size="xs"
href="https://www.sbb.ch"
class="sbb-lead-container-spacing"
>
Link
</sbb-block-link>
<sbb-title class="sbb-lead-container-spacing">Title</sbb-title>
<p class="sbb-text-xl sbb-lead-container-lead-text">
Lead text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer enim elit,
ultricies in tincidunt quis, mattis eu quam. Nulla sit amet lorem fermentum, molestie
nunc ut, hendrerit risus.
</p>
<p class="sbb-text-m other-content">
Other content. Vestibulum rutrum elit et lacus sollicitudin, quis malesuada lorem
vehicula. Suspendisse at augue quis tellus vulputate tempor. Vivamus urna velit, varius
nec est ac, mollis efficitur lorem. Quisque non nisl eget massa interdum tempus.
Praesent vel feugiat metus.
</p>
</sbb-lead-container>
`;

describeViewports(() => {
describe('with sbb-image', () => {
beforeEach(async function () {
root = await visualRegressionFixture(
leadContainerTemplate(
html`<sbb-image
slot="image"
image-src=${leadImageUrl}
alt="Station of Lucerne from outside"
></sbb-image>`,
),
this,
wrapperStyles,
);
await waitForCondition(() =>
root.querySelector('sbb-image')!.hasAttribute('data-loaded'),
);
await aTimeout(20);
});

testVisualDiff(() => root);
});

describe('with img tag', () => {
beforeEach(async function () {
root = await visualRegressionFixture(
leadContainerTemplate(
html`<img
slot="image"
src=${leadImageBase64}
alt="Station of Lucerne from outside"
/>`,
),
this,
wrapperStyles,
);
});

testVisualDiff(() => root);
});
});
});
}
});
71 changes: 71 additions & 0 deletions src/components/lead-container/lead-container.stories.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import type { Meta, StoryObj } from '@storybook/web-components';
import { html, type TemplateResult } from 'lit';

import '../breadcrumb.js';
import '../image.js';
import '../link/block-link/block-link.js';
import '../title.js';
import './lead-container.js';

import images from '../core/images.js';

import readme from './readme.md?raw';

const DefaultTemplate = (): TemplateResult => html`
<sbb-lead-container>
<style>
p.other-content {
margin-block-end: 0;
}
</style>
<sbb-image
slot="image"
image-src=${images[6]}
alt="Station of Lucerne from outside"
></sbb-image>
<sbb-breadcrumb-group class="sbb-lead-container-spacing">
<sbb-breadcrumb href="#" icon-name="house-small" id="breadcrumb-0"></sbb-breadcrumb>
<sbb-breadcrumb href="#" id="breadcrumb-1">Level 1</sbb-breadcrumb>
<sbb-breadcrumb href="#" id="breadcrumb-1">Level 2</sbb-breadcrumb>
<sbb-breadcrumb href="#" id="breadcrumb-1">Level 3</sbb-breadcrumb>
<sbb-breadcrumb href="#" id="breadcrumb-1">Level 4</sbb-breadcrumb>
</sbb-breadcrumb-group>
<sbb-block-link
icon-placement="start"
icon-name="chevron-small-left-small"
size="xs"
href="https://www.sbb.ch"
class="sbb-lead-container-spacing"
>
Link
</sbb-block-link>
<sbb-title class="sbb-lead-container-spacing">Title</sbb-title>
<p class="sbb-text-xl sbb-lead-container-lead-text">
Lead text. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer enim elit,
ultricies in tincidunt quis, mattis eu quam. Nulla sit amet lorem fermentum, molestie nunc ut,
hendrerit risus.
</p>
<p class="sbb-text-m other-content">
Other content. Vestibulum rutrum elit et lacus sollicitudin, quis malesuada lorem vehicula.
Suspendisse at augue quis tellus vulputate tempor. Vivamus urna velit, varius nec est ac,
mollis efficitur lorem. Quisque non nisl eget massa interdum tempus. Praesent vel feugiat
metus.
</p>
</sbb-lead-container>
`;

export const Default: StoryObj = {
render: DefaultTemplate,
};

const meta: Meta = {
parameters: {
docs: {
extractComponentDescription: () => readme,
},
layout: 'fullscreen',
},
title: 'components/sbb-lead-container',
};

export default meta;
Loading

0 comments on commit bb1f3a8

Please sign in to comment.