ngx-mq 2.11.3 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +170 -123
- package/fesm2022/ngx-mq.mjs +465 -16
- package/fesm2022/ngx-mq.mjs.map +1 -1
- package/index.d.ts +446 -3
- package/package.json +20 -5
package/fesm2022/ngx-mq.mjs
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { InjectionToken, inject, isDevMode, signal, DestroyRef, assertInInjectionContext } from '@angular/core';
|
|
2
|
-
import { createComputed, SIGNAL } from '@angular/core/primitives/signals';
|
|
1
|
+
import { InjectionToken, inject, isDevMode, signal, DestroyRef, computed, assertInInjectionContext } from '@angular/core';
|
|
3
2
|
|
|
4
3
|
const TAILWIND_BREAKPOINTS = {
|
|
5
4
|
sm: 640,
|
|
@@ -23,11 +22,29 @@ const MATERIAL_BREAKPOINTS = {
|
|
|
23
22
|
};
|
|
24
23
|
const DEFAULT_BREAKPOINT_EPSILON = 0.02;
|
|
25
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Holds the active {@link MqBreakpoints} map. Has no default: configure it with
|
|
27
|
+
* {@link provideBreakpoints} or a preset. Inject it to read breakpoints directly.
|
|
28
|
+
*
|
|
29
|
+
* @category Injection Tokens
|
|
30
|
+
*/
|
|
26
31
|
const MQ_BREAKPOINTS = new InjectionToken('MQ_BREAKPOINTS');
|
|
32
|
+
/**
|
|
33
|
+
* Holds the epsilon used for exclusive upper bounds. Set it with
|
|
34
|
+
* {@link provideBreakpointEpsilon}; defaults to `0.02`.
|
|
35
|
+
*
|
|
36
|
+
* @category Injection Tokens
|
|
37
|
+
*/
|
|
27
38
|
const MQ_BREAKPOINT_EPSILON = new InjectionToken('MQ_BREAKPOINT_EPSILON', {
|
|
28
39
|
providedIn: 'root',
|
|
29
40
|
factory: () => DEFAULT_BREAKPOINT_EPSILON,
|
|
30
41
|
});
|
|
42
|
+
/**
|
|
43
|
+
* Holds the value query signals report during SSR. Set it with
|
|
44
|
+
* {@link provideSsrValue}; defaults to `false`.
|
|
45
|
+
*
|
|
46
|
+
* @category Injection Tokens
|
|
47
|
+
*/
|
|
31
48
|
const NGX_MQ_SSR_VALUE = new InjectionToken('NGX_MQ_SSR_VALUE', {
|
|
32
49
|
providedIn: 'root',
|
|
33
50
|
factory: () => false,
|
|
@@ -54,18 +71,22 @@ function resolveBreakpoint(bp) {
|
|
|
54
71
|
const breakpoints = assertBreakpointsProvided();
|
|
55
72
|
return assertBreakpointExists(bp.trim(), breakpoints);
|
|
56
73
|
}
|
|
74
|
+
function validateBreakpointValue(key, value) {
|
|
75
|
+
if (!Number.isFinite(value)) {
|
|
76
|
+
throw new Error(`[ngx-mq] Breakpoint "${key}" must be a finite number, got ${value}.`);
|
|
77
|
+
}
|
|
78
|
+
if (value <= 0) {
|
|
79
|
+
throw new Error(`[ngx-mq] Breakpoint "${key}" must be > 0, got ${value}.`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
57
82
|
function normalizeBreakpoints(bps) {
|
|
58
83
|
const out = {};
|
|
59
84
|
for (const [rawKey, value] of Object.entries(bps)) {
|
|
60
85
|
const key = rawKey.trim();
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (value <= 0) {
|
|
66
|
-
throw new Error(`[ngx-mq] Breakpoint "${key}" must be > 0, got ${value}.`);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
86
|
+
// Dev-only guard; the false branch never runs in production builds.
|
|
87
|
+
/* v8 ignore next */
|
|
88
|
+
if (isDevMode())
|
|
89
|
+
validateBreakpointValue(key, value);
|
|
69
90
|
out[key] = value;
|
|
70
91
|
}
|
|
71
92
|
return Object.freeze(out);
|
|
@@ -167,11 +188,7 @@ function createConsumer(query, options) {
|
|
|
167
188
|
const defaultSsrValue = inject(NGX_MQ_SSR_VALUE);
|
|
168
189
|
const effectiveSsrValue = options?.ssrValue ?? defaultSsrValue;
|
|
169
190
|
const querySignal = retainUntilDestroy(query, effectiveSsrValue);
|
|
170
|
-
|
|
171
|
-
if (isDevMode()) {
|
|
172
|
-
getter[SIGNAL].debugName = options?.debugName;
|
|
173
|
-
}
|
|
174
|
-
return getter;
|
|
191
|
+
return computed(() => querySignal(), { debugName: options?.debugName });
|
|
175
192
|
}
|
|
176
193
|
function createConsumerLabel(descriptor) {
|
|
177
194
|
return `[NgxMq Signal: ${descriptor}]`;
|
|
@@ -181,6 +198,29 @@ function normalizeQuery(value) {
|
|
|
181
198
|
return value.trim().replace(/\s+/g, ' ').toLowerCase();
|
|
182
199
|
}
|
|
183
200
|
|
|
201
|
+
/**
|
|
202
|
+
* Tracks whether the viewport width is **at or above** a breakpoint.
|
|
203
|
+
*
|
|
204
|
+
* Builds a `(min-width: <bp>px)` query from the value registered for `bp` via
|
|
205
|
+
* {@link provideBreakpoints} (or a preset like {@link provideTailwindBreakpoints}).
|
|
206
|
+
*
|
|
207
|
+
* @param bp - Name of a configured breakpoint, e.g. `'md'`.
|
|
208
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
209
|
+
* @returns A `Signal<boolean>` that is `true` while the viewport width is `>=` the breakpoint.
|
|
210
|
+
*
|
|
211
|
+
* @remarks Must be called within an Angular
|
|
212
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```ts
|
|
216
|
+
* export class LayoutComponent {
|
|
217
|
+
* readonly isDesktop = up('lg');
|
|
218
|
+
* }
|
|
219
|
+
* ```
|
|
220
|
+
*
|
|
221
|
+
* @see {@link down} and {@link between} for the complementary ranges.
|
|
222
|
+
* @category Breakpoints
|
|
223
|
+
*/
|
|
184
224
|
function up(bp, options) {
|
|
185
225
|
isDevMode() && assertInInjectionContext(up);
|
|
186
226
|
const query = normalizeQuery(`(min-width: ${resolveBreakpoint(bp)}px)`);
|
|
@@ -188,6 +228,29 @@ function up(bp, options) {
|
|
|
188
228
|
consumer.toString = () => createConsumerLabel(`up(${bp})`);
|
|
189
229
|
return consumer;
|
|
190
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Tracks whether the viewport width is **below** a breakpoint.
|
|
233
|
+
*
|
|
234
|
+
* Builds a `(max-width: <bp - epsilon>px)` query. The upper bound is **exclusive**:
|
|
235
|
+
* a small epsilon is subtracted so `down('md')` and {@link up}`('md')` never overlap.
|
|
236
|
+
*
|
|
237
|
+
* @param bp - Name of a configured breakpoint, e.g. `'md'`.
|
|
238
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
239
|
+
* @returns A `Signal<boolean>` that is `true` while the viewport width is `<` the breakpoint.
|
|
240
|
+
*
|
|
241
|
+
* @remarks Must be called within an Angular
|
|
242
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```ts
|
|
246
|
+
* export class NavComponent {
|
|
247
|
+
* readonly isMobile = down('md');
|
|
248
|
+
* }
|
|
249
|
+
* ```
|
|
250
|
+
*
|
|
251
|
+
* @see {@link provideBreakpointEpsilon} to tune the exclusive-bound epsilon.
|
|
252
|
+
* @category Breakpoints
|
|
253
|
+
*/
|
|
191
254
|
function down(bp, options) {
|
|
192
255
|
isDevMode() && assertInInjectionContext(down);
|
|
193
256
|
const query = normalizeQuery(`(max-width: ${applyMaxEpsilon(resolveBreakpoint(bp))}px)`);
|
|
@@ -195,6 +258,29 @@ function down(bp, options) {
|
|
|
195
258
|
consumer.toString = () => createConsumerLabel(`down(${bp})`);
|
|
196
259
|
return consumer;
|
|
197
260
|
}
|
|
261
|
+
/**
|
|
262
|
+
* Tracks whether the viewport width falls within the range `[minBp, maxBp)`.
|
|
263
|
+
*
|
|
264
|
+
* Combines `min-width` and `max-width` into a single query. The lower bound is
|
|
265
|
+
* inclusive and the upper bound is **exclusive** (epsilon is subtracted from `maxBp`).
|
|
266
|
+
*
|
|
267
|
+
* @param minBp - Name of the lower (inclusive) breakpoint.
|
|
268
|
+
* @param maxBp - Name of the upper (exclusive) breakpoint.
|
|
269
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
270
|
+
* @returns A `Signal<boolean>` that is `true` while the width is in `[minBp, maxBp)`.
|
|
271
|
+
*
|
|
272
|
+
* @remarks Must be called within an Angular
|
|
273
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
274
|
+
*
|
|
275
|
+
* @example
|
|
276
|
+
* ```ts
|
|
277
|
+
* export class GridComponent {
|
|
278
|
+
* readonly isTablet = between('md', 'lg');
|
|
279
|
+
* }
|
|
280
|
+
* ```
|
|
281
|
+
*
|
|
282
|
+
* @category Breakpoints
|
|
283
|
+
*/
|
|
198
284
|
function between(minBp, maxBp, options) {
|
|
199
285
|
isDevMode() && assertInInjectionContext(between);
|
|
200
286
|
const minPx = resolveBreakpoint(minBp);
|
|
@@ -204,6 +290,24 @@ function between(minBp, maxBp, options) {
|
|
|
204
290
|
consumer.toString = () => createConsumerLabel(`between(${minBp}, ${maxBp})`);
|
|
205
291
|
return consumer;
|
|
206
292
|
}
|
|
293
|
+
/**
|
|
294
|
+
* Tracks the screen orientation via the `(orientation: ...)` media feature.
|
|
295
|
+
*
|
|
296
|
+
* @param value - `'portrait'` (height `>=` width) or `'landscape'` (width `>` height).
|
|
297
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
298
|
+
* @returns A `Signal<boolean>` that is `true` while the orientation matches `value`.
|
|
299
|
+
*
|
|
300
|
+
* @remarks Must be called within an Angular
|
|
301
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
302
|
+
*
|
|
303
|
+
* @example
|
|
304
|
+
* ```ts
|
|
305
|
+
* readonly isLandscape = orientation('landscape');
|
|
306
|
+
* ```
|
|
307
|
+
*
|
|
308
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/orientation | MDN: orientation}
|
|
309
|
+
* @category Media Features
|
|
310
|
+
*/
|
|
207
311
|
function orientation(value, options) {
|
|
208
312
|
isDevMode() && assertInInjectionContext(orientation);
|
|
209
313
|
const query = normalizeQuery(`(orientation: ${value})`);
|
|
@@ -211,6 +315,24 @@ function orientation(value, options) {
|
|
|
211
315
|
consumer.toString = () => createConsumerLabel(`orientation(${value})`);
|
|
212
316
|
return consumer;
|
|
213
317
|
}
|
|
318
|
+
/**
|
|
319
|
+
* Tracks the user's preferred color scheme via `(prefers-color-scheme: ...)`.
|
|
320
|
+
*
|
|
321
|
+
* @param value - `'light'` or `'dark'`.
|
|
322
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
323
|
+
* @returns A `Signal<boolean>` that is `true` while the system scheme matches `value`.
|
|
324
|
+
*
|
|
325
|
+
* @remarks Must be called within an Angular
|
|
326
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
327
|
+
*
|
|
328
|
+
* @example
|
|
329
|
+
* ```ts
|
|
330
|
+
* readonly isDark = colorScheme('dark');
|
|
331
|
+
* ```
|
|
332
|
+
*
|
|
333
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme | MDN: prefers-color-scheme}
|
|
334
|
+
* @category Media Features
|
|
335
|
+
*/
|
|
214
336
|
function colorScheme(value, options) {
|
|
215
337
|
isDevMode() && assertInInjectionContext(colorScheme);
|
|
216
338
|
const query = normalizeQuery(`(prefers-color-scheme: ${value})`);
|
|
@@ -218,6 +340,25 @@ function colorScheme(value, options) {
|
|
|
218
340
|
consumer.toString = () => createConsumerLabel(`colorScheme(${value})`);
|
|
219
341
|
return consumer;
|
|
220
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* Tracks how the app is being displayed via the `(display-mode: ...)` feature,
|
|
345
|
+
* useful for detecting installed PWAs.
|
|
346
|
+
*
|
|
347
|
+
* @param value - One of {@link DisplayModeOption}, e.g. `'standalone'`.
|
|
348
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
349
|
+
* @returns A `Signal<boolean>` that is `true` while the display mode matches `value`.
|
|
350
|
+
*
|
|
351
|
+
* @remarks Must be called within an Angular
|
|
352
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* ```ts
|
|
356
|
+
* readonly isInstalledPwa = displayMode('standalone');
|
|
357
|
+
* ```
|
|
358
|
+
*
|
|
359
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/display-mode | MDN: display-mode}
|
|
360
|
+
* @category Media Features
|
|
361
|
+
*/
|
|
221
362
|
function displayMode(value, options) {
|
|
222
363
|
isDevMode() && assertInInjectionContext(displayMode);
|
|
223
364
|
const query = normalizeQuery(`(display-mode: ${value})`);
|
|
@@ -225,6 +366,24 @@ function displayMode(value, options) {
|
|
|
225
366
|
consumer.toString = () => createConsumerLabel(`displayMode(${value})`);
|
|
226
367
|
return consumer;
|
|
227
368
|
}
|
|
369
|
+
/**
|
|
370
|
+
* Tracks whether the user has requested reduced motion via
|
|
371
|
+
* `(prefers-reduced-motion: reduce)`.
|
|
372
|
+
*
|
|
373
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
374
|
+
* @returns A `Signal<boolean>` that is `true` while reduced motion is preferred.
|
|
375
|
+
*
|
|
376
|
+
* @remarks Must be called within an Angular
|
|
377
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
378
|
+
*
|
|
379
|
+
* @example
|
|
380
|
+
* ```ts
|
|
381
|
+
* readonly reduceMotion = reducedMotion();
|
|
382
|
+
* ```
|
|
383
|
+
*
|
|
384
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion | MDN: prefers-reduced-motion}
|
|
385
|
+
* @category Media Features
|
|
386
|
+
*/
|
|
228
387
|
function reducedMotion(options) {
|
|
229
388
|
isDevMode() && assertInInjectionContext(reducedMotion);
|
|
230
389
|
const query = normalizeQuery('(prefers-reduced-motion: reduce)');
|
|
@@ -232,6 +391,49 @@ function reducedMotion(options) {
|
|
|
232
391
|
consumer.toString = () => createConsumerLabel('reducedMotion');
|
|
233
392
|
return consumer;
|
|
234
393
|
}
|
|
394
|
+
/**
|
|
395
|
+
* Tracks the user's contrast preference via `(prefers-contrast: ...)`.
|
|
396
|
+
*
|
|
397
|
+
* @param value - `'more'`, `'less'`, `'no-preference'`, or `'custom'`.
|
|
398
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
399
|
+
* @returns A `Signal<boolean>` that is `true` while the contrast preference matches `value`.
|
|
400
|
+
*
|
|
401
|
+
* @remarks Must be called within an Angular
|
|
402
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
403
|
+
*
|
|
404
|
+
* @example
|
|
405
|
+
* ```ts
|
|
406
|
+
* readonly wantsMoreContrast = prefersContrast('more');
|
|
407
|
+
* ```
|
|
408
|
+
*
|
|
409
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast | MDN: prefers-contrast}
|
|
410
|
+
* @category Media Features
|
|
411
|
+
*/
|
|
412
|
+
function prefersContrast(value, options) {
|
|
413
|
+
isDevMode() && assertInInjectionContext(prefersContrast);
|
|
414
|
+
const query = normalizeQuery(`(prefers-contrast: ${value})`);
|
|
415
|
+
const consumer = createConsumer(query, options);
|
|
416
|
+
consumer.toString = () => createConsumerLabel(`prefersContrast(${value})`);
|
|
417
|
+
return consumer;
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Tracks whether the **primary** input device can hover via `(hover: hover)`.
|
|
421
|
+
*
|
|
422
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
423
|
+
* @returns A `Signal<boolean>` that is `true` while the primary pointer supports hover.
|
|
424
|
+
*
|
|
425
|
+
* @remarks Must be called within an Angular
|
|
426
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
427
|
+
*
|
|
428
|
+
* @example
|
|
429
|
+
* ```ts
|
|
430
|
+
* readonly canHover = hover();
|
|
431
|
+
* ```
|
|
432
|
+
*
|
|
433
|
+
* @see {@link anyHover} to test **any** available input device.
|
|
434
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover | MDN: hover}
|
|
435
|
+
* @category Media Features
|
|
436
|
+
*/
|
|
235
437
|
function hover(options) {
|
|
236
438
|
isDevMode() && assertInInjectionContext(hover);
|
|
237
439
|
const query = normalizeQuery('(hover: hover)');
|
|
@@ -239,6 +441,24 @@ function hover(options) {
|
|
|
239
441
|
consumer.toString = () => createConsumerLabel('hover');
|
|
240
442
|
return consumer;
|
|
241
443
|
}
|
|
444
|
+
/**
|
|
445
|
+
* Tracks whether **any** available input device can hover via `(any-hover: hover)`.
|
|
446
|
+
*
|
|
447
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
448
|
+
* @returns A `Signal<boolean>` that is `true` while at least one pointer supports hover.
|
|
449
|
+
*
|
|
450
|
+
* @remarks Must be called within an Angular
|
|
451
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
452
|
+
*
|
|
453
|
+
* @example
|
|
454
|
+
* ```ts
|
|
455
|
+
* readonly anyCanHover = anyHover();
|
|
456
|
+
* ```
|
|
457
|
+
*
|
|
458
|
+
* @see {@link hover} to test only the primary input device.
|
|
459
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-hover | MDN: any-hover}
|
|
460
|
+
* @category Media Features
|
|
461
|
+
*/
|
|
242
462
|
function anyHover(options) {
|
|
243
463
|
isDevMode() && assertInInjectionContext(anyHover);
|
|
244
464
|
const query = normalizeQuery('(any-hover: hover)');
|
|
@@ -246,6 +466,25 @@ function anyHover(options) {
|
|
|
246
466
|
consumer.toString = () => createConsumerLabel('anyHover');
|
|
247
467
|
return consumer;
|
|
248
468
|
}
|
|
469
|
+
/**
|
|
470
|
+
* Tracks the accuracy of the **primary** pointer via `(pointer: ...)`.
|
|
471
|
+
*
|
|
472
|
+
* @param value - `'fine'` (mouse/stylus), `'coarse'` (touch), or `'none'`.
|
|
473
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
474
|
+
* @returns A `Signal<boolean>` that is `true` while the primary pointer matches `value`.
|
|
475
|
+
*
|
|
476
|
+
* @remarks Must be called within an Angular
|
|
477
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
478
|
+
*
|
|
479
|
+
* @example
|
|
480
|
+
* ```ts
|
|
481
|
+
* readonly isTouch = pointer('coarse');
|
|
482
|
+
* ```
|
|
483
|
+
*
|
|
484
|
+
* @see {@link anyPointer} to test **any** available input device.
|
|
485
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer | MDN: pointer}
|
|
486
|
+
* @category Media Features
|
|
487
|
+
*/
|
|
249
488
|
function pointer(value, options) {
|
|
250
489
|
isDevMode() && assertInInjectionContext(pointer);
|
|
251
490
|
const query = normalizeQuery(`(pointer: ${value})`);
|
|
@@ -253,6 +492,25 @@ function pointer(value, options) {
|
|
|
253
492
|
consumer.toString = () => createConsumerLabel(`pointer(${value})`);
|
|
254
493
|
return consumer;
|
|
255
494
|
}
|
|
495
|
+
/**
|
|
496
|
+
* Tracks the accuracy of **any** available pointer via `(any-pointer: ...)`.
|
|
497
|
+
*
|
|
498
|
+
* @param value - `'fine'` (mouse/stylus), `'coarse'` (touch), or `'none'`.
|
|
499
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
500
|
+
* @returns A `Signal<boolean>` that is `true` while at least one pointer matches `value`.
|
|
501
|
+
*
|
|
502
|
+
* @remarks Must be called within an Angular
|
|
503
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
504
|
+
*
|
|
505
|
+
* @example
|
|
506
|
+
* ```ts
|
|
507
|
+
* readonly hasFinePointer = anyPointer('fine');
|
|
508
|
+
* ```
|
|
509
|
+
*
|
|
510
|
+
* @see {@link pointer} to test only the primary input device.
|
|
511
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-pointer | MDN: any-pointer}
|
|
512
|
+
* @category Media Features
|
|
513
|
+
*/
|
|
256
514
|
function anyPointer(value, options) {
|
|
257
515
|
isDevMode() && assertInInjectionContext(anyPointer);
|
|
258
516
|
const query = normalizeQuery(`(any-pointer: ${value})`);
|
|
@@ -260,6 +518,24 @@ function anyPointer(value, options) {
|
|
|
260
518
|
consumer.toString = () => createConsumerLabel(`anyPointer(${value})`);
|
|
261
519
|
return consumer;
|
|
262
520
|
}
|
|
521
|
+
/**
|
|
522
|
+
* Tracks the approximate color gamut of the display via `(color-gamut: ...)`.
|
|
523
|
+
*
|
|
524
|
+
* @param value - `'srgb'`, `'p3'`, or `'rec2020'` (ordered by increasing range).
|
|
525
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
526
|
+
* @returns A `Signal<boolean>` that is `true` while the display covers `value`.
|
|
527
|
+
*
|
|
528
|
+
* @remarks Must be called within an Angular
|
|
529
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
530
|
+
*
|
|
531
|
+
* @example
|
|
532
|
+
* ```ts
|
|
533
|
+
* readonly isWideGamut = colorGamut('p3');
|
|
534
|
+
* ```
|
|
535
|
+
*
|
|
536
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/color-gamut | MDN: color-gamut}
|
|
537
|
+
* @category Media Features
|
|
538
|
+
*/
|
|
263
539
|
function colorGamut(value, options) {
|
|
264
540
|
isDevMode() && assertInInjectionContext(colorGamut);
|
|
265
541
|
const query = normalizeQuery(`(color-gamut: ${value})`);
|
|
@@ -267,6 +543,27 @@ function colorGamut(value, options) {
|
|
|
267
543
|
consumer.toString = () => createConsumerLabel(`colorGamut(${value})`);
|
|
268
544
|
return consumer;
|
|
269
545
|
}
|
|
546
|
+
/**
|
|
547
|
+
* Tracks an arbitrary, raw CSS media query.
|
|
548
|
+
*
|
|
549
|
+
* Use this escape hatch for any feature not covered by the dedicated helpers.
|
|
550
|
+
* The query is normalized (trimmed, collapsed whitespace, lower-cased) before use.
|
|
551
|
+
*
|
|
552
|
+
* @param query - A valid CSS media query, e.g. `'(min-resolution: 2dppx)'`.
|
|
553
|
+
* @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
|
|
554
|
+
* @returns A `Signal<boolean>` that reflects the live result of the query.
|
|
555
|
+
*
|
|
556
|
+
* @remarks Must be called within an Angular
|
|
557
|
+
* [injection context](https://angular.dev/guide/di/dependency-injection-context).
|
|
558
|
+
*
|
|
559
|
+
* @example
|
|
560
|
+
* ```ts
|
|
561
|
+
* readonly isRetina = matchMediaSignal('(min-resolution: 2dppx)');
|
|
562
|
+
* ```
|
|
563
|
+
*
|
|
564
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries | MDN: CSS media queries}
|
|
565
|
+
* @category Custom Queries
|
|
566
|
+
*/
|
|
270
567
|
function matchMediaSignal(query, options) {
|
|
271
568
|
isDevMode() && assertInInjectionContext(matchMediaSignal);
|
|
272
569
|
const media = normalizeQuery(query);
|
|
@@ -275,30 +572,182 @@ function matchMediaSignal(query, options) {
|
|
|
275
572
|
return consumer;
|
|
276
573
|
}
|
|
277
574
|
|
|
575
|
+
const LABEL_RE = /^\[NgxMq Signal: (.+)]$/;
|
|
576
|
+
/** Extracts the inner descriptor from an ngx-mq signal label, or falls back to its raw toString(). */
|
|
577
|
+
function describe(condition) {
|
|
578
|
+
const raw = condition.toString();
|
|
579
|
+
const match = LABEL_RE.exec(raw);
|
|
580
|
+
return match ? match[1] : raw;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Combines boolean signals with logical **AND**.
|
|
584
|
+
*
|
|
585
|
+
* Composition happens at the signal level, so the underlying media-query
|
|
586
|
+
* listeners stay shared and are still cleaned up automatically.
|
|
587
|
+
*
|
|
588
|
+
* @param conditions - Boolean signals to combine. An empty call returns a
|
|
589
|
+
* signal that is always `true` (vacuous truth).
|
|
590
|
+
* @returns A `Signal<boolean>` that is `true` only when **every** condition is `true`.
|
|
591
|
+
*
|
|
592
|
+
* @example
|
|
593
|
+
* ```ts
|
|
594
|
+
* readonly isLandscapeDesktop = and(up('lg'), orientation('landscape'), hover());
|
|
595
|
+
* ```
|
|
596
|
+
*
|
|
597
|
+
* @see {@link or} and {@link not}.
|
|
598
|
+
* @category Combining Signals
|
|
599
|
+
*/
|
|
600
|
+
function and(...conditions) {
|
|
601
|
+
const result = computed(() => conditions.every((condition) => condition()), ...(ngDevMode ? [{ debugName: "result" }] : []));
|
|
602
|
+
result.toString = () => createConsumerLabel(`and(${conditions.map(describe).join(', ')})`);
|
|
603
|
+
return result;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Combines boolean signals with logical **OR**.
|
|
607
|
+
*
|
|
608
|
+
* Composition happens at the signal level, so the underlying media-query
|
|
609
|
+
* listeners stay shared and are still cleaned up automatically.
|
|
610
|
+
*
|
|
611
|
+
* @param conditions - Boolean signals to combine. An empty call returns a
|
|
612
|
+
* signal that is always `false`.
|
|
613
|
+
* @returns A `Signal<boolean>` that is `true` when **at least one** condition is `true`.
|
|
614
|
+
*
|
|
615
|
+
* @example
|
|
616
|
+
* ```ts
|
|
617
|
+
* readonly prefersSimpleUi = or(down('md'), reducedMotion());
|
|
618
|
+
* ```
|
|
619
|
+
*
|
|
620
|
+
* @see {@link and} and {@link not}.
|
|
621
|
+
* @category Combining Signals
|
|
622
|
+
*/
|
|
623
|
+
function or(...conditions) {
|
|
624
|
+
const result = computed(() => conditions.some((condition) => condition()), ...(ngDevMode ? [{ debugName: "result" }] : []));
|
|
625
|
+
result.toString = () => createConsumerLabel(`or(${conditions.map(describe).join(', ')})`);
|
|
626
|
+
return result;
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Negates a boolean signal.
|
|
630
|
+
*
|
|
631
|
+
* Useful for features that have no direct inverse helper, such as
|
|
632
|
+
* "devices without hover": `not(hover())`.
|
|
633
|
+
*
|
|
634
|
+
* @param condition - The boolean signal to invert.
|
|
635
|
+
* @returns A `Signal<boolean>` that is `true` when `condition` is `false`, and vice versa.
|
|
636
|
+
*
|
|
637
|
+
* @example
|
|
638
|
+
* ```ts
|
|
639
|
+
* readonly isTouchLike = not(hover());
|
|
640
|
+
* ```
|
|
641
|
+
*
|
|
642
|
+
* @see {@link and} and {@link or}.
|
|
643
|
+
* @category Combining Signals
|
|
644
|
+
*/
|
|
645
|
+
function not(condition) {
|
|
646
|
+
const result = computed(() => !condition(), ...(ngDevMode ? [{ debugName: "result" }] : []));
|
|
647
|
+
result.toString = () => createConsumerLabel(`not(${describe(condition)})`);
|
|
648
|
+
return result;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
/**
|
|
652
|
+
* Registers a custom breakpoint map, enabling {@link up}, {@link down} and {@link between}.
|
|
653
|
+
*
|
|
654
|
+
* Provide once at bootstrap, or at any injector level to scope/override breakpoints.
|
|
655
|
+
*
|
|
656
|
+
* @param bps - A {@link MqBreakpoints} map of names to minimum widths in pixels.
|
|
657
|
+
* @returns An Angular {@link Provider}.
|
|
658
|
+
*
|
|
659
|
+
* @example
|
|
660
|
+
* ```ts
|
|
661
|
+
* bootstrapApplication(AppComponent, {
|
|
662
|
+
* providers: [provideBreakpoints({ sm: 640, md: 768, lg: 1024 })],
|
|
663
|
+
* });
|
|
664
|
+
* ```
|
|
665
|
+
*
|
|
666
|
+
* @category Providers
|
|
667
|
+
*/
|
|
278
668
|
function provideBreakpoints(bps) {
|
|
279
669
|
return { provide: MQ_BREAKPOINTS, useValue: normalizeBreakpoints(bps) };
|
|
280
670
|
}
|
|
671
|
+
/**
|
|
672
|
+
* Registers the default Tailwind CSS breakpoints:
|
|
673
|
+
* `sm: 640, md: 768, lg: 1024, xl: 1280, 2xl: 1536`.
|
|
674
|
+
*
|
|
675
|
+
* @returns An Angular {@link Provider}.
|
|
676
|
+
* @category Providers
|
|
677
|
+
*/
|
|
281
678
|
function provideTailwindBreakpoints() {
|
|
282
679
|
return provideBreakpoints(TAILWIND_BREAKPOINTS);
|
|
283
680
|
}
|
|
681
|
+
/**
|
|
682
|
+
* Registers the default Bootstrap breakpoints:
|
|
683
|
+
* `sm: 576, md: 768, lg: 992, xl: 1200, xxl: 1400`.
|
|
684
|
+
*
|
|
685
|
+
* @returns An Angular {@link Provider}.
|
|
686
|
+
* @category Providers
|
|
687
|
+
*/
|
|
284
688
|
function provideBootstrapBreakpoints() {
|
|
285
689
|
return provideBreakpoints(BOOTSTRAP_BREAKPOINTS);
|
|
286
690
|
}
|
|
691
|
+
/**
|
|
692
|
+
* Registers the default Material 2 breakpoints:
|
|
693
|
+
* `sm: 600, md: 905, lg: 1240, xl: 1440`.
|
|
694
|
+
*
|
|
695
|
+
* @returns An Angular {@link Provider}.
|
|
696
|
+
* @category Providers
|
|
697
|
+
*/
|
|
287
698
|
function provideMaterialBreakpoints() {
|
|
288
699
|
return provideBreakpoints(MATERIAL_BREAKPOINTS);
|
|
289
700
|
}
|
|
701
|
+
/**
|
|
702
|
+
* Sets the epsilon subtracted from exclusive upper bounds in {@link down} and
|
|
703
|
+
* {@link between}, preventing adjacent ranges from overlapping.
|
|
704
|
+
*
|
|
705
|
+
* @param epsilon - A value in the range `(0, 1]`. Defaults to `0.02`.
|
|
706
|
+
* @returns An Angular {@link Provider}.
|
|
707
|
+
*
|
|
708
|
+
* @example
|
|
709
|
+
* ```ts
|
|
710
|
+
* provideBreakpointEpsilon(0.02);
|
|
711
|
+
* ```
|
|
712
|
+
*
|
|
713
|
+
* @category Providers
|
|
714
|
+
*/
|
|
290
715
|
function provideBreakpointEpsilon(epsilon = DEFAULT_BREAKPOINT_EPSILON) {
|
|
716
|
+
// Dev-only guard; the false branch never runs in production builds.
|
|
717
|
+
/* v8 ignore next */
|
|
291
718
|
if (isDevMode())
|
|
292
719
|
validateEpsilon(epsilon);
|
|
293
720
|
return { provide: MQ_BREAKPOINT_EPSILON, useValue: epsilon };
|
|
294
721
|
}
|
|
722
|
+
/**
|
|
723
|
+
* Sets the app-wide value query signals report during server-side rendering,
|
|
724
|
+
* where `matchMedia` is unavailable. A per-call `ssrValue` overrides this.
|
|
725
|
+
*
|
|
726
|
+
* @param value - The boolean returned by every signal on the server.
|
|
727
|
+
* @returns An Angular {@link Provider}.
|
|
728
|
+
*
|
|
729
|
+
* @example
|
|
730
|
+
* ```ts
|
|
731
|
+
* provideSsrValue(true);
|
|
732
|
+
* ```
|
|
733
|
+
*
|
|
734
|
+
* @category Providers
|
|
735
|
+
*/
|
|
295
736
|
function provideSsrValue(value) {
|
|
296
737
|
return { provide: NGX_MQ_SSR_VALUE, useValue: value };
|
|
297
738
|
}
|
|
298
739
|
|
|
740
|
+
/**
|
|
741
|
+
* @packageDocumentation
|
|
742
|
+
*
|
|
743
|
+
* @document ../guides/getting-started.md
|
|
744
|
+
* @document ../guides/ssr.md
|
|
745
|
+
* @document ../guides/recipes.md
|
|
746
|
+
*/
|
|
747
|
+
|
|
299
748
|
/**
|
|
300
749
|
* Generated bundle index. Do not edit.
|
|
301
750
|
*/
|
|
302
751
|
|
|
303
|
-
export { MQ_BREAKPOINTS, MQ_BREAKPOINT_EPSILON, NGX_MQ_SSR_VALUE, anyHover, anyPointer, between, colorGamut, colorScheme, displayMode, down, hover, matchMediaSignal, orientation, pointer, provideBootstrapBreakpoints, provideBreakpointEpsilon, provideBreakpoints, provideMaterialBreakpoints, provideSsrValue, provideTailwindBreakpoints, reducedMotion, up };
|
|
752
|
+
export { MQ_BREAKPOINTS, MQ_BREAKPOINT_EPSILON, NGX_MQ_SSR_VALUE, and, anyHover, anyPointer, between, colorGamut, colorScheme, displayMode, down, hover, matchMediaSignal, not, or, orientation, pointer, prefersContrast, provideBootstrapBreakpoints, provideBreakpointEpsilon, provideBreakpoints, provideMaterialBreakpoints, provideSsrValue, provideTailwindBreakpoints, reducedMotion, up };
|
|
304
753
|
//# sourceMappingURL=ngx-mq.mjs.map
|