Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(sbb-link-list-anchor): initial implementation #2987

Merged
merged 16 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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';
DavideMininni-Fincons marked this conversation as resolved.
Show resolved Hide resolved

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,151 @@
/* @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"
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';
25 changes: 25 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,25 @@
@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-list-anchor {
@include sbb.list-reset;

display: flex;
gap: var(--sbb-spacing-fixed-2x);
flex-flow: column;
margin-inline-start: var(--sbb-spacing-fixed-4x);
padding-inline-start: var(--sbb-spacing-fixed-4x);
padding-block: var(--sbb-spacing-fixed-1x);
border-inline-start: var(--sbb-border-width-1x) solid var(--sbb-link-list-anchor-border-color);
}
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();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { assert, expect } from '@open-wc/testing';
import { html } from 'lit/static-html.js';

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

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

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

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

it('renders', async () => {
assert.instanceOf(element, SbbLinkListAnchorElement);
});

it('should sync negative', async () => {
element.toggleAttribute('negative', true);
await waitForLitRender(element);
const links = Array.from(element.querySelectorAll('sbb-block-link'));
expect(links.every((l) => l.negative)).to.be.true;
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { assert } from '@open-wc/testing';
import { html } from 'lit/static-html.js';

import { ssrHydratedFixture } from '../../core/testing/private.js';

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

describe(`sbb-link-list-anchor ssr`, () => {
let root: SbbLinkListAnchorElement;

beforeEach(async () => {
root = await ssrHydratedFixture(
html` <sbb-link-list-anchor title-content="Title">
<sbb-block-link href="#">Link 1</sbb-block-link>
<sbb-block-link href="#">Link 2</sbb-block-link>
</sbb-link-list-anchor>`,
{
modules: ['./link-list-anchor.js', '../../link.js'],
},
);
});

it('renders', () => {
assert.instanceOf(root, SbbLinkListAnchorElement);
});
});
Loading
Loading