Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
42 changes: 42 additions & 0 deletions libs/design/src/core/breakpoints/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Breakpoints

Breakpoints provides utilities for observing and reacting to viewport size changes.

## Overview

It provides a set of standardized, mobile-first `min-width` media query strings for building responsive layouts with Angular CDK's [`BreakpointObserver`](https://material.angular.io/cdk/layout/overview#breakpointobserver). It includes a server-safe observer that gracefully handles server-side rendering (SSR) by substituting a noop implementation on the server.

## Breakpoint map

The `DaffBreakpoints` enum maps common device viewport widths to CSS media query strings. Each value targets a `min-width` threshold, so styles cascade upward from smaller screens to larger ones.

| Breakpoint | Min Width |
|---|---|
| `MOBILE` | 480px |
| `TABLET` | 768px |
| `BIG_TABLET` | 1024px |
| `SMALL_LAPTOP` | 1200px |
| `LAPTOP` | 1440px |
| `DESKTOP` | 1920px |

## Server-safe observer

`SERVER_SAFE_BREAKPOINT_OBSERVER` is an injection token that resolves to Angular CDK's [`BreakpointObserver`](https://material.angular.io/cdk/layout/overview#breakpointobserver) in the browser and a `NoopBreakpointObserver` on the server, preventing SSR errors when observing breakpoints.

## Usage

```ts
import {
SERVER_SAFE_BREAKPOINT_OBSERVER,
DaffBreakpoints
} from '@daffodil/design';

@Component({ ... })
export class MyComponent {
private breakpointObserver = inject(SERVER_SAFE_BREAKPOINT_OBSERVER);

isBigTablet$ = this.breakpointObserver
.observe(DaffBreakpoints.BIG_TABLET)
.pipe(map((result) => result.matches));
}
```
9 changes: 9 additions & 0 deletions libs/design/src/core/breakpoints/breakpoints.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,17 @@
/**
* Sensible breakpoints for layouts and interfaces used across `@daffodil/design` components.
*/
export enum DaffBreakpoints {
/** `min-width: 1920px` */
DESKTOP = '(min-width: 1920px)',
/** `min-width: 1440px` */
LAPTOP = '(min-width: 1440px)',
/** `min-width: 1200px` */
SMALL_LAPTOP = '(min-width: 1200px)',
/** `min-width: 1024px` */
BIG_TABLET = '(min-width: 1024px)',
/** `min-width: 768px` */
TABLET = '(min-width: 768px)',
/** `min-width: 480px` */
MOBILE = '(min-width: 480px)',
}
15 changes: 14 additions & 1 deletion libs/design/src/core/breakpoints/noop.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,30 @@ import {
} from 'rxjs';

/**
* A stubbed out breakpoint observer service.
* A no-op implementation of Angular CDK's `BreakpointObserver` that always reports
* no breakpoints as matched. Useful for server-side rendering or testing contexts
* where browser layout APIs are unavailable.
*/
@Injectable({
providedIn: 'root',
})
export class NoopBreakpointObserver implements Omit<BreakpointObserver, never> {
/**
* @docs-private
*/
// eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method, @angular-eslint/use-lifecycle-interface
ngOnDestroy(): void {}

/**
* Always returns `false`, indicating that none of the given media queries are active.
*/
isMatched(value: string | readonly string[]): boolean {
return false;
}

/**
* Returns an observable that never emits a `BreakpointState`, making breakpoint-dependent logic inert.
*/
observe(value: string | readonly string[]): Observable<BreakpointState> {
return of();
}
Expand Down
Loading