Skip to content

Commit 19b3dc3

Browse files
authored
feat: allow to use signals to get breakpoints (#2)
1 parent 4089c81 commit 19b3dc3

File tree

6 files changed

+57
-28
lines changed

6 files changed

+57
-28
lines changed

libs/ngx-breakpoint-observer/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@
55
export * from './lib/breakpoints';
66
export * from './lib/observe-breakpoints';
77
export * from './lib/observe-media-query';
8+
export * from './lib/types';

libs/ngx-breakpoint-observer/src/lib/observe-breakpoints.ts

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import { computed, type Signal } from '@angular/core';
22
import { Breakpoints } from './breakpoints';
3-
import { increaseWithUnit } from './increase-with-unit';
3+
import { increaseWithUnit } from './utils/increase-with-unit';
44
import { observeMediaQuery } from './observe-media-query';
5+
import { toValue } from './utils/to-value';
6+
import { MaybeSignalOrGetter } from './types';
57

68
/**
79
* Reactive viewport breakpoints
@@ -11,8 +13,8 @@ import { observeMediaQuery } from './observe-media-query';
1113
export function observeBreakpoints<K extends string>(
1214
breakpoints: Breakpoints<K>
1315
) {
14-
function getValue(k: K, delta?: number): string {
15-
let v = breakpoints[k];
16+
function getValue(k: MaybeSignalOrGetter<K>, delta?: number): string {
17+
let v = breakpoints[toValue(k)];
1618

1719
if (delta !== null && delta !== undefined) {
1820
v = increaseWithUnit(v, delta);
@@ -31,8 +33,8 @@ export function observeBreakpoints<K extends string>(
3133
return window.matchMedia(query).matches;
3234
}
3335

34-
const greaterOrEqual = (k: K): Signal<boolean> => {
35-
return observeMediaQuery(`(min-width: ${getValue(k)})`);
36+
const greaterOrEqual = (k: MaybeSignalOrGetter<K>): Signal<boolean> => {
37+
return observeMediaQuery(() => `(min-width: ${getValue(k)})`);
3638
};
3739

3840
const shortcutMethods = Object.keys(breakpoints).reduce((shortcuts, k) => {
@@ -45,34 +47,35 @@ export function observeBreakpoints<K extends string>(
4547
}, {} as Record<K, Signal<boolean>>);
4648

4749
return Object.assign(shortcutMethods, {
48-
greater(k: K) {
49-
return observeMediaQuery(`(min-width: ${getValue(k, 0.1)})`);
50+
greater(k: MaybeSignalOrGetter<K>) {
51+
return observeMediaQuery(() => `(min-width: ${getValue(k, 0.1)})`);
5052
},
5153
greaterOrEqual,
52-
smaller(k: K) {
53-
return observeMediaQuery(`(max-width: ${getValue(k, -0.1)})`);
54+
smaller(k: MaybeSignalOrGetter<K>) {
55+
return observeMediaQuery(() => `(max-width: ${getValue(k, -0.1)})`);
5456
},
55-
smallerOrEqual(k: K) {
56-
return observeMediaQuery(`(max-width: ${getValue(k)})`);
57+
smallerOrEqual(k: MaybeSignalOrGetter<K>) {
58+
return observeMediaQuery(() => `(max-width: ${getValue(k)})`);
5759
},
58-
between(a: K, b: K) {
60+
between(a: MaybeSignalOrGetter<K>, b: MaybeSignalOrGetter<K>) {
5961
return observeMediaQuery(
60-
`(min-width: ${getValue(a)}) and (max-width: ${getValue(b, -0.1)})`
62+
() =>
63+
`(min-width: ${getValue(a)}) and (max-width: ${getValue(b, -0.1)})`
6164
);
6265
},
63-
isGreater(k: K) {
66+
isGreater(k: MaybeSignalOrGetter<K>) {
6467
return match(`(min-width: ${getValue(k, 0.1)})`);
6568
},
66-
isGreaterOrEqual(k: K) {
69+
isGreaterOrEqual(k: MaybeSignalOrGetter<K>) {
6770
return match(`(min-width: ${getValue(k)})`);
6871
},
69-
isSmaller(k: K) {
72+
isSmaller(k: MaybeSignalOrGetter<K>) {
7073
return match(`(max-width: ${getValue(k, -0.1)})`);
7174
},
72-
isSmallerOrEqual(k: K) {
75+
isSmallerOrEqual(k: MaybeSignalOrGetter<K>) {
7376
return match(`(max-width: ${getValue(k)})`);
7477
},
75-
isInBetween(a: K, b: K) {
78+
isInBetween(a: MaybeSignalOrGetter<K>, b: MaybeSignalOrGetter<K>) {
7679
return match(
7780
`(min-width: ${getValue(a)}) and (max-width: ${getValue(b, -0.1)})`
7881
);

libs/ngx-breakpoint-observer/src/lib/observe-media-query.ts

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,46 @@
11
import { effect, type Signal, signal, untracked } from '@angular/core';
2+
import { toValue } from './utils/to-value';
3+
import { MaybeSignalOrGetter } from './types';
24

35
/**
46
* Reactive Media Query.
57
*
68
* @param query
79
*/
8-
export function observeMediaQuery(query: string): Signal<boolean> {
10+
export function observeMediaQuery(
11+
query: MaybeSignalOrGetter<string>
12+
): Signal<boolean> {
913
const isSupported =
1014
window && 'matchMedia' in window && typeof window.matchMedia === 'function';
1115

1216
let mediaQuery: MediaQueryList | undefined;
1317
const matches = signal(false);
1418

19+
const handler = (event: MediaQueryListEvent) => {
20+
matches.set(event.matches);
21+
};
22+
1523
const cleanup = () => {
1624
if (!mediaQuery) return;
17-
mediaQuery.removeEventListener('change', update);
25+
26+
if ('removeEventListener' in mediaQuery)
27+
mediaQuery.removeEventListener('change', handler);
28+
// @ts-expect-error deprecated API
29+
else mediaQuery.removeListener(handler);
1830
};
1931

20-
const update = () => {
32+
effect(onCleanup => {
2133
if (!isSupported) return;
22-
mediaQuery = window.matchMedia(query);
23-
untracked(() => matches.set(!!mediaQuery?.matches));
2434

25-
if (!mediaQuery) return;
26-
mediaQuery.addEventListener('change', update);
27-
};
35+
mediaQuery = window.matchMedia(toValue(query));
36+
37+
if ('addEventListener' in mediaQuery)
38+
mediaQuery.addEventListener('change', handler);
39+
// @ts-expect-error deprecated API
40+
else mediaQuery.addListener(handler);
41+
42+
untracked(() => matches.set(!!mediaQuery?.matches));
2843

29-
effect(onCleanup => {
30-
update();
3144
onCleanup(cleanup);
3245
});
3346

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import { Signal } from '@angular/core';
2+
3+
export type MaybeSignalOrGetter<T> = T | Signal<T> | (() => T);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { Signal } from '@angular/core';
2+
import { MaybeSignalOrGetter } from '../types';
3+
4+
/**
5+
* Get the value of value/signal/getter.
6+
*/
7+
export function toValue<T>(r: MaybeSignalOrGetter<T>): T {
8+
return typeof r === 'function' ? (r as any)() : r;
9+
}

0 commit comments

Comments
 (0)