Skip to content

Commit

Permalink
refactor(sbb-breadcrumb): support SSR and hydration (#2224)
Browse files Browse the repository at this point in the history
  • Loading branch information
jeripeierSBB committed Nov 23, 2023
1 parent 0555549 commit e38ee8a
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 151 deletions.
5 changes: 1 addition & 4 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
dist/
loader/
hydrate/
src/components.d.ts
www/
tools/generate-component/boilerplate/
**/__snapshots__/

# not ignored folders/files
!.github/
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
coverage
dist
**/__snapshots__

# needed for apexes in `HTMLElementTagNameMap`, which otherwise would be stripped
tools/generate-component/boilerplate/component.ts
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"start": "storybook dev -p 6006",
"test": "wtr --coverage --group default",
"test:spec": "wtr --group spec",
"test:spec-snapshot": "yarn -S test:spec --update-snapshot",
"test:snapshot": "yarn test --update-snapshots",
"test:e2e": "wtr --group e2e",
"prepare": "husky install"
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots["sbb-breadcrumb renders with text"] =
`<a
class="sbb-breadcrumb"
download=""
href="/test"
rel="subsection"
role="presentation"
tabindex="-1"
target="_blank"
>
<slot name="icon">
</slot>
<span class="sbb-breadcrumb__label">
<slot>
</slot>
</span>
<span class="sbb-breadcrumb__label--opens-in-new-window">
. Link target opens in new window.
</span>
</a>
`;
/* end snapshot sbb-breadcrumb renders with text */

snapshots["sbb-breadcrumb renders with icon"] =
`<a
class="sbb-breadcrumb"
href="/"
role="presentation"
tabindex="-1"
>
<slot name="icon">
<sbb-icon
aria-hidden="true"
class="sbb-breadcrumb__icon"
data-namespace="default"
name="house-small"
role="img"
>
</sbb-icon>
</slot>
<span
class="sbb-breadcrumb__label"
hidden=""
>
<slot>
</slot>
</span>
</a>
`;
/* end snapshot sbb-breadcrumb renders with icon */

snapshots["sbb-breadcrumb renders with icon and text"] =
`<a
class="sbb-breadcrumb"
href="/"
role="presentation"
tabindex="-1"
>
<slot name="icon">
<sbb-icon
aria-hidden="true"
class="sbb-breadcrumb__icon"
data-namespace="default"
name="house-small"
role="img"
>
</sbb-icon>
</slot>
<span class="sbb-breadcrumb__label">
<slot>
</slot>
</span>
</a>
`;
/* end snapshot sbb-breadcrumb renders with icon and text */

snapshots["sbb-breadcrumb renders as span if no href is provided"] =
`<span class="sbb-breadcrumb">
<slot name="icon">
</slot>
<span class="sbb-breadcrumb__label">
<slot>
</slot>
</span>
</span>
`;
/* end snapshot sbb-breadcrumb renders as span if no href is provided */

14 changes: 7 additions & 7 deletions src/components/breadcrumb/breadcrumb/breadcrumb.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,17 @@
}
}

.sbb-breadcrumb__icon {
display: flex;
flex-shrink: 0;
cursor: pointer;
color: var(--sbb-breadcrumb-color);
}

.sbb-breadcrumb__label {
@include sbb.ellipsis;
}

.sbb-breadcrumb__label--opens-in-new-window {
@include sbb.screen-reader-only;
}

.sbb-breadcrumb__icon,
::slotted(*) {
slot[name='icon'] & {
flex-shrink: 0;
}
}
45 changes: 4 additions & 41 deletions src/components/breadcrumb/breadcrumb/breadcrumb.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,7 @@ describe('sbb-breadcrumb', () => {
</sbb-breadcrumb>
`);

expect(root).shadowDom.to.be.equal(`
<a role="presentation" tabindex="-1" class="sbb-breadcrumb" href="/test" target="_blank" download rel="subsection">
<span class="sbb-breadcrumb__label">
<slot></slot>
<span class="sbb-breadcrumb__label--opens-in-new-window">
. Link target opens in new window.
</span>
</span>
</a>
`);
await expect(root).shadowDom.to.equalSnapshot();
});

it('renders with icon', async () => {
Expand All @@ -37,18 +28,7 @@ describe('sbb-breadcrumb', () => {
<sbb-breadcrumb dir="ltr" role="link" tabindex="0" href="/" icon-name="house-small"></sbb-breadcrumb>
`);

expect(root).shadowDom.to.be.equal(`
<a role="presentation" tabindex="-1" class="sbb-breadcrumb" href="/">
<span class="sbb-breadcrumb__icon">
<slot name="icon">
<sbb-icon name="house-small" aria-hidden="true" data-namespace="default" role="img"></sbb-icon>
</slot>
</span>
<span hidden>
<slot></slot>
</span>
</a>
`);
await expect(root).shadowDom.to.equalSnapshot();
});

it('renders with icon and text', async () => {
Expand All @@ -62,18 +42,7 @@ describe('sbb-breadcrumb', () => {
</sbb-breadcrumb>
`);

expect(root).shadowDom.to.be.equal(`
<a role="presentation" tabindex="-1" class="sbb-breadcrumb" href="/">
<span class="sbb-breadcrumb__icon">
<slot name="icon">
<sbb-icon name="house-small" aria-hidden="true" data-namespace="default" role="img"></sbb-icon>
</slot>
</span>
<span class="sbb-breadcrumb__label">
<slot></slot>
</span>
</a>
`);
await expect(root).shadowDom.to.equalSnapshot();
});

it('renders as span if no href is provided', async () => {
Expand All @@ -85,12 +54,6 @@ describe('sbb-breadcrumb', () => {
</sbb-breadcrumb>
`);

expect(root).shadowDom.to.be.equal(`
<span class="sbb-breadcrumb">
<span class="sbb-breadcrumb__label">
<slot></slot>
</span>
</span>
`);
await expect(root).shadowDom.to.equalSnapshot();
});
});
57 changes: 19 additions & 38 deletions src/components/breadcrumb/breadcrumb/breadcrumb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,13 @@ import { CSSResultGroup, LitElement, nothing, TemplateResult } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';
import { html, unsafeStatic } from 'lit/static-html.js';

import { SlotChildObserver } from '../../core/common-behaviors';
import { setAttributes } from '../../core/dom';
import {
actionElementHandlerAspect,
createNamedSlotState,
documentLanguage,
HandlerRepository,
languageChangeHandlerAspect,
namedSlotChangeHandlerAspect,
} from '../../core/eventing';
import { i18nTargetOpensInNewWindow } from '../../core/i18n';
import {
Expand All @@ -30,7 +29,7 @@ import '../../icon';
* @slot icon - Use this to display an icon as breadcrumb.
*/
@customElement('sbb-breadcrumb')
export class SbbBreadcrumb extends LitElement {
export class SbbBreadcrumb extends SlotChildObserver(LitElement) {
public static override styles: CSSResultGroup = style;

/** The href value you want to link to. */
Expand All @@ -52,9 +51,6 @@ export class SbbBreadcrumb extends LitElement {
*/
@property({ attribute: 'icon-name' }) public iconName?: string;

/** State of listed named slots, by indicating whether any element for a named slot is defined. */
@state() private _namedSlots = createNamedSlotState('icon');

@state() private _currentLanguage = documentLanguage();

@state() private _hasText = false;
Expand All @@ -63,7 +59,6 @@ export class SbbBreadcrumb extends LitElement {
this,
actionElementHandlerAspect,
languageChangeHandlerAspect((l) => (this._currentLanguage = l)),
namedSlotChangeHandlerAspect((m) => (this._namedSlots = m(this._namedSlots))),
);

public override connectedCallback(): void {
Expand All @@ -79,8 +74,9 @@ export class SbbBreadcrumb extends LitElement {
this._handlerRepository.disconnect();
}

private _onLabelSlotChange(event: Event): void {
this._hasText = (event.target as HTMLSlotElement)
protected override checkChildren(): void {
this._hasText = this.shadowRoot
.querySelector<HTMLSlotElement>('slot:not([name])')
.assignedNodes()
.some((n) => !!n.textContent?.trim());
}
Expand All @@ -96,36 +92,21 @@ export class SbbBreadcrumb extends LitElement {

/* eslint-disable lit/binding-positions */
return html`
<${unsafeStatic(TAG_NAME)} class='sbb-breadcrumb' ${spread(attributes)}>
${
this.iconName || this._namedSlots.icon
? html` <span class="sbb-breadcrumb__icon">
<slot name="icon">
${this.iconName ? html` <sbb-icon name="${this.iconName}"></sbb-icon>` : nothing}
</slot>
</span>`
: nothing
}
${
this._hasText
? html` <span class="sbb-breadcrumb__label">
<slot
@slotchange="${(event: Event): void => this._onLabelSlotChange(event)}"
></slot>
${targetsNewWindow(this)
? html` <span class="sbb-breadcrumb__label--opens-in-new-window">
. ${i18nTargetOpensInNewWindow[this._currentLanguage]}
</span>`
: nothing}
</span>`
: nothing
}
<${unsafeStatic(TAG_NAME)} class="sbb-breadcrumb" ${spread(attributes)}>
<slot name="icon">
${
this.iconName
? html`<sbb-icon name="${this.iconName}" class="sbb-breadcrumb__icon"></sbb-icon>`
: nothing
}
</slot>
<span class="sbb-breadcrumb__label" ?hidden=${!this._hasText}>
<slot></slot>
</span>
${
!this._hasText
? html` <span hidden>
<slot
@slotchange="${(event: Event): void => this._onLabelSlotChange(event)}"
></slot>
targetsNewWindow(this)
? html` <span class="sbb-breadcrumb__label--opens-in-new-window">
. ${i18nTargetOpensInNewWindow[this._currentLanguage]}
</span>`
: nothing
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/datepicker/datepicker/datepicker.e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,9 @@ describe('sbb-datepicker', () => {
}
});

it('should not touch invalid values', async () => {
it('should not touch invalid values', async function () {
// This test is flaky on Firefox, so we retry a few times.
this.retries(3);
const testCases = [
{ value: '.12.2020', interpretedAs: '.12.2020' },
{ value: '24..1995', interpretedAs: '24..1995' },
Expand Down
10 changes: 7 additions & 3 deletions src/components/link-list/__snapshots__/link-list.spec.snap.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
/* @web/test-runner snapshot v1 */
export const snapshots = {};

snapshots['sbb-link-list rendered with a slotted title'] = `<sbb-link-list
snapshots["sbb-link-list rendered with a slotted title"] =
`<sbb-link-list
orientation="vertical"
size="s"
title-level="2"
Expand Down Expand Up @@ -68,7 +69,8 @@ snapshots['sbb-link-list rendered with a slotted title'] = `<sbb-link-list
`;
/* end snapshot sbb-link-list rendered with a slotted title */

snapshots['sbb-link-list rendered with a title from properties'] = `<sbb-link-list
snapshots["sbb-link-list rendered with a title from properties"] =
`<sbb-link-list
orientation="vertical"
size="s"
title-content="Help &amp; Contact"
Expand Down Expand Up @@ -133,7 +135,8 @@ snapshots['sbb-link-list rendered with a title from properties'] = `<sbb-link-li
`;
/* end snapshot sbb-link-list rendered with a title from properties */

snapshots['sbb-link-list rendered without a title'] = `<sbb-link-list
snapshots["sbb-link-list rendered without a title"] =
`<sbb-link-list
orientation="vertical"
size="s"
>
Expand Down Expand Up @@ -195,3 +198,4 @@ snapshots['sbb-link-list rendered without a title'] = `<sbb-link-list
</sbb-link-list>
`;
/* end snapshot sbb-link-list rendered without a title */

Loading

0 comments on commit e38ee8a

Please sign in to comment.