diff --git a/src/elements/calendar/calendar.ts b/src/elements/calendar/calendar.ts index 7956ed7330..5da8b91918 100644 --- a/src/elements/calendar/calendar.ts +++ b/src/elements/calendar/calendar.ts @@ -12,7 +12,11 @@ import { classMap } from 'lit/directives/class-map.js'; import { isArrowKeyOrPageKeysPressed, sbbInputModalityDetector } from '../core/a11y.js'; import { readConfig } from '../core/config.js'; -import { SbbConnectedAbortController, SbbLanguageController } from '../core/controllers.js'; +import { + SbbLanguageController, + SbbMediaMatcherController, + SbbMediaQueryBreakpointMediumAndAbove, +} from '../core/controllers.js'; import type { DateAdapter } from '../core/datetime.js'; import { DAYS_PER_ROW, @@ -22,7 +26,6 @@ import { YEARS_PER_ROW, } from '../core/datetime.js'; import { forceType } from '../core/decorators.js'; -import { isBreakpoint } from '../core/dom.js'; import { EventEmitter } from '../core/eventing.js'; import { i18nCalendarDateSelection, @@ -229,11 +232,13 @@ class SbbCalendarElement extends SbbHydrationMixin(LitElement) { @state() private accessor _initialized = false; - private _abort = new SbbConnectedAbortController(this); private _language = new SbbLanguageController(this).withHandler(() => { this._monthNames = this._dateAdapter.getMonthNames('long'); this._createMonthRows(); }); + private _mediaMatcher = new SbbMediaMatcherController(this, { + [SbbMediaQueryBreakpointMediumAndAbove]: () => this._init(), + }); public constructor() { super(); @@ -258,10 +263,6 @@ class SbbCalendarElement extends SbbHydrationMixin(LitElement) { this._resetFocus = true; this._focusCell(); }; - globalThis.window?.addEventListener('resize', () => this._init(), { - passive: true, - signal: this._abort.signal, - }); } protected override willUpdate(changedProperties: PropertyValues): void { @@ -297,7 +298,7 @@ class SbbCalendarElement extends SbbHydrationMixin(LitElement) { /** Initializes the component. */ private _init(activeDate?: T): void { - //Due to its complexity, the caledar is only initialized on client side + // Due to its complexity, the calendar is only initialized on client side if (isServer) { return; } else if (this.hydrationRequired) { @@ -308,7 +309,8 @@ class SbbCalendarElement extends SbbHydrationMixin(LitElement) { if (activeDate) { this._assignActiveDate(activeDate); } - this._wide = isBreakpoint('medium') && this.wide; + this._wide = + (this._mediaMatcher.matches(SbbMediaQueryBreakpointMediumAndAbove) ?? false) && this.wide; this._weeks = this._createWeekRows(this._activeDate); this._years = this._createYearRows(); this._nextMonthWeeks = [[]]; diff --git a/src/elements/core/controllers/media-matchers-controller.ts b/src/elements/core/controllers/media-matchers-controller.ts index f683f88c86..9febba3c72 100644 --- a/src/elements/core/controllers/media-matchers-controller.ts +++ b/src/elements/core/controllers/media-matchers-controller.ts @@ -1,12 +1,18 @@ -import { SbbBreakpointMediumMin, SbbBreakpointSmallMax } from '@sbb-esta/lyne-design-tokens'; +import { + SbbBreakpointMediumMin, + SbbBreakpointSmallMax, + SbbTypoScaleDefault, +} from '@sbb-esta/lyne-design-tokens'; import { isServer, type ReactiveController, type ReactiveControllerHost } from 'lit'; +const pxToRem = (px: number): number => px / SbbTypoScaleDefault; + /* eslint-disable @typescript-eslint/naming-convention */ export const SbbMediaQueryForcedColors = '(forced-colors: active)'; export const SbbMediaQueryHover = '(any-hover: hover)'; export const SbbMediaQueryPointerCoarse = '(pointer: coarse)'; -export const SbbMediaQueryBreakpointMediumAndAbove = `(min-width: ${SbbBreakpointMediumMin})`; -export const SbbMediaQueryBreakpointSmallAndBelow = `(max-width: ${SbbBreakpointSmallMax})`; +export const SbbMediaQueryBreakpointMediumAndAbove = `(min-width: ${pxToRem(SbbBreakpointMediumMin)}rem)`; +export const SbbMediaQueryBreakpointSmallAndBelow = `(max-width: ${pxToRem(SbbBreakpointSmallMax)}rem)`; /* eslint-enable @typescript-eslint/naming-convention */ /** diff --git a/src/elements/core/dom/breakpoint.ts b/src/elements/core/dom/breakpoint.ts index eff10e8be9..99ea4c3caf 100644 --- a/src/elements/core/dom/breakpoint.ts +++ b/src/elements/core/dom/breakpoint.ts @@ -9,16 +9,16 @@ export type Breakpoint = (typeof breakpoints)[number]; * * @param from The breakpoint corresponding to the `min-width` value of the media query (optional). * @param to The breakpoint corresponding to the `max-width` value of the media query (optional). + * @param properties Whether the max breakpoint should be included * @returns A boolean indicating whether the window matches the breakpoint. */ export function isBreakpoint( from?: Breakpoint, to?: Breakpoint, properties?: { includeMaxBreakpoint: boolean }, -): boolean { +): boolean | null { if (isServer) { - // TODO: Remove and decide case by case what should be done on consuming end - return false; + return null; } const computedStyle = getComputedStyle(document.documentElement); diff --git a/src/elements/dialog/dialog/dialog.ts b/src/elements/dialog/dialog/dialog.ts index 2bb07a6cb8..166a293d35 100644 --- a/src/elements/dialog/dialog/dialog.ts +++ b/src/elements/dialog/dialog/dialog.ts @@ -269,7 +269,7 @@ class SbbDialogElement extends SbbOverlayBaseElement { const hideHeader = typeof hideOnScroll === 'boolean' ? hideOnScroll - : isBreakpoint('zero', hideOnScroll, { includeMaxBreakpoint: true }); + : (isBreakpoint('zero', hideOnScroll, { includeMaxBreakpoint: true }) ?? false); this.toggleAttribute('data-hide-header', !hideHeader ? false : value); if (this._dialogTitleElement) { this._dialogTitleElement.toggleAttribute('data-hide-header', !hideHeader ? false : value); diff --git a/src/elements/image/image.ts b/src/elements/image/image.ts index dce9297bfc..1f561dd67c 100644 --- a/src/elements/image/image.ts +++ b/src/elements/image/image.ts @@ -127,9 +127,7 @@ const eventListenerOptions = { passive: true, }; -const pxToRem = (px: number): number => { - return px / SbbTypoScaleDefault; -}; +const pxToRem = (px: number): number => px / SbbTypoScaleDefault; const breakpointMap: Record = { 'sbb-breakpoint-zero-min': pxToRem(SbbBreakpointZeroMin), diff --git a/src/elements/menu/menu/menu.ts b/src/elements/menu/menu/menu.ts index 8819469dcf..decb424b34 100644 --- a/src/elements/menu/menu/menu.ts +++ b/src/elements/menu/menu/menu.ts @@ -12,10 +12,10 @@ import { } from '../../core/a11y.js'; import { SbbOpenCloseBaseElement } from '../../core/base-elements.js'; import { - SbbMediaQueryBreakpointSmallAndBelow, SbbConnectedAbortController, SbbInertController, SbbMediaMatcherController, + SbbMediaQueryBreakpointSmallAndBelow, } from '../../core/controllers.js'; import { forceType } from '../../core/decorators.js'; import { findReferencedElement, SbbScrollHandler } from '../../core/dom.js'; @@ -124,7 +124,7 @@ class SbbMenuElement extends SbbNamedSlotListMixin< this._setMenuPosition(); this._triggerElement?.setAttribute('aria-expanded', 'true'); - // Starting from breakpoint medium, disable scroll + // From zero to medium, disable scroll if (this._mediaMatcher.matches(SbbMediaQueryBreakpointSmallAndBelow)) { this._scrollHandler.disableScroll(); } diff --git a/src/elements/navigation/navigation-section/navigation-section.ts b/src/elements/navigation/navigation-section/navigation-section.ts index d29884153a..675a39c969 100644 --- a/src/elements/navigation/navigation-section/navigation-section.ts +++ b/src/elements/navigation/navigation-section/navigation-section.ts @@ -247,7 +247,7 @@ class SbbNavigationSectionElement extends SbbUpdateSchedulerMixin(LitElement) { } private _isZeroToLargeBreakpoint(): boolean { - return isBreakpoint('zero', 'large'); + return isBreakpoint('zero', 'large') ?? false; } // Closes the navigation on "Esc" key pressed.