Skip to content

Commit

Permalink
fix: fix issues with server side rendering for consumers
Browse files Browse the repository at this point in the history
  • Loading branch information
kyubisation committed Nov 17, 2023
1 parent 1500005 commit 636163e
Show file tree
Hide file tree
Showing 14 changed files with 55 additions and 38 deletions.
4 changes: 2 additions & 2 deletions src/components/calendar/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { isArrowKeyOrPageKeysPressed, sbbInputModalityDetector } from '../core/a
import {
DateAdapter,
DAYS_PER_ROW,
defaultDateAdapter,
MONTHS_PER_ROW,
NativeDateAdapter,
YEARS_PER_PAGE,
YEARS_PER_ROW,
} from '../core/datetime';
Expand Down Expand Up @@ -132,7 +132,7 @@ export class SbbCalendar extends LitElement {

private _nextCalendarView: CalendarView = 'day';

private _dateAdapter: DateAdapter<Date> = new NativeDateAdapter();
private _dateAdapter: DateAdapter<Date> = defaultDateAdapter;

/** A list of days, in two formats (long and single char). */
private _weekdays: Weekday[];
Expand Down
9 changes: 6 additions & 3 deletions src/components/core/a11y/input-modality-detector.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// This implementation is inspired by https://github.com/angular/components/blob/main/src/cdk/a11y/input-modality/input-modality-detector.ts

import { isBrowser } from '../dom';
import { getEventTarget } from '../eventing';

import {
Expand Down Expand Up @@ -165,9 +166,11 @@ class SbbInputModalityDetector {
};

public constructor() {
document.addEventListener('keydown', this._onKeydown, modalityEventListenerOptions);
document.addEventListener('mousedown', this._onMousedown, modalityEventListenerOptions);
document.addEventListener('touchstart', this._onTouchstart, modalityEventListenerOptions);
if (isBrowser()) {
document.addEventListener('keydown', this._onKeydown, modalityEventListenerOptions);
document.addEventListener('mousedown', this._onMousedown, modalityEventListenerOptions);
document.addEventListener('touchstart', this._onTouchstart, modalityEventListenerOptions);
}
}
}

Expand Down
1 change: 1 addition & 0 deletions src/components/core/a11y/interactivity-checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class InteractivityCheckerMock implements InterfaceInteractivityChecker {
// For unit tests we need to pretend that an element is always visible.
// This can be done by checking if visibility property is set to empty.
export const interactivityChecker: InterfaceInteractivityChecker =
typeof getComputedStyle === 'undefined' ||
getComputedStyle(document.documentElement).visibility === ''
? new InteractivityCheckerMock()
: new InteractivityChecker();
11 changes: 5 additions & 6 deletions src/components/core/config/config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DateAdapter, NativeDateAdapter } from '../datetime';
import type { DateAdapter } from '../datetime';

export interface SbbIconConfig {
interceptor?: (parameters: {
Expand All @@ -11,19 +11,18 @@ export interface SbbIconConfig {
}

export interface SbbDatetimeConfig {
dateAdapter: DateAdapter;
dateAdapter?: DateAdapter;
}

export interface SbbConfig {
language?: string;
icon?: SbbIconConfig;
datetime: SbbDatetimeConfig;
datetime?: SbbDatetimeConfig;
}

export function readConfig(): SbbConfig {
if (!('sbbConfig' in globalThis)) {
globalThis.sbbConfig = {
datetime: { dateAdapter: new NativeDateAdapter() },
};
globalThis.sbbConfig = {};
}
return globalThis.sbbConfig as SbbConfig;
}
Expand Down
2 changes: 2 additions & 0 deletions src/components/core/datetime/native-date-adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,3 +319,5 @@ export class NativeDateAdapter implements DateAdapter<Date> {
return result;
}
}

export const defaultDateAdapter = new NativeDateAdapter();
4 changes: 3 additions & 1 deletion src/components/core/dom/get-document-writing-mode.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
import { isBrowser } from './platform';

export const getDocumentWritingMode = (): string =>
document.querySelector('html').getAttribute('dir') || 'ltr';
(isBrowser() && document.documentElement.getAttribute('dir')) || 'ltr';
12 changes: 9 additions & 3 deletions src/components/core/eventing/language-change-handler.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { readConfig } from '../config';
import { isBrowser } from '../dom';
import { AgnosticMutationObserver } from '../observers';

import { HandlerAspect } from './handler-repository';
Expand All @@ -15,15 +17,19 @@ declare global {
}

/**
* Extracts `lang` attribute from `<html>` tag. If language is not supported, fall back to English.
* Extracts language from the configuration or from the `lang` attribute from `<html>` tag.
* If language is not supported, fall back to English.
* If lang attribute contains the country, it will be stripped away.
*/
export const documentLanguage = (): string => {
const fallbackLanguage = 'en';
const langAttribute = document.documentElement.getAttribute('lang') || fallbackLanguage;
const language =
(readConfig().language ??
(isBrowser() ? document.documentElement.getAttribute('lang') : fallbackLanguage)) ||
fallbackLanguage;

// Support e.g. cases like `de-ch`.
const langAttributeNormalized = langAttribute.split('-')[0];
const langAttributeNormalized = language.split('-')[0];

if (!['en', 'de', 'fr', 'it'].includes(langAttributeNormalized)) {
return fallbackLanguage;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CSSResultGroup, LitElement, PropertyValues, TemplateResult, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';

import { DateAdapter, NativeDateAdapter } from '../../core/datetime';
import { DateAdapter, defaultDateAdapter } from '../../core/datetime';
import { isValidAttribute, setAttribute, setAttributes, toggleDatasetEntry } from '../../core/dom';
import {
ConnectedAbortController,
Expand All @@ -14,7 +14,7 @@ import { i18nNextDay, i18nSelectNextDay, i18nToday } from '../../core/i18n';
import { resolveButtonRenderVariables } from '../../core/interfaces';
import {
InputUpdateEvent,
datepickerControlRegisteredEvent,
datepickerControlRegisteredEventFactory,
findNextAvailableDate,
getDatePicker,
type SbbDatepicker,
Expand Down Expand Up @@ -62,7 +62,7 @@ export class SbbDatepickerNextDay extends LitElement {

private _datePickerElement: SbbDatepicker;

private _dateAdapter: DateAdapter<Date> = new NativeDateAdapter();
private _dateAdapter: DateAdapter<Date> = defaultDateAdapter;

private _datePickerController: AbortController;

Expand Down Expand Up @@ -169,7 +169,7 @@ export class SbbDatepickerNextDay extends LitElement {
{ signal: this._datePickerController.signal },
);

this._datePickerElement.dispatchEvent(datepickerControlRegisteredEvent);
this._datePickerElement.dispatchEvent(datepickerControlRegisteredEventFactory());
}

private _setDisabledState(datepicker: SbbDatepicker): void {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CSSResultGroup, LitElement, PropertyValues, TemplateResult, html } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';

import { DateAdapter, NativeDateAdapter } from '../../core/datetime';
import { DateAdapter, defaultDateAdapter } from '../../core/datetime';
import { isValidAttribute, setAttribute, setAttributes, toggleDatasetEntry } from '../../core/dom';
import {
ConnectedAbortController,
Expand All @@ -14,7 +14,7 @@ import { i18nPreviousDay, i18nSelectPreviousDay, i18nToday } from '../../core/i1
import { resolveButtonRenderVariables } from '../../core/interfaces';
import {
InputUpdateEvent,
datepickerControlRegisteredEvent,
datepickerControlRegisteredEventFactory,
findPreviousAvailableDate,
getDatePicker,
type SbbDatepicker,
Expand Down Expand Up @@ -62,7 +62,7 @@ export class SbbDatepickerPreviousDay extends LitElement {

private _datePickerElement: SbbDatepicker;

private _dateAdapter: DateAdapter<Date> = new NativeDateAdapter();
private _dateAdapter: DateAdapter<Date> = defaultDateAdapter;

private _datePickerController: AbortController;

Expand Down Expand Up @@ -169,7 +169,7 @@ export class SbbDatepickerPreviousDay extends LitElement {
{ signal: this._datePickerController.signal },
);

this._datePickerElement.dispatchEvent(datepickerControlRegisteredEvent);
this._datePickerElement.dispatchEvent(datepickerControlRegisteredEventFactory());
}

private _setDisabledState(datepicker: SbbDatepicker): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { i18nShowCalendar } from '../../core/i18n';
import type { SbbTooltip, SbbTooltipTrigger } from '../../tooltip';
import {
datepickerControlRegisteredEvent,
datepickerControlRegisteredEventFactory,
getDatePicker,
InputUpdateEvent,
type SbbDatepicker,
Expand Down Expand Up @@ -144,7 +144,7 @@ export class SbbDatepickerToggle extends LitElement {
this._configureCalendar(this._calendarElement, event.target as SbbDatepicker),
{ signal: this._datePickerController.signal },
);
this._datePickerElement.dispatchEvent(datepickerControlRegisteredEvent);
this._datePickerElement.dispatchEvent(datepickerControlRegisteredEventFactory());
}

private _configureCalendar(calendar: SbbCalendar, datepicker: SbbDatepicker): void {
Expand Down
16 changes: 9 additions & 7 deletions src/components/datepicker/datepicker/datepicker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { customElement, property, state } from 'lit/decorators.js';
import { ref } from 'lit/directives/ref.js';

import { readConfig } from '../../core/config';
import { DateAdapter, NativeDateAdapter } from '../../core/datetime';
import { DateAdapter, defaultDateAdapter } from '../../core/datetime';
import {
findInput,
findReferencedElement,
Expand Down Expand Up @@ -145,7 +145,7 @@ export function isDateAvailable(
max: string | number,
): boolean {
// TODO: Get date adapter from config
const dateAdapter: DateAdapter<Date> = new NativeDateAdapter();
const dateAdapter: DateAdapter<Date> = defaultDateAdapter;
const dateMin: Date = dateAdapter.deserializeDate(min);
const dateMax: Date = dateAdapter.deserializeDate(max);

Expand All @@ -159,10 +159,11 @@ export function isDateAvailable(
return dateFilter ? dateFilter(date) : true;
}

export const datepickerControlRegisteredEvent = new CustomEvent('datepicker-control-registered', {
bubbles: false,
composed: true,
});
export const datepickerControlRegisteredEventFactory = (): CustomEvent =>
new CustomEvent('datepicker-control-registered', {
bubbles: false,
composed: true,
});

/**
* Combined with a native input, it displays the input's value as a formatted date.
Expand Down Expand Up @@ -327,7 +328,8 @@ export class SbbDatepicker extends LitElement {

private _inputObserver = new AgnosticMutationObserver(this._onInputPropertiesChange.bind(this));

private _dateAdapter: DateAdapter<Date> = readConfig().datetime.dateAdapter;
private _dateAdapter: DateAdapter<Date> =
readConfig().datetime?.dateAdapter ?? defaultDateAdapter;

private _statusContainer: HTMLParagraphElement | null;

Expand Down
8 changes: 5 additions & 3 deletions src/components/header/header/header.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { CSSResultGroup, html, LitElement, TemplateResult } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';

import { findReferencedElement, toggleDatasetEntry } from '../../core/dom';
import { findReferencedElement, isBrowser, toggleDatasetEntry } from '../../core/dom';

import style from './header.scss?lit&inline';
import '../../logo';
Expand Down Expand Up @@ -34,7 +34,7 @@ export class SbbHeader extends LitElement {
public get scrollOrigin(): string | HTMLElement | Document {
return this._scrollOrigin;
}
private _scrollOrigin: string | HTMLElement | Document = document;
private _scrollOrigin: string | HTMLElement | Document = isBrowser() ? document : null!;

/** Whether the header should hide and show on scroll. */
@property({ attribute: 'hide-on-scroll', reflect: true, type: Boolean }) public hideOnScroll =
Expand Down Expand Up @@ -75,7 +75,9 @@ export class SbbHeader extends LitElement {
/** Sets the value of `_scrollElement` and `_scrollFunction` and possibly adds the function on the correct element. */
private _setListenerOnScrollElement(scrollOrigin: string | HTMLElement | Document): void {
this._scrollEventsController = new AbortController();
this._scrollElement = findReferencedElement(scrollOrigin as string | HTMLElement) || document;
this._scrollElement =
findReferencedElement(scrollOrigin as string | HTMLElement) ||
(isBrowser() ? document : null);
this._scrollFunction = this._getScrollFunction.bind(this);
this._scrollElement?.addEventListener('scroll', this._scrollFunction, {
passive: true,
Expand Down
4 changes: 2 additions & 2 deletions src/components/journey-summary/journey-summary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { CSSResultGroup, html, LitElement, nothing, TemplateResult } from 'lit';
import { customElement, property, state } from 'lit/decorators.js';

import {
defaultDateAdapter,
durationToTime,
NativeDateAdapter,
removeTimezoneFromISOTimeString,
} from '../core/datetime';
import { documentLanguage, HandlerRepository, languageChangeHandlerAspect } from '../core/eventing';
Expand Down Expand Up @@ -86,7 +86,7 @@ export class SbbJourneySummary extends LitElement {

/** renders the date of the journey or if it is the current or next day */
private _renderJourneyStart(departureTime: Date, duration: number): TemplateResult {
const dateAdapter = new NativeDateAdapter();
const dateAdapter = defaultDateAdapter;
const durationObj = durationToTime(duration, this._currentLanguage);

if (isValid(departureTime))
Expand Down
2 changes: 1 addition & 1 deletion src/components/link-list/link-list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export class SbbLinkList extends LitElement {
@property({ reflect: true }) public orientation: SbbOrientation = 'vertical';

/** Sbb-Link elements */
@state() private _links: SbbLink[];
@state() private _links: SbbLink[] = [];

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

0 comments on commit 636163e

Please sign in to comment.