From e38ee8a183ca078b0ee1998674084e5026f660d8 Mon Sep 17 00:00:00 2001 From: Jeri Peier Date: Thu, 23 Nov 2023 16:19:37 +0100 Subject: [PATCH] refactor(sbb-breadcrumb): support SSR and hydration (#2224) --- .eslintignore | 5 +- .prettierignore | 1 + package.json | 2 +- .../__snapshots__/breadcrumb.spec.snap.js | 91 +++++++++++++++++++ .../breadcrumb/breadcrumb/breadcrumb.scss | 14 +-- .../breadcrumb/breadcrumb/breadcrumb.spec.ts | 45 +-------- .../breadcrumb/breadcrumb/breadcrumb.ts | 57 ++++-------- .../datepicker/datepicker/datepicker.e2e.ts | 4 +- .../__snapshots__/link-list.spec.snap.js | 10 +- .../menu/menu/__snapshots__/menu.spec.snap.js | 67 +++++++------- .../train-formation.spec.snap.js | 51 ++++++----- 11 files changed, 196 insertions(+), 151 deletions(-) create mode 100644 src/components/breadcrumb/breadcrumb/__snapshots__/breadcrumb.spec.snap.js diff --git a/.eslintignore b/.eslintignore index 856bb61f3f..88155ca4e6 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,9 +1,6 @@ dist/ -loader/ -hydrate/ -src/components.d.ts -www/ tools/generate-component/boilerplate/ +**/__snapshots__/ # not ignored folders/files !.github/ diff --git a/.prettierignore b/.prettierignore index 03f6318114..fa24d82f35 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,5 +1,6 @@ coverage dist +**/__snapshots__ # needed for apexes in `HTMLElementTagNameMap`, which otherwise would be stripped tools/generate-component/boilerplate/component.ts diff --git a/package.json b/package.json index 72b12d2912..798984e5d6 100644 --- a/package.json +++ b/package.json @@ -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" }, diff --git a/src/components/breadcrumb/breadcrumb/__snapshots__/breadcrumb.spec.snap.js b/src/components/breadcrumb/breadcrumb/__snapshots__/breadcrumb.spec.snap.js new file mode 100644 index 0000000000..9de65f093b --- /dev/null +++ b/src/components/breadcrumb/breadcrumb/__snapshots__/breadcrumb.spec.snap.js @@ -0,0 +1,91 @@ +/* @web/test-runner snapshot v1 */ +export const snapshots = {}; + +snapshots["sbb-breadcrumb renders with text"] = +` + + + + + + + + . Link target opens in new window. + + +`; +/* end snapshot sbb-breadcrumb renders with text */ + +snapshots["sbb-breadcrumb renders with icon"] = +` + + + + + +`; +/* end snapshot sbb-breadcrumb renders with icon */ + +snapshots["sbb-breadcrumb renders with icon and text"] = +` + + + + + + + + +`; +/* end snapshot sbb-breadcrumb renders with icon and text */ + +snapshots["sbb-breadcrumb renders as span if no href is provided"] = +` + + + + + + + +`; +/* end snapshot sbb-breadcrumb renders as span if no href is provided */ + diff --git a/src/components/breadcrumb/breadcrumb/breadcrumb.scss b/src/components/breadcrumb/breadcrumb/breadcrumb.scss index 82af5070af..dcb24c0cb2 100644 --- a/src/components/breadcrumb/breadcrumb/breadcrumb.scss +++ b/src/components/breadcrumb/breadcrumb/breadcrumb.scss @@ -43,13 +43,6 @@ } } -.sbb-breadcrumb__icon { - display: flex; - flex-shrink: 0; - cursor: pointer; - color: var(--sbb-breadcrumb-color); -} - .sbb-breadcrumb__label { @include sbb.ellipsis; } @@ -57,3 +50,10 @@ .sbb-breadcrumb__label--opens-in-new-window { @include sbb.screen-reader-only; } + +.sbb-breadcrumb__icon, +::slotted(*) { + slot[name='icon'] & { + flex-shrink: 0; + } +} diff --git a/src/components/breadcrumb/breadcrumb/breadcrumb.spec.ts b/src/components/breadcrumb/breadcrumb/breadcrumb.spec.ts index e6c197897d..1b2c9bbf16 100644 --- a/src/components/breadcrumb/breadcrumb/breadcrumb.spec.ts +++ b/src/components/breadcrumb/breadcrumb/breadcrumb.spec.ts @@ -16,16 +16,7 @@ describe('sbb-breadcrumb', () => { `); - expect(root).shadowDom.to.be.equal(` - - - - - . Link target opens in new window. - - - - `); + await expect(root).shadowDom.to.equalSnapshot(); }); it('renders with icon', async () => { @@ -37,18 +28,7 @@ describe('sbb-breadcrumb', () => { `); - expect(root).shadowDom.to.be.equal(` - - - - - - - - - `); + await expect(root).shadowDom.to.equalSnapshot(); }); it('renders with icon and text', async () => { @@ -62,18 +42,7 @@ describe('sbb-breadcrumb', () => { `); - expect(root).shadowDom.to.be.equal(` - - - - - - - - - - - `); + await expect(root).shadowDom.to.equalSnapshot(); }); it('renders as span if no href is provided', async () => { @@ -85,12 +54,6 @@ describe('sbb-breadcrumb', () => { `); - expect(root).shadowDom.to.be.equal(` - - - - - - `); + await expect(root).shadowDom.to.equalSnapshot(); }); }); diff --git a/src/components/breadcrumb/breadcrumb/breadcrumb.ts b/src/components/breadcrumb/breadcrumb/breadcrumb.ts index 3ca9b1bfe7..1237777427 100644 --- a/src/components/breadcrumb/breadcrumb/breadcrumb.ts +++ b/src/components/breadcrumb/breadcrumb/breadcrumb.ts @@ -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 { @@ -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. */ @@ -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; @@ -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 { @@ -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('slot:not([name])') .assignedNodes() .some((n) => !!n.textContent?.trim()); } @@ -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` - - ${this.iconName ? html` ` : nothing} - - ` - : nothing - } - ${ - this._hasText - ? html` - - ${targetsNewWindow(this) - ? html` - . ${i18nTargetOpensInNewWindow[this._currentLanguage]} - ` - : nothing} - ` - : nothing - } + <${unsafeStatic(TAG_NAME)} class="sbb-breadcrumb" ${spread(attributes)}> + + ${ + this.iconName + ? html`` + : nothing + } + + + + ${ - !this._hasText - ? html`