Skip to content

Commit

Permalink
feat(sbb-link-list-anchor): component implementation (#2987)
Browse files Browse the repository at this point in the history
  • Loading branch information
TomMenga authored Aug 12, 2024
1 parent 5fb0061 commit d81a565
Show file tree
Hide file tree
Showing 27 changed files with 788 additions and 138 deletions.
2 changes: 1 addition & 1 deletion src/elements/core/styles/mixins/link.scss
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
@mixin link-hover-rules {
@include mediaqueries.hover-mq($hover: true) {
color: var(--sbb-link-color-hover);
text-decoration: underline;
text-decoration: var(--sbb-link-hover-text-decoration, underline);
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/elements/link-list.ts
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
export * from './link-list/link-list.js';
export * from './link-list/link-list-anchor.js';
export * from './link-list/common.js';
3 changes: 3 additions & 0 deletions src/elements/link-list/common.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './common/link-list-base.js';

export { default as linkListBaseStyle } from './common/link-list-base.scss?lit&inline';
23 changes: 23 additions & 0 deletions src/elements/link-list/common/link-list-base.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
@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-link-list-wrapper {
display: flex;
flex-direction: column;
gap: var(--sbb-spacing-fixed-3x);
}

.sbb-link-list-title {
// Overwrite sbb-title default margin
margin: 0;

:host(:not([data-slot-names~='title'], [title-content])) & {
display: none;
}
}
83 changes: 83 additions & 0 deletions src/elements/link-list/common/link-list-base.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import type { PropertyValues, TemplateResult } from 'lit';
import { html, LitElement, nothing } from 'lit';
import { property } from 'lit/decorators.js';

import { slotState } from '../../core/decorators.js';
import {
SbbNamedSlotListMixin,
SbbNegativeMixin,
type WithListChildren,
} from '../../core/mixins.js';
import type {
SbbBlockLinkButtonElement,
SbbBlockLinkElement,
SbbBlockLinkStaticElement,
SbbLinkSize,
} from '../../link.js';
import type { SbbTitleLevel } from '../../title.js';

import '../../title.js';

/**
* It displays a list of `sbb-block-link`.
*
* @slot - Use the unnamed slot to add one or more `sbb-block-link`.
* @slot title - Use this slot to provide a title.
*/
@slotState()
export class SbbLinkListBaseElement extends SbbNegativeMixin(
SbbNamedSlotListMixin<
SbbBlockLinkElement | SbbBlockLinkButtonElement | SbbBlockLinkStaticElement,
typeof LitElement
>(LitElement),
) {
protected override readonly listChildLocalNames = [
'sbb-block-link',
'sbb-block-link-button',
'sbb-block-link-static',
];

/** The title text we want to show before the list. */
@property({ attribute: 'title-content', reflect: true }) public titleContent?: string;

/** The semantic level of the title, e.g. 2 = h2. */
@property({ attribute: 'title-level' }) public titleLevel: SbbTitleLevel = '2';

/**
* Text size of the nested sbb-block-link instances.
* This will overwrite the size attribute of nested sbb-block-link instances.
*/
@property({ reflect: true }) public size: SbbLinkSize = 's';

protected override willUpdate(changedProperties: PropertyValues<WithListChildren<this>>): void {
super.willUpdate(changedProperties);

if (
changedProperties.has('size') ||
changedProperties.has('negative') ||
changedProperties.has('listChildren')
) {
for (const link of this.listChildren) {
link.negative = this.negative;
link.size = this.size;
}
}
}

protected override render(): TemplateResult {
return html`
<div class="sbb-link-list-wrapper">
<sbb-title
class="sbb-link-list-title"
level=${this.titleLevel || nothing}
visual-level="5"
?negative=${this.negative}
id="sbb-link-list-title-id"
>
<slot name="title">${this.titleContent}</slot>
</sbb-title>
${this.renderList({ ariaLabelledby: 'sbb-link-list-title-id' })}
</div>
`;
}
}
1 change: 1 addition & 0 deletions src/elements/link-list/link-list-anchor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './link-list-anchor/link-list-anchor.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["sbb-link-list-anchor renders DOM"] =
`<sbb-link-list-anchor
data-slot-names="li-0 li-1 li-2"
size="s"
title-content="title"
>
<sbb-block-link
data-action=""
data-link=""
data-sbb-link=""
data-slot-names="unnamed"
dir="ltr"
href="https://www.sbb.ch"
icon-placement="start"
size="s"
slot="li-0"
>
Link 0
</sbb-block-link>
<sbb-block-link
data-action=""
data-link=""
data-sbb-link=""
data-slot-names="unnamed"
dir="ltr"
href="https://www.sbb.ch"
icon-placement="start"
size="s"
slot="li-1"
>
Link 1
</sbb-block-link>
<sbb-block-link
data-action=""
data-link=""
data-sbb-link=""
data-slot-names="unnamed"
dir="ltr"
href="https://www.sbb.ch"
icon-placement="start"
size="s"
slot="li-2"
>
Link 2
</sbb-block-link>
</sbb-link-list-anchor>
`;
/* end snapshot sbb-link-list-anchor renders DOM */

snapshots["sbb-link-list-anchor renders Shadow DOM"] =
`<div class="sbb-link-list-wrapper">
<sbb-title
aria-level="2"
class="sbb-link-list-title"
id="sbb-link-list-title-id"
level="2"
role="heading"
visual-level="5"
>
<slot name="title">
title
</slot>
</sbb-title>
<ul
aria-labelledby="sbb-link-list-title-id"
class="sbb-link-list-anchor"
>
<li>
<slot name="li-0">
</slot>
</li>
<li>
<slot name="li-1">
</slot>
</li>
<li>
<slot name="li-2">
</slot>
</li>
</ul>
<span hidden="">
<slot>
</slot>
</span>
</div>
`;
/* end snapshot sbb-link-list-anchor renders Shadow DOM */

snapshots["sbb-link-list-anchor renders A11y tree Chrome"] =
`<p>
{
"role": "WebArea",
"name": "",
"children": [
{
"role": "heading",
"name": "title",
"level": 2
},
{
"role": "link",
"name": "Link 0"
},
{
"role": "link",
"name": "Link 1"
},
{
"role": "link",
"name": "Link 2"
}
]
}
</p>
`;
/* end snapshot sbb-link-list-anchor renders A11y tree Chrome */

snapshots["sbb-link-list-anchor renders A11y tree Firefox"] =
`<p>
{
"role": "document",
"name": "",
"children": [
{
"role": "heading",
"name": "title",
"level": 2
},
{
"role": "link",
"name": "Link 0",
"value": "https://www.sbb.ch/"
},
{
"role": "link",
"name": "Link 1",
"value": "https://www.sbb.ch/"
},
{
"role": "link",
"name": "Link 2",
"value": "https://www.sbb.ch/"
}
]
}
</p>
`;
/* end snapshot sbb-link-list-anchor renders A11y tree Firefox */

1 change: 1 addition & 0 deletions src/elements/link-list/link-list-anchor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './link-list-anchor.js';
53 changes: 53 additions & 0 deletions src/elements/link-list/link-list-anchor/link-list-anchor.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
@use '../../core/styles/index' as sbb;

:host {
--sbb-link-list-anchor-border-color: var(--sbb-color-cloud);
}

:host([negative]) {
--sbb-link-list-anchor-border-color: var(--sbb-color-granite);
}

::slotted([data-link]) {
--sbb-link-text-decoration: none;
--sbb-link-hover-text-decoration: none;
--sbb-link-padding: var(--sbb-spacing-fixed-1x) 0 var(--sbb-spacing-fixed-1x)
var(--sbb-spacing-fixed-4x);
--sbb-link-color-hover: var(--sbb-color-charcoal);
--sbb-link-color-active: var(--sbb-color-granite);

border-inline-start: var(--sbb-border-width-1x) solid var(--sbb-link-list-anchor-border-color);

:host([negative]) & {
--sbb-link-color-normal: var(--sbb-color-smoke);
--sbb-link-color-hover: var(--sbb-color-milk);
--sbb-link-color-active: var(--sbb-color-smoke);
}
}

::slotted([data-link]:is(:active, [data-active]):not([disabled])) {
--sbb-link-list-anchor-border-color: var(--sbb-color-iron);

:host([negative]) & {
--sbb-link-list-anchor-border-color: var(--sbb-color-silver);
}
}

::slotted([data-link]:hover:not([disabled])) {
--sbb-link-list-anchor-border-color: var(--sbb-color-charcoal);

:host([negative]) & {
--sbb-link-list-anchor-border-color: var(--sbb-color-milk);
}
}

.sbb-link-list-anchor {
@include sbb.list-reset;

display: flex;
flex-flow: column;

> li {
margin-inline-start: var(--sbb-spacing-fixed-4x);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { expect } from '@open-wc/testing';
import { html } from 'lit/static-html.js';

import { fixture, testA11yTreeSnapshot } from '../../core/testing/private.js';

import type { SbbLinkListAnchorElement } from './link-list-anchor.js';
import './link-list-anchor.js';
import '../../link/block-link.js';

describe(`sbb-link-list-anchor`, () => {
describe('renders', () => {
let element: SbbLinkListAnchorElement;

beforeEach(async () => {
element = await fixture(html`
<sbb-link-list-anchor title-content="title">
${new Array(3)
.fill('')
.map(
(_v, i) => html`
<sbb-block-link href="https://www.sbb.ch">Link ${i}</sbb-block-link>
`,
)}
</sbb-link-list-anchor>
`);
});

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

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

testA11yTreeSnapshot();
});
});
Loading

0 comments on commit d81a565

Please sign in to comment.