ngx-mq 3.0.0 → 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/README.md CHANGED
@@ -1,12 +1,9 @@
1
1
  <p align="center">
2
- <img src="https://raw.githubusercontent.com/martsinlabs/ngx-mq/refs/heads/main/assets/logo.svg" width="140" alt="ngx-mq" />
2
+ <img src="https://raw.githubusercontent.com/martsinlabs/ngx-mq/refs/heads/main/assets/logo.svg" width="130" alt="ngx-mq logo" />
3
3
  </p>
4
4
 
5
- <h3 align="center">Signal-Powered Breakpoints &amp; Media Queries for Angular</h3>
6
-
7
- <p align="center">
8
- Reactive <code>matchMedia</code> as Angular signals. SSR-safe, zoneless-ready, and free of RxJS.
9
- </p>
5
+ <h3 align="center">Signal-powered breakpoints &amp; media queries for Angular</h3>
6
+ <br />
10
7
 
11
8
  <p align="center">
12
9
  <a href="https://github.com/martsinlabs/ngx-mq/actions/workflows/ci.yml">
@@ -29,237 +26,211 @@
29
26
  </a>
30
27
  </p>
31
28
 
32
- ---
33
-
34
- ## Features
35
-
36
- - **Signal-native**: every query is a `Signal<boolean>` that updates as the viewport changes.
37
- - **SSR-safe**: returns a configurable static value on the server, then hydrates on the client.
38
- - **Auto-cleanup**: listeners are tied to Angular's `DestroyRef`; no manual teardown.
39
- - **Efficient**: one shared `matchMedia` listener per unique query, reused across the app.
40
- - **Batteries included**: Tailwind, Bootstrap and Material breakpoint presets out of the box.
41
- - **Composable**: combine any signals with `and` / `or` / `not`.
42
- - **Tiny and tested**: ~1.9 kB gzipped, 100% line coverage.
43
-
44
- ## Why ngx-mq?
29
+ <p align="center">
30
+ <a href="https://martsinlabs.github.io/ngx-mq"><b>Documentation</b></a>
31
+ &nbsp;&nbsp;·&nbsp;&nbsp;
32
+ <a href="https://stackblitz.com/github/martsinlabs/ngx-mq-demo/tree/demo/v3"><b>Live demo</b></a>
33
+ &nbsp;&nbsp;·&nbsp;&nbsp;
34
+ <a href="#why-ngx-mq"><b>Why ngx-mq?</b></a>
35
+ </p>
45
36
 
46
- Angular's CDK ships [`BreakpointObserver`](https://material.angular.io/cdk/layout/overview), which
47
- works well but is built around RxJS and raw query strings. `ngx-mq` is designed for the signals era:
48
- templates read a value directly, there is nothing to subscribe to, and cleanup is automatic.
37
+ ---
49
38
 
50
- | | `ngx-mq` | CDK `BreakpointObserver` |
51
- | --------------------- | ------------------------------------------------- | ----------------------------------------- |
52
- | Reactivity | `Signal<boolean>` | `Observable<BreakpointState>` |
53
- | Cleanup | Automatic via `DestroyRef` | Manual (`unsubscribe` / `takeUntilDestroyed`) |
54
- | Template usage | `@if (isDesktop())` | `async` pipe or manual subscription |
55
- | Named breakpoints | Tailwind, Bootstrap, Material presets or your own | Material breakpoints or raw strings |
56
- | Media-feature helpers | `colorScheme`, `hover`, `pointer`, ... | Raw query strings |
57
- | Composition | `and` / `or` / `not` | RxJS operators |
58
- | SSR | Configurable static value | Handle it yourself |
59
- | Footprint | ~1.9 kB standalone | Part of `@angular/cdk` |
39
+ ## Overview
60
40
 
61
- If you already pull in `@angular/cdk` and live in RxJS, `BreakpointObserver` is a fine choice. If you
62
- want a signals-first, zoneless-friendly API with batteries included, reach for `ngx-mq`.
41
+ A responsive value is just a signal: read it in the template, compose it, and never wire up cleanup.
63
42
 
64
- ## Documentation
43
+ ```ts
44
+ import { Component } from '@angular/core';
45
+ import { up } from 'ngx-mq';
65
46
 
66
- - **API reference and guides:** https://martsinlabs.github.io/ngx-mq
67
- - **Live demo:** [StackBlitz](https://stackblitz.com/github/martsinlabs/ngx-mq-demo/tree/demo/v2?file=src%2Fapp%2Fapp.component.ts)
47
+ @Component({
48
+ selector: 'app-root',
49
+ template: `
50
+ @if (isDesktop()) {
51
+ <app-sidebar />
52
+ }
53
+ `,
54
+ })
55
+ export class AppComponent {
56
+ readonly isDesktop = up('lg');
57
+ }
58
+ ```
68
59
 
69
- ## Installation
60
+ - **Signal-native** so it works anywhere signals do, zoneless apps included.
61
+ - **Zero boilerplate**: no subscriptions, no `unsubscribe`, cleanup is automatic.
62
+ - **SSR-safe** with a value you control on the server.
63
+ - **Batteries included**: Tailwind, Bootstrap and Material presets, plus `and` / `or` / `not`.
64
+ - **Tiny**: ~1.9 kB gzipped, and no RxJS.
70
65
 
71
- Install the major version that matches your Angular version:
66
+ ## Install
72
67
 
73
- | Angular | Install |
74
- | ------- | ------------------ |
75
- | 20 - 22 | `npm i ngx-mq@3` |
76
- | 19 | `npm i ngx-mq@2` |
77
- | 16 - 18 | `npm i ngx-mq@1` |
68
+ ```bash
69
+ npm i ngx-mq # Angular 20-22
70
+ ```
78
71
 
79
- ## Quick start
72
+ <sub>Angular 19 -> <code>ngx-mq@2</code> &nbsp;·&nbsp; Angular 16-18 -> <code>ngx-mq@1</code></sub>
80
73
 
81
- **1. Provide a breakpoint map** at bootstrap (a custom map or a preset):
74
+ Then register your breakpoints once, at bootstrap:
82
75
 
83
76
  ```ts
84
- import { bootstrapApplication } from '@angular/platform-browser';
85
77
  import { provideBreakpoints } from 'ngx-mq';
86
- import { AppComponent } from './app/app.component';
87
78
 
88
79
  bootstrapApplication(AppComponent, {
89
80
  providers: [provideBreakpoints({ sm: 640, md: 768, lg: 1024 })],
81
+ // or a preset: provideTailwindBreakpoints() / provideBootstrapBreakpoints() / provideMaterialBreakpoints()
90
82
  });
91
83
  ```
92
84
 
93
- **2. Use the helpers** as signals inside any component:
85
+ > Call the helpers inside an [injection context](https://angular.dev/guide/di/dependency-injection-context): a component field, a constructor, or a DI factory.
86
+
87
+ ## Examples
88
+
89
+ #### Show different layouts per screen size
94
90
 
95
91
  ```ts
96
- import { Component } from '@angular/core';
97
- import { up, down, between } from 'ngx-mq';
92
+ readonly isMobile = down('md');
93
+ readonly isTablet = between('md', 'lg');
94
+ readonly isDesktop = up('lg');
95
+ ```
98
96
 
99
- @Component({
100
- selector: 'app-root',
101
- template: `
102
- @if (isDesktop()) {
103
- <app-sidebar />
104
- }
105
- `,
106
- })
107
- export class AppComponent {
108
- readonly isMobile = down('md');
109
- readonly isTablet = between('md', 'lg');
110
- readonly isDesktop = up('lg');
111
- }
97
+ #### Follow the system dark mode
98
+
99
+ ```ts
100
+ readonly prefersDark = colorScheme('dark');
112
101
  ```
113
102
 
114
- > **Tip:** Call the helpers within Angular's [injection context](https://angular.dev/guide/di/dependency-injection-context) (component fields, `inject`, factories) so their lifecycle stays in sync with the framework.
103
+ #### Drop hover styles on touch devices
104
+
105
+ ```ts
106
+ // `hover()` has no direct inverse, so compose it
107
+ readonly isTouchLike = not(hover());
108
+ ```
115
109
 
116
- ## API
110
+ #### Combine any conditions
117
111
 
118
- Every query helper returns a `Signal<boolean>` and accepts an optional `options` argument
119
- ([`CreateMediaQueryOptions`](#options)). The `options` column is omitted below for brevity.
112
+ ```ts
113
+ // Large screen, in landscape, with a hover-capable pointer
114
+ readonly isLandscapeDesktop = and(up('lg'), orientation('landscape'), hover());
120
115
 
121
- ### Configuration
116
+ // Small screens OR a reduced-motion preference
117
+ readonly prefersSimpleUi = or(down('md'), reducedMotion());
118
+ ```
122
119
 
123
- Register breakpoints once, then refer to them by name. Use a custom map or a preset:
120
+ #### Respect reduced motion
124
121
 
125
122
  ```ts
126
- import {
127
- provideBreakpoints,
128
- provideTailwindBreakpoints,
129
- provideBootstrapBreakpoints,
130
- provideMaterialBreakpoints,
131
- } from 'ngx-mq';
123
+ readonly reduceMotion = reducedMotion();
132
124
  ```
133
125
 
134
- | Preset | Breakpoints |
135
- | ----------- | ------------------------------------------------ |
136
- | Tailwind | `sm: 640, md: 768, lg: 1024, xl: 1280, 2xl: 1536` |
137
- | Bootstrap | `sm: 576, md: 768, lg: 992, xl: 1200, xxl: 1400` |
138
- | Material | `sm: 600, md: 905, lg: 1240, xl: 1440` |
126
+ #### Anything else, with a raw query
139
127
 
140
- ### Breakpoints
128
+ ```ts
129
+ readonly isRetina = matchMediaSignal('(min-resolution: 2dppx)');
130
+ ```
141
131
 
142
- | Helper | Arguments | `true` when |
143
- | --------- | ---------------- | ------------------------------------ |
144
- | `up` | `bp` | viewport width `>=` `bp` |
145
- | `down` | `bp` | viewport width `<` `bp` |
146
- | `between` | `minBp`, `maxBp` | viewport width is in `[minBp, maxBp)` |
132
+ ## Why ngx-mq?
147
133
 
148
- > **Note:** `down` and `between` upper bounds are **exclusive**: a small epsilon is subtracted
149
- > from the max so adjacent ranges (e.g. `down('md')` and `up('md')`) never overlap. Tune it with
150
- > [`provideBreakpointEpsilon`](#providers).
134
+ Angular's CDK ships [`BreakpointObserver`](https://material.angular.io/cdk/layout/overview), which works well but is built around RxJS and raw query strings. `ngx-mq` is built for the signals era: read a value in the template, subscribe to nothing, clean up automatically.
151
135
 
152
- ### Media features
136
+ | | `ngx-mq` | CDK `BreakpointObserver` |
137
+ | --------------------- | ------------------------------------------- | ------------------------------------- |
138
+ | Reactivity | `Signal<boolean>` | `Observable<BreakpointState>` |
139
+ | Cleanup | Automatic via `DestroyRef` | Manual (`takeUntilDestroyed`) |
140
+ | Named breakpoints | Tailwind / Bootstrap / Material or your own | Material breakpoints or raw strings |
141
+ | Media-feature helpers | `colorScheme`, `hover`, `pointer`, ... | Raw query strings |
142
+ | Composition | `and` / `or` / `not` | RxJS operators |
143
+ | SSR | Configurable static value | Handle it yourself |
144
+ | Footprint | ~1.9 kB standalone | Part of `@angular/cdk` |
153
145
 
154
- | Helper | Arguments | `true` when |
155
- | --------------- | ------------------------------ | ------------------------------------ |
156
- | `orientation` | `'portrait' \| 'landscape'` | the screen orientation matches |
157
- | `colorScheme` | `'light' \| 'dark'` | the system color scheme matches |
158
- | `displayMode` | `DisplayModeOption` | the display mode matches (PWA detection) |
159
- | `reducedMotion` | none | the user prefers reduced motion |
160
- | `hover` | none | the primary pointer can hover |
161
- | `anyHover` | none | any available pointer can hover |
162
- | `pointer` | `'fine' \| 'coarse' \| 'none'` | the primary pointer matches |
163
- | `anyPointer` | `'fine' \| 'coarse' \| 'none'` | any available pointer matches |
164
- | `colorGamut` | `'srgb' \| 'p3' \| 'rec2020'` | the display covers the gamut |
146
+ ## Documentation
165
147
 
166
- ### Custom queries
148
+ Spin it up in seconds on [StackBlitz](https://stackblitz.com/github/martsinlabs/ngx-mq-demo/tree/demo/v3), no setup required.
167
149
 
168
- For anything without a dedicated helper, pass a raw CSS media query:
150
+ Full API reference, guides and recipes live at **[martsinlabs.github.io/ngx-mq](https://martsinlabs.github.io/ngx-mq)**.
169
151
 
170
- ```ts
171
- import { matchMediaSignal } from 'ngx-mq';
152
+ <details>
153
+ <summary><b>API reference</b> (quick view)</summary>
172
154
 
173
- readonly isRetina = matchMediaSignal('(min-resolution: 2dppx)');
174
- ```
155
+ <br>
156
+
157
+ Every query helper returns a `Signal<boolean>` and accepts an optional `options` argument
158
+ ([`CreateMediaQueryOptions`](#options-and-types)).
175
159
 
176
- ### Composition
160
+ **Breakpoints**
177
161
 
178
- Combine boolean signals into derived ones. Combinators work at the signal level, so the underlying
179
- listeners stay shared and are still cleaned up automatically.
162
+ | Helper | Arguments | `true` when |
163
+ | --------- | ---------------- | ------------------------------------ |
164
+ | `up` | `bp` | viewport width `>=` `bp` |
165
+ | `down` | `bp` | viewport width `<` `bp` (exclusive) |
166
+ | `between` | `minBp`, `maxBp` | viewport width is in `[minBp, maxBp)` |
180
167
 
181
- | Helper | Arguments | `true` when |
182
- | ------ | ---------------------------------- | ------------------------------------------ |
183
- | `and` | `...conditions: Signal<boolean>[]` | every condition is `true` (empty: `true`) |
184
- | `or` | `...conditions: Signal<boolean>[]` | any condition is `true` (empty: `false`) |
185
- | `not` | `condition: Signal<boolean>` | the condition is `false` |
168
+ `down` and `between` upper bounds are exclusive: a small epsilon (default `0.02`, set via `provideBreakpointEpsilon`) is subtracted from the max so adjacent ranges never overlap.
186
169
 
187
- ```ts
188
- import { and, or, not, up, down, hover, orientation, reducedMotion } from 'ngx-mq';
170
+ **Media features**
189
171
 
190
- // Large screen, in landscape, with a hover-capable pointer
191
- readonly isLandscapeDesktop = and(up('lg'), orientation('landscape'), hover());
172
+ | Helper | Arguments | `true` when |
173
+ | --------------- | ------------------------------ | ---------------------------------------- |
174
+ | `orientation` | `'portrait' \| 'landscape'` | the screen orientation matches |
175
+ | `colorScheme` | `'light' \| 'dark'` | the system color scheme matches |
176
+ | `displayMode` | `DisplayModeOption` | the display mode matches (PWA detection) |
177
+ | `reducedMotion` | none | the user prefers reduced motion |
178
+ | `prefersContrast` | `'more' \| 'less' \| 'no-preference' \| 'custom'` | the user's contrast preference matches |
179
+ | `hover` | none | the primary pointer can hover |
180
+ | `anyHover` | none | any available pointer can hover |
181
+ | `pointer` | `'fine' \| 'coarse' \| 'none'` | the primary pointer matches |
182
+ | `anyPointer` | `'fine' \| 'coarse' \| 'none'` | any available pointer matches |
183
+ | `colorGamut` | `'srgb' \| 'p3' \| 'rec2020'` | the display covers the gamut |
192
184
 
193
- // Small screens OR a reduced-motion preference
194
- readonly prefersSimpleUi = or(down('md'), reducedMotion());
185
+ **Composition**
195
186
 
196
- // Devices without hover (touch-like): `hover()` has no direct inverse helper
197
- readonly isTouchLike = not(hover());
198
- ```
187
+ | Helper | Arguments | `true` when |
188
+ | ------ | ---------------------------------- | ----------------------------------------- |
189
+ | `and` | `...conditions: Signal<boolean>[]` | every condition is `true` (empty: `true`) |
190
+ | `or` | `...conditions: Signal<boolean>[]` | any condition is `true` (empty: `false`) |
191
+ | `not` | `condition: Signal<boolean>` | the condition is `false` |
199
192
 
200
- ### Providers
193
+ **Custom queries**
201
194
 
202
- Each returns a standard Angular `Provider` you can register at any injector level.
195
+ | Helper | Arguments | Description |
196
+ | ------------------ | --------------- | -------------------------------------------- |
197
+ | `matchMediaSignal` | `query: string` | A signal for any raw CSS media query |
203
198
 
204
- | Provider | Argument | Description |
205
- | ------------------------------- | -------------------- | ----------------------------------------------------- |
206
- | `provideBreakpoints` | `bps: MqBreakpoints` | Registers a custom breakpoint map. |
207
- | `provideTailwindBreakpoints` | none | Registers the Tailwind preset. |
208
- | `provideBootstrapBreakpoints` | none | Registers the Bootstrap preset. |
209
- | `provideMaterialBreakpoints` | none | Registers the Material 2 preset. |
210
- | `provideBreakpointEpsilon` | `epsilon: number` | Sets the exclusive-bound epsilon (default `0.02`). |
211
- | `provideSsrValue` | `value: boolean` | Sets the value signals report during SSR (default `false`). |
199
+ **Providers**
212
200
 
213
- > **Tip:** To register these as environment providers, wrap them with
214
- > [`makeEnvironmentProviders`](https://angular.dev/api/core/makeEnvironmentProviders).
201
+ | Provider | Argument | Description |
202
+ | ----------------------------- | -------------------- | ------------------------------------------------------- |
203
+ | `provideBreakpoints` | `bps: MqBreakpoints` | Registers a custom breakpoint map |
204
+ | `provideTailwindBreakpoints` | none | Registers the Tailwind preset |
205
+ | `provideBootstrapBreakpoints` | none | Registers the Bootstrap preset |
206
+ | `provideMaterialBreakpoints` | none | Registers the Material 2 preset |
207
+ | `provideBreakpointEpsilon` | `epsilon: number` | Sets the exclusive-bound epsilon (default `0.02`) |
208
+ | `provideSsrValue` | `value: boolean` | Sets the value signals report during SSR (default `false`) |
215
209
 
216
- ### Options
210
+ **Options and types**
217
211
 
218
212
  ```ts
219
213
  interface CreateMediaQueryOptions {
220
- /** Value the signal reports during SSR. Overrides the app-wide `provideSsrValue`. */
221
- ssrValue?: boolean;
222
- /** Debug name shown for the signal in Angular DevTools. */
223
- debugName?: string;
214
+ ssrValue?: boolean; // value reported during SSR; overrides provideSsrValue
215
+ debugName?: string; // shown for the signal in Angular DevTools
224
216
  }
225
- ```
226
-
227
- ### Types
228
217
 
229
- ```ts
230
218
  type MqBreakpoints = Record<string, number>;
231
219
 
232
220
  type DisplayModeOption =
233
- | 'browser'
234
- | 'fullscreen'
235
- | 'standalone'
236
- | 'minimal-ui'
237
- | 'window-controls-overlay'
238
- | 'picture-in-picture';
221
+ | 'browser' | 'fullscreen' | 'standalone'
222
+ | 'minimal-ui' | 'window-controls-overlay' | 'picture-in-picture';
239
223
  ```
240
224
 
241
- ## Server-side rendering
242
-
243
- `matchMedia` does not exist on the server, so during SSR every signal returns a static value and
244
- no listeners are created. Set the default with `provideSsrValue`, or override it per call:
225
+ </details>
245
226
 
246
- ```ts
247
- provideSsrValue(false); // app-wide default
248
- up('lg', { ssrValue: true }); // per-call override
249
- ```
250
-
251
- Once the app hydrates in the browser, each signal switches to the live query result.
252
-
253
- ## How it works
227
+ ## Server-side rendering
254
228
 
255
- `ngx-mq` keeps a single `MediaQueryList` and writable signal per unique query in a global registry
256
- (Multiton + Flyweight). Callers share that signal, and a reference count tied to `DestroyRef`
257
- removes the listener and registry entry once the last consumer is destroyed. No manual cleanup, no
258
- duplicate listeners.
229
+ `matchMedia` does not exist on the server, so each signal returns a static value during SSR and switches to the live result after hydration. Set the default with `provideSsrValue(true)`, or override per call with `up('lg', { ssrValue: true })`.
259
230
 
260
231
  ## Contributing
261
232
 
262
- Contributions are welcome. See [CONTRIBUTING.md](https://github.com/martsinlabs/ngx-mq/blob/main/CONTRIBUTING.md).
233
+ Contributions are welcome. See [CONTRIBUTING.md](https://github.com/martsinlabs/ngx-mq/blob/main/CONTRIBUTING.md) and [ARCHITECTURE.md](https://github.com/martsinlabs/ngx-mq/blob/main/ARCHITECTURE.md).
263
234
 
264
235
  ## License
265
236
 
@@ -71,18 +71,22 @@ function resolveBreakpoint(bp) {
71
71
  const breakpoints = assertBreakpointsProvided();
72
72
  return assertBreakpointExists(bp.trim(), breakpoints);
73
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
+ }
74
82
  function normalizeBreakpoints(bps) {
75
83
  const out = {};
76
84
  for (const [rawKey, value] of Object.entries(bps)) {
77
85
  const key = rawKey.trim();
78
- if (isDevMode()) {
79
- if (!Number.isFinite(value)) {
80
- throw new Error(`[ngx-mq] Breakpoint "${key}" must be a finite number, got ${value}.`);
81
- }
82
- if (value <= 0) {
83
- throw new Error(`[ngx-mq] Breakpoint "${key}" must be > 0, got ${value}.`);
84
- }
85
- }
86
+ // Dev-only guard; the false branch never runs in production builds.
87
+ /* v8 ignore next */
88
+ if (isDevMode())
89
+ validateBreakpointValue(key, value);
86
90
  out[key] = value;
87
91
  }
88
92
  return Object.freeze(out);
@@ -184,9 +188,7 @@ function createConsumer(query, options) {
184
188
  const defaultSsrValue = inject(NGX_MQ_SSR_VALUE);
185
189
  const effectiveSsrValue = options?.ssrValue ?? defaultSsrValue;
186
190
  const querySignal = retainUntilDestroy(query, effectiveSsrValue);
187
- return computed(() => querySignal(), {
188
- debugName: isDevMode() ? options?.debugName : undefined,
189
- });
191
+ return computed(() => querySignal(), { debugName: options?.debugName });
190
192
  }
191
193
  function createConsumerLabel(descriptor) {
192
194
  return `[NgxMq Signal: ${descriptor}]`;
@@ -389,6 +391,31 @@ function reducedMotion(options) {
389
391
  consumer.toString = () => createConsumerLabel('reducedMotion');
390
392
  return consumer;
391
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
+ }
392
419
  /**
393
420
  * Tracks whether the **primary** input device can hover via `(hover: hover)`.
394
421
  *
@@ -686,6 +713,8 @@ function provideMaterialBreakpoints() {
686
713
  * @category Providers
687
714
  */
688
715
  function provideBreakpointEpsilon(epsilon = DEFAULT_BREAKPOINT_EPSILON) {
716
+ // Dev-only guard; the false branch never runs in production builds.
717
+ /* v8 ignore next */
689
718
  if (isDevMode())
690
719
  validateEpsilon(epsilon);
691
720
  return { provide: MQ_BREAKPOINT_EPSILON, useValue: epsilon };
@@ -720,5 +749,5 @@ function provideSsrValue(value) {
720
749
  * Generated bundle index. Do not edit.
721
750
  */
722
751
 
723
- export { MQ_BREAKPOINTS, MQ_BREAKPOINT_EPSILON, NGX_MQ_SSR_VALUE, and, anyHover, anyPointer, between, colorGamut, colorScheme, displayMode, down, hover, matchMediaSignal, not, or, 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 };
724
753
  //# sourceMappingURL=ngx-mq.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ngx-mq.mjs","sources":["../../src/lib/constants.ts","../../src/lib/tokens.ts","../../src/lib/utils/breakpoints.utils.ts","../../src/lib/mql-registry/mql-registry.listeners.ts","../../src/lib/mql-registry/mql-registry.ts","../../src/lib/mql-registry/mql-registry.extensions.ts","../../src/lib/core.ts","../../src/lib/utils/common.utils.ts","../../src/lib/api.ts","../../src/lib/composition.ts","../../src/lib/providers.ts","../../src/index.ts","../../src/ngx-mq.ts"],"sourcesContent":["import { MqBreakpoints } from './models';\n\nexport const TAILWIND_BREAKPOINTS: MqBreakpoints = {\n sm: 640,\n md: 768,\n lg: 1024,\n xl: 1280,\n '2xl': 1536,\n};\n\nexport const BOOTSTRAP_BREAKPOINTS: MqBreakpoints = {\n sm: 576,\n md: 768,\n lg: 992,\n xl: 1200,\n xxl: 1400,\n};\n\nexport const MATERIAL_BREAKPOINTS: MqBreakpoints = {\n sm: 600,\n md: 905,\n lg: 1240,\n xl: 1440,\n};\n\nexport const DEFAULT_BREAKPOINT_EPSILON: number = 0.02;\n","import { InjectionToken } from '@angular/core';\nimport { DEFAULT_BREAKPOINT_EPSILON } from './constants';\nimport { MqBreakpoints } from './models';\n\n/**\n * Holds the active {@link MqBreakpoints} map. Has no default: configure it with\n * {@link provideBreakpoints} or a preset. Inject it to read breakpoints directly.\n *\n * @category Injection Tokens\n */\nexport const MQ_BREAKPOINTS: InjectionToken<MqBreakpoints> = new InjectionToken('MQ_BREAKPOINTS');\n\n/**\n * Holds the epsilon used for exclusive upper bounds. Set it with\n * {@link provideBreakpointEpsilon}; defaults to `0.02`.\n *\n * @category Injection Tokens\n */\nexport const MQ_BREAKPOINT_EPSILON: InjectionToken<number> = new InjectionToken('MQ_BREAKPOINT_EPSILON', {\n providedIn: 'root',\n factory: () => DEFAULT_BREAKPOINT_EPSILON,\n});\n\n/**\n * Holds the value query signals report during SSR. Set it with\n * {@link provideSsrValue}; defaults to `false`.\n *\n * @category Injection Tokens\n */\nexport const NGX_MQ_SSR_VALUE: InjectionToken<boolean> = new InjectionToken('NGX_MQ_SSR_VALUE', {\n providedIn: 'root',\n factory: () => false,\n});\n","import { inject, isDevMode } from '@angular/core';\nimport { MQ_BREAKPOINT_EPSILON, MQ_BREAKPOINTS } from '../tokens';\nimport { MqBreakpoints } from '../models';\n\nfunction assertBreakpointsProvided(): MqBreakpoints {\n const breakpoints: MqBreakpoints | null = inject(MQ_BREAKPOINTS, { optional: true });\n\n if (isDevMode() && !breakpoints) {\n throw new Error(\n '[ngx-mq]: No breakpoints provided.\\n' +\n 'Please configure your app with provideBreakpoints(), ' +\n 'or use one of the built-in presets: ' +\n 'provideTailwindBreakpoints(), provideBootstrapBreakpoints(), provideMaterialBreakpoints().'\n );\n }\n\n return breakpoints!;\n}\n\nfunction assertBreakpointExists(bp: string, breakpoints: MqBreakpoints): number {\n if (isDevMode() && !(bp in breakpoints)) {\n throw new Error(\n `[ngx-mq]: Breakpoint \"${bp}\" not found in provided configuration.\\n` +\n `Available breakpoints: ${Object.keys(breakpoints).join(', ')}.`\n );\n }\n\n return breakpoints[bp];\n}\n\nexport function resolveBreakpoint(bp: string): number {\n const breakpoints: MqBreakpoints = assertBreakpointsProvided();\n\n return assertBreakpointExists(bp.trim(), breakpoints);\n}\n\nexport function normalizeBreakpoints(bps: MqBreakpoints): Readonly<MqBreakpoints> {\n const out: Record<string, number> = {};\n\n for (const [rawKey, value] of Object.entries(bps)) {\n const key = rawKey.trim();\n\n if (isDevMode()) {\n if (!Number.isFinite(value)) {\n throw new Error(`[ngx-mq] Breakpoint \"${key}\" must be a finite number, got ${value}.`);\n }\n\n if (value <= 0) {\n throw new Error(`[ngx-mq] Breakpoint \"${key}\" must be > 0, got ${value}.`);\n }\n }\n\n out[key] = value;\n }\n\n return Object.freeze(out);\n}\n\nexport function validateEpsilon(epsilon: number): void {\n if (!Number.isFinite(epsilon) || epsilon <= 0 || epsilon > 1) {\n throw new Error(`[ngx-mq] Epsilon must be in (0, 1]. Got: ${epsilon}`);\n }\n}\n\nexport function applyMaxEpsilon(value: number): number {\n const epsilon: number = inject(MQ_BREAKPOINT_EPSILON);\n\n return value - epsilon;\n}\n","export function addChangeListenerToMql(mql: MediaQueryList, onChange: (event?: MediaQueryListEvent) => void): void {\n if (typeof mql.addEventListener === 'function') {\n // Modern browsers\n mql.addEventListener('change', onChange);\n } else {\n // Legacy fallback (Safari < 14)\n (mql as any).addListener(onChange);\n }\n}\n\nexport function removeChangeListenerFromMql(\n mql: MediaQueryList,\n onChange: (event?: MediaQueryListEvent) => void\n): void {\n if (typeof mql.removeEventListener === 'function') {\n // Modern browsers\n mql.removeEventListener('change', onChange);\n } else {\n // Legacy fallback (Safari < 14)\n (mql as any).removeListener(onChange);\n }\n}\n","import { signal as createSignal, Signal, WritableSignal } from '@angular/core';\nimport { addChangeListenerToMql, removeChangeListenerFromMql } from './mql-registry.listeners';\nimport { MqlRegistry, MqRetainToken, MqHandle } from './mql-registry.models';\n\nconst REGISTRY_KEY: symbol = Symbol.for('ngx-mq:mql-registry');\n\nconst getRegistry = (): MqlRegistry => {\n const realmGlobal: Record<PropertyKey, unknown> = globalThis;\n\n return (realmGlobal[REGISTRY_KEY] ??= new Map()) as MqlRegistry;\n};\n\nconst createMqHandle = (query: string): MqHandle => {\n const mql: MediaQueryList = matchMedia(query);\n const signal: WritableSignal<boolean> = createSignal(mql.matches, { debugName: `ngx-mq: ${query}` });\n\n const onChange = (event?: MediaQueryListEvent) => signal.set(event?.matches ?? mql.matches);\n\n addChangeListenerToMql(mql, onChange);\n\n return { mql, signal, onChange, retainers: new Set() };\n};\n\nexport function retain(query: string, token: MqRetainToken, ssrValue: boolean): Signal<boolean> {\n // SSR mode\n if (typeof globalThis.matchMedia !== 'function') {\n return createSignal(ssrValue).asReadonly();\n }\n\n const registry: MqlRegistry = getRegistry();\n\n let handle: MqHandle | undefined = registry.get(query);\n\n if (!handle) {\n handle = createMqHandle(query);\n registry.set(query, handle);\n }\n\n handle.retainers.add(token);\n\n return handle.signal.asReadonly();\n}\n\nexport function release(query: string, token: MqRetainToken): boolean {\n const registry: MqlRegistry = getRegistry();\n\n let handle: MqHandle | undefined = registry.get(query);\n\n if (!handle) return false;\n\n const removed: boolean = handle.retainers.delete(token);\n\n if (handle.retainers.size === 0) {\n removeChangeListenerFromMql(handle.mql, handle.onChange);\n registry.delete(query);\n }\n\n return removed;\n}\n\n/* @internal\n * Returns the current registry (used only in tests).\n */\nexport function _getRegistry(): MqlRegistry {\n return getRegistry();\n}\n\n/* @internal\n * Clears all registry entries and removes media-query listeners.\n */\nexport function _resetRegistry(): void {\n const registry: MqlRegistry = getRegistry();\n\n registry.forEach((handle: MqHandle) => {\n removeChangeListenerFromMql(handle.mql, handle.onChange);\n });\n\n registry.clear();\n}\n","import { DestroyRef, inject, Signal } from '@angular/core';\nimport { retain, release } from './mql-registry';\n\nexport function retainUntilDestroy(query: string, ssrValue: boolean): Signal<boolean> {\n const destroyRef: DestroyRef = inject(DestroyRef);\n\n const querySignal: Signal<boolean> = retain(query, destroyRef, ssrValue);\n\n destroyRef.onDestroy(() => release(query, destroyRef));\n\n return querySignal;\n}\n","import { computed, isDevMode, Signal, inject } from '@angular/core';\nimport { retainUntilDestroy } from './mql-registry';\nimport { CreateMediaQueryOptions } from './models';\nimport { NGX_MQ_SSR_VALUE } from './tokens';\n\nexport function createConsumer(query: string, options?: CreateMediaQueryOptions): Signal<boolean> {\n const defaultSsrValue: boolean = inject(NGX_MQ_SSR_VALUE);\n const effectiveSsrValue: boolean = options?.ssrValue ?? defaultSsrValue;\n\n const querySignal: Signal<boolean> = retainUntilDestroy(query, effectiveSsrValue);\n\n return computed(() => querySignal(), {\n debugName: isDevMode() ? options?.debugName : undefined,\n });\n}\n\nexport function createConsumerLabel(descriptor: string): string {\n return `[NgxMq Signal: ${descriptor}]`;\n}\n","export function normalizeQuery(value: string): string {\n return value.trim().replace(/\\s+/g, ' ').toLowerCase();\n}\n","import { assertInInjectionContext, isDevMode, Signal } from '@angular/core';\nimport { applyMaxEpsilon, resolveBreakpoint } from './utils/breakpoints.utils';\nimport { CreateMediaQueryOptions, DisplayModeOption } from './models';\nimport { createConsumer, createConsumerLabel } from './core';\nimport { normalizeQuery } from './utils/common.utils';\n\n/**\n * Tracks whether the viewport width is **at or above** a breakpoint.\n *\n * Builds a `(min-width: <bp>px)` query from the value registered for `bp` via\n * {@link provideBreakpoints} (or a preset like {@link provideTailwindBreakpoints}).\n *\n * @param bp - Name of a configured breakpoint, e.g. `'md'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the viewport width is `>=` the breakpoint.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * export class LayoutComponent {\n * readonly isDesktop = up('lg');\n * }\n * ```\n *\n * @see {@link down} and {@link between} for the complementary ranges.\n * @category Breakpoints\n */\nexport function up(bp: string, options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(up);\n\n const query: string = normalizeQuery(`(min-width: ${resolveBreakpoint(bp)}px)`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`up(${bp})`);\n\n return consumer;\n}\n\n/**\n * Tracks whether the viewport width is **below** a breakpoint.\n *\n * Builds a `(max-width: <bp - epsilon>px)` query. The upper bound is **exclusive**:\n * a small epsilon is subtracted so `down('md')` and {@link up}`('md')` never overlap.\n *\n * @param bp - Name of a configured breakpoint, e.g. `'md'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the viewport width is `<` the breakpoint.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * export class NavComponent {\n * readonly isMobile = down('md');\n * }\n * ```\n *\n * @see {@link provideBreakpointEpsilon} to tune the exclusive-bound epsilon.\n * @category Breakpoints\n */\nexport function down(bp: string, options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(down);\n\n const query: string = normalizeQuery(`(max-width: ${applyMaxEpsilon(resolveBreakpoint(bp))}px)`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`down(${bp})`);\n\n return consumer;\n}\n\n/**\n * Tracks whether the viewport width falls within the range `[minBp, maxBp)`.\n *\n * Combines `min-width` and `max-width` into a single query. The lower bound is\n * inclusive and the upper bound is **exclusive** (epsilon is subtracted from `maxBp`).\n *\n * @param minBp - Name of the lower (inclusive) breakpoint.\n * @param maxBp - Name of the upper (exclusive) breakpoint.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the width is in `[minBp, maxBp)`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * export class GridComponent {\n * readonly isTablet = between('md', 'lg');\n * }\n * ```\n *\n * @category Breakpoints\n */\nexport function between(minBp: string, maxBp: string, options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(between);\n\n const minPx: number = resolveBreakpoint(minBp);\n const maxPx: number = resolveBreakpoint(maxBp);\n const query: string = normalizeQuery(`(min-width: ${minPx}px) and (max-width: ${applyMaxEpsilon(maxPx)}px)`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`between(${minBp}, ${maxBp})`);\n\n return consumer;\n}\n\n/**\n * Tracks the screen orientation via the `(orientation: ...)` media feature.\n *\n * @param value - `'portrait'` (height `>=` width) or `'landscape'` (width `>` height).\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the orientation matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isLandscape = orientation('landscape');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/orientation | MDN: orientation}\n * @category Media Features\n */\nexport function orientation(value: 'portrait' | 'landscape', options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(orientation);\n\n const query: string = normalizeQuery(`(orientation: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`orientation(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks the user's preferred color scheme via `(prefers-color-scheme: ...)`.\n *\n * @param value - `'light'` or `'dark'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the system scheme matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isDark = colorScheme('dark');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme | MDN: prefers-color-scheme}\n * @category Media Features\n */\nexport function colorScheme(value: 'light' | 'dark', options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(colorScheme);\n\n const query: string = normalizeQuery(`(prefers-color-scheme: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`colorScheme(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks how the app is being displayed via the `(display-mode: ...)` feature,\n * useful for detecting installed PWAs.\n *\n * @param value - One of {@link DisplayModeOption}, e.g. `'standalone'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the display mode matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isInstalledPwa = displayMode('standalone');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/display-mode | MDN: display-mode}\n * @category Media Features\n */\nexport function displayMode(value: DisplayModeOption, options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(displayMode);\n\n const query = normalizeQuery(`(display-mode: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`displayMode(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks whether the user has requested reduced motion via\n * `(prefers-reduced-motion: reduce)`.\n *\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while reduced motion is preferred.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly reduceMotion = reducedMotion();\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion | MDN: prefers-reduced-motion}\n * @category Media Features\n */\nexport function reducedMotion(options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(reducedMotion);\n\n const query: string = normalizeQuery('(prefers-reduced-motion: reduce)');\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel('reducedMotion');\n\n return consumer;\n}\n\n/**\n * Tracks whether the **primary** input device can hover via `(hover: hover)`.\n *\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the primary pointer supports hover.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly canHover = hover();\n * ```\n *\n * @see {@link anyHover} to test **any** available input device.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover | MDN: hover}\n * @category Media Features\n */\nexport function hover(options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(hover);\n\n const query: string = normalizeQuery('(hover: hover)');\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel('hover');\n\n return consumer;\n}\n\n/**\n * Tracks whether **any** available input device can hover via `(any-hover: hover)`.\n *\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while at least one pointer supports hover.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly anyCanHover = anyHover();\n * ```\n *\n * @see {@link hover} to test only the primary input device.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-hover | MDN: any-hover}\n * @category Media Features\n */\nexport function anyHover(options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(anyHover);\n\n const query: string = normalizeQuery('(any-hover: hover)');\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel('anyHover');\n\n return consumer;\n}\n\n/**\n * Tracks the accuracy of the **primary** pointer via `(pointer: ...)`.\n *\n * @param value - `'fine'` (mouse/stylus), `'coarse'` (touch), or `'none'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the primary pointer matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isTouch = pointer('coarse');\n * ```\n *\n * @see {@link anyPointer} to test **any** available input device.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer | MDN: pointer}\n * @category Media Features\n */\nexport function pointer(value: 'fine' | 'coarse' | 'none', options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(pointer);\n\n const query: string = normalizeQuery(`(pointer: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`pointer(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks the accuracy of **any** available pointer via `(any-pointer: ...)`.\n *\n * @param value - `'fine'` (mouse/stylus), `'coarse'` (touch), or `'none'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while at least one pointer matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly hasFinePointer = anyPointer('fine');\n * ```\n *\n * @see {@link pointer} to test only the primary input device.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-pointer | MDN: any-pointer}\n * @category Media Features\n */\nexport function anyPointer(value: 'fine' | 'coarse' | 'none', options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(anyPointer);\n\n const query: string = normalizeQuery(`(any-pointer: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`anyPointer(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks the approximate color gamut of the display via `(color-gamut: ...)`.\n *\n * @param value - `'srgb'`, `'p3'`, or `'rec2020'` (ordered by increasing range).\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the display covers `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isWideGamut = colorGamut('p3');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/color-gamut | MDN: color-gamut}\n * @category Media Features\n */\nexport function colorGamut(value: 'srgb' | 'p3' | 'rec2020', options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(colorGamut);\n\n const query: string = normalizeQuery(`(color-gamut: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`colorGamut(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks an arbitrary, raw CSS media query.\n *\n * Use this escape hatch for any feature not covered by the dedicated helpers.\n * The query is normalized (trimmed, collapsed whitespace, lower-cased) before use.\n *\n * @param query - A valid CSS media query, e.g. `'(min-resolution: 2dppx)'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that reflects the live result of the query.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isRetina = matchMediaSignal('(min-resolution: 2dppx)');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries | MDN: CSS media queries}\n * @category Custom Queries\n */\nexport function matchMediaSignal(query: string, options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(matchMediaSignal);\n\n const media: string = normalizeQuery(query);\n const consumer: Signal<boolean> = createConsumer(media, options);\n\n consumer.toString = () => createConsumerLabel(`matchMediaSignal(${query})`);\n\n return consumer;\n}\n","import { computed, Signal } from '@angular/core';\nimport { createConsumerLabel } from './core';\n\nconst LABEL_RE = /^\\[NgxMq Signal: (.+)]$/;\n\n/** Extracts the inner descriptor from an ngx-mq signal label, or falls back to its raw toString(). */\nfunction describe(condition: Signal<boolean>): string {\n const raw: string = condition.toString();\n const match: RegExpExecArray | null = LABEL_RE.exec(raw);\n\n return match ? match[1] : raw;\n}\n\n/**\n * Combines boolean signals with logical **AND**.\n *\n * Composition happens at the signal level, so the underlying media-query\n * listeners stay shared and are still cleaned up automatically.\n *\n * @param conditions - Boolean signals to combine. An empty call returns a\n * signal that is always `true` (vacuous truth).\n * @returns A `Signal<boolean>` that is `true` only when **every** condition is `true`.\n *\n * @example\n * ```ts\n * readonly isLandscapeDesktop = and(up('lg'), orientation('landscape'), hover());\n * ```\n *\n * @see {@link or} and {@link not}.\n * @category Combining Signals\n */\nexport function and(...conditions: Signal<boolean>[]): Signal<boolean> {\n const result: Signal<boolean> = computed(() => conditions.every((condition: Signal<boolean>) => condition()));\n\n result.toString = () => createConsumerLabel(`and(${conditions.map(describe).join(', ')})`);\n\n return result;\n}\n\n/**\n * Combines boolean signals with logical **OR**.\n *\n * Composition happens at the signal level, so the underlying media-query\n * listeners stay shared and are still cleaned up automatically.\n *\n * @param conditions - Boolean signals to combine. An empty call returns a\n * signal that is always `false`.\n * @returns A `Signal<boolean>` that is `true` when **at least one** condition is `true`.\n *\n * @example\n * ```ts\n * readonly prefersSimpleUi = or(down('md'), reducedMotion());\n * ```\n *\n * @see {@link and} and {@link not}.\n * @category Combining Signals\n */\nexport function or(...conditions: Signal<boolean>[]): Signal<boolean> {\n const result: Signal<boolean> = computed(() => conditions.some((condition: Signal<boolean>) => condition()));\n\n result.toString = () => createConsumerLabel(`or(${conditions.map(describe).join(', ')})`);\n\n return result;\n}\n\n/**\n * Negates a boolean signal.\n *\n * Useful for features that have no direct inverse helper, such as\n * \"devices without hover\": `not(hover())`.\n *\n * @param condition - The boolean signal to invert.\n * @returns A `Signal<boolean>` that is `true` when `condition` is `false`, and vice versa.\n *\n * @example\n * ```ts\n * readonly isTouchLike = not(hover());\n * ```\n *\n * @see {@link and} and {@link or}.\n * @category Combining Signals\n */\nexport function not(condition: Signal<boolean>): Signal<boolean> {\n const result: Signal<boolean> = computed(() => !condition());\n\n result.toString = () => createConsumerLabel(`not(${describe(condition)})`);\n\n return result;\n}\n","import { isDevMode, Provider } from '@angular/core';\nimport { MQ_BREAKPOINT_EPSILON, MQ_BREAKPOINTS, NGX_MQ_SSR_VALUE } from './tokens';\nimport { normalizeBreakpoints, validateEpsilon } from './utils/breakpoints.utils';\nimport { MqBreakpoints } from './models';\nimport {\n BOOTSTRAP_BREAKPOINTS,\n DEFAULT_BREAKPOINT_EPSILON,\n MATERIAL_BREAKPOINTS,\n TAILWIND_BREAKPOINTS,\n} from './constants';\n\n/**\n * Registers a custom breakpoint map, enabling {@link up}, {@link down} and {@link between}.\n *\n * Provide once at bootstrap, or at any injector level to scope/override breakpoints.\n *\n * @param bps - A {@link MqBreakpoints} map of names to minimum widths in pixels.\n * @returns An Angular {@link Provider}.\n *\n * @example\n * ```ts\n * bootstrapApplication(AppComponent, {\n * providers: [provideBreakpoints({ sm: 640, md: 768, lg: 1024 })],\n * });\n * ```\n *\n * @category Providers\n */\nexport function provideBreakpoints(bps: MqBreakpoints): Provider {\n return { provide: MQ_BREAKPOINTS, useValue: normalizeBreakpoints(bps) };\n}\n\n/**\n * Registers the default Tailwind CSS breakpoints:\n * `sm: 640, md: 768, lg: 1024, xl: 1280, 2xl: 1536`.\n *\n * @returns An Angular {@link Provider}.\n * @category Providers\n */\nexport function provideTailwindBreakpoints(): Provider {\n return provideBreakpoints(TAILWIND_BREAKPOINTS);\n}\n\n/**\n * Registers the default Bootstrap breakpoints:\n * `sm: 576, md: 768, lg: 992, xl: 1200, xxl: 1400`.\n *\n * @returns An Angular {@link Provider}.\n * @category Providers\n */\nexport function provideBootstrapBreakpoints(): Provider {\n return provideBreakpoints(BOOTSTRAP_BREAKPOINTS);\n}\n\n/**\n * Registers the default Material 2 breakpoints:\n * `sm: 600, md: 905, lg: 1240, xl: 1440`.\n *\n * @returns An Angular {@link Provider}.\n * @category Providers\n */\nexport function provideMaterialBreakpoints(): Provider {\n return provideBreakpoints(MATERIAL_BREAKPOINTS);\n}\n\n/**\n * Sets the epsilon subtracted from exclusive upper bounds in {@link down} and\n * {@link between}, preventing adjacent ranges from overlapping.\n *\n * @param epsilon - A value in the range `(0, 1]`. Defaults to `0.02`.\n * @returns An Angular {@link Provider}.\n *\n * @example\n * ```ts\n * provideBreakpointEpsilon(0.02);\n * ```\n *\n * @category Providers\n */\nexport function provideBreakpointEpsilon(epsilon: number = DEFAULT_BREAKPOINT_EPSILON): Provider {\n if (isDevMode()) validateEpsilon(epsilon);\n\n return { provide: MQ_BREAKPOINT_EPSILON, useValue: epsilon };\n}\n\n/**\n * Sets the app-wide value query signals report during server-side rendering,\n * where `matchMedia` is unavailable. A per-call `ssrValue` overrides this.\n *\n * @param value - The boolean returned by every signal on the server.\n * @returns An Angular {@link Provider}.\n *\n * @example\n * ```ts\n * provideSsrValue(true);\n * ```\n *\n * @category Providers\n */\nexport function provideSsrValue(value: boolean): Provider {\n return { provide: NGX_MQ_SSR_VALUE, useValue: value };\n}\n","/**\n * @packageDocumentation\n *\n * @document ../guides/getting-started.md\n * @document ../guides/ssr.md\n * @document ../guides/recipes.md\n */\n\nexport * from './lib/api';\nexport * from './lib/composition';\nexport * from './lib/tokens';\nexport * from './lib/providers';\nexport * from './lib/models';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["signal","createSignal"],"mappings":"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"}
1
+ {"version":3,"file":"ngx-mq.mjs","sources":["../../src/lib/constants.ts","../../src/lib/tokens.ts","../../src/lib/utils/breakpoints.utils.ts","../../src/lib/mql-registry/mql-registry.listeners.ts","../../src/lib/mql-registry/mql-registry.ts","../../src/lib/mql-registry/mql-registry.extensions.ts","../../src/lib/core.ts","../../src/lib/utils/common.utils.ts","../../src/lib/api.ts","../../src/lib/composition.ts","../../src/lib/providers.ts","../../src/index.ts","../../src/ngx-mq.ts"],"sourcesContent":["import { MqBreakpoints } from './models';\n\nexport const TAILWIND_BREAKPOINTS: MqBreakpoints = {\n sm: 640,\n md: 768,\n lg: 1024,\n xl: 1280,\n '2xl': 1536,\n};\n\nexport const BOOTSTRAP_BREAKPOINTS: MqBreakpoints = {\n sm: 576,\n md: 768,\n lg: 992,\n xl: 1200,\n xxl: 1400,\n};\n\nexport const MATERIAL_BREAKPOINTS: MqBreakpoints = {\n sm: 600,\n md: 905,\n lg: 1240,\n xl: 1440,\n};\n\nexport const DEFAULT_BREAKPOINT_EPSILON: number = 0.02;\n","import { InjectionToken } from '@angular/core';\nimport { DEFAULT_BREAKPOINT_EPSILON } from './constants';\nimport { MqBreakpoints } from './models';\n\n/**\n * Holds the active {@link MqBreakpoints} map. Has no default: configure it with\n * {@link provideBreakpoints} or a preset. Inject it to read breakpoints directly.\n *\n * @category Injection Tokens\n */\nexport const MQ_BREAKPOINTS: InjectionToken<MqBreakpoints> = new InjectionToken('MQ_BREAKPOINTS');\n\n/**\n * Holds the epsilon used for exclusive upper bounds. Set it with\n * {@link provideBreakpointEpsilon}; defaults to `0.02`.\n *\n * @category Injection Tokens\n */\nexport const MQ_BREAKPOINT_EPSILON: InjectionToken<number> = new InjectionToken('MQ_BREAKPOINT_EPSILON', {\n providedIn: 'root',\n factory: () => DEFAULT_BREAKPOINT_EPSILON,\n});\n\n/**\n * Holds the value query signals report during SSR. Set it with\n * {@link provideSsrValue}; defaults to `false`.\n *\n * @category Injection Tokens\n */\nexport const NGX_MQ_SSR_VALUE: InjectionToken<boolean> = new InjectionToken('NGX_MQ_SSR_VALUE', {\n providedIn: 'root',\n factory: () => false,\n});\n","import { inject, isDevMode } from '@angular/core';\nimport { MQ_BREAKPOINT_EPSILON, MQ_BREAKPOINTS } from '../tokens';\nimport { MqBreakpoints } from '../models';\n\nfunction assertBreakpointsProvided(): MqBreakpoints {\n const breakpoints: MqBreakpoints | null = inject(MQ_BREAKPOINTS, { optional: true });\n\n if (isDevMode() && !breakpoints) {\n throw new Error(\n '[ngx-mq]: No breakpoints provided.\\n' +\n 'Please configure your app with provideBreakpoints(), ' +\n 'or use one of the built-in presets: ' +\n 'provideTailwindBreakpoints(), provideBootstrapBreakpoints(), provideMaterialBreakpoints().'\n );\n }\n\n return breakpoints!;\n}\n\nfunction assertBreakpointExists(bp: string, breakpoints: MqBreakpoints): number {\n if (isDevMode() && !(bp in breakpoints)) {\n throw new Error(\n `[ngx-mq]: Breakpoint \"${bp}\" not found in provided configuration.\\n` +\n `Available breakpoints: ${Object.keys(breakpoints).join(', ')}.`\n );\n }\n\n return breakpoints[bp];\n}\n\nexport function resolveBreakpoint(bp: string): number {\n const breakpoints: MqBreakpoints = assertBreakpointsProvided();\n\n return assertBreakpointExists(bp.trim(), breakpoints);\n}\n\nfunction validateBreakpointValue(key: string, value: number): void {\n if (!Number.isFinite(value)) {\n throw new Error(`[ngx-mq] Breakpoint \"${key}\" must be a finite number, got ${value}.`);\n }\n\n if (value <= 0) {\n throw new Error(`[ngx-mq] Breakpoint \"${key}\" must be > 0, got ${value}.`);\n }\n}\n\nexport function normalizeBreakpoints(bps: MqBreakpoints): Readonly<MqBreakpoints> {\n const out: Record<string, number> = {};\n\n for (const [rawKey, value] of Object.entries(bps)) {\n const key = rawKey.trim();\n\n // Dev-only guard; the false branch never runs in production builds.\n /* v8 ignore next */\n if (isDevMode()) validateBreakpointValue(key, value);\n\n out[key] = value;\n }\n\n return Object.freeze(out);\n}\n\nexport function validateEpsilon(epsilon: number): void {\n if (!Number.isFinite(epsilon) || epsilon <= 0 || epsilon > 1) {\n throw new Error(`[ngx-mq] Epsilon must be in (0, 1]. Got: ${epsilon}`);\n }\n}\n\nexport function applyMaxEpsilon(value: number): number {\n const epsilon: number = inject(MQ_BREAKPOINT_EPSILON);\n\n return value - epsilon;\n}\n","export function addChangeListenerToMql(mql: MediaQueryList, onChange: (event?: MediaQueryListEvent) => void): void {\n if (typeof mql.addEventListener === 'function') {\n // Modern browsers\n mql.addEventListener('change', onChange);\n } else {\n // Legacy fallback (Safari < 14)\n (mql as any).addListener(onChange);\n }\n}\n\nexport function removeChangeListenerFromMql(\n mql: MediaQueryList,\n onChange: (event?: MediaQueryListEvent) => void\n): void {\n if (typeof mql.removeEventListener === 'function') {\n // Modern browsers\n mql.removeEventListener('change', onChange);\n } else {\n // Legacy fallback (Safari < 14)\n (mql as any).removeListener(onChange);\n }\n}\n","import { signal as createSignal, Signal, WritableSignal } from '@angular/core';\nimport { addChangeListenerToMql, removeChangeListenerFromMql } from './mql-registry.listeners';\nimport { MqlRegistry, MqRetainToken, MqHandle } from './mql-registry.models';\n\nconst REGISTRY_KEY: symbol = Symbol.for('ngx-mq:mql-registry');\n\nconst getRegistry = (): MqlRegistry => {\n const realmGlobal: Record<PropertyKey, unknown> = globalThis;\n\n return (realmGlobal[REGISTRY_KEY] ??= new Map()) as MqlRegistry;\n};\n\nconst createMqHandle = (query: string): MqHandle => {\n const mql: MediaQueryList = matchMedia(query);\n const signal: WritableSignal<boolean> = createSignal(mql.matches, { debugName: `ngx-mq: ${query}` });\n\n const onChange = (event?: MediaQueryListEvent) => signal.set(event?.matches ?? mql.matches);\n\n addChangeListenerToMql(mql, onChange);\n\n return { mql, signal, onChange, retainers: new Set() };\n};\n\nexport function retain(query: string, token: MqRetainToken, ssrValue: boolean): Signal<boolean> {\n // SSR mode\n if (typeof globalThis.matchMedia !== 'function') {\n return createSignal(ssrValue).asReadonly();\n }\n\n const registry: MqlRegistry = getRegistry();\n\n let handle: MqHandle | undefined = registry.get(query);\n\n if (!handle) {\n handle = createMqHandle(query);\n registry.set(query, handle);\n }\n\n handle.retainers.add(token);\n\n return handle.signal.asReadonly();\n}\n\nexport function release(query: string, token: MqRetainToken): boolean {\n const registry: MqlRegistry = getRegistry();\n\n let handle: MqHandle | undefined = registry.get(query);\n\n if (!handle) return false;\n\n const removed: boolean = handle.retainers.delete(token);\n\n if (handle.retainers.size === 0) {\n removeChangeListenerFromMql(handle.mql, handle.onChange);\n registry.delete(query);\n }\n\n return removed;\n}\n\n/* @internal\n * Returns the current registry (used only in tests).\n */\nexport function _getRegistry(): MqlRegistry {\n return getRegistry();\n}\n\n/* @internal\n * Clears all registry entries and removes media-query listeners.\n */\nexport function _resetRegistry(): void {\n const registry: MqlRegistry = getRegistry();\n\n registry.forEach((handle: MqHandle) => {\n removeChangeListenerFromMql(handle.mql, handle.onChange);\n });\n\n registry.clear();\n}\n","import { DestroyRef, inject, Signal } from '@angular/core';\nimport { retain, release } from './mql-registry';\n\nexport function retainUntilDestroy(query: string, ssrValue: boolean): Signal<boolean> {\n const destroyRef: DestroyRef = inject(DestroyRef);\n\n const querySignal: Signal<boolean> = retain(query, destroyRef, ssrValue);\n\n destroyRef.onDestroy(() => release(query, destroyRef));\n\n return querySignal;\n}\n","import { computed, Signal, inject } from '@angular/core';\nimport { retainUntilDestroy } from './mql-registry';\nimport { CreateMediaQueryOptions } from './models';\nimport { NGX_MQ_SSR_VALUE } from './tokens';\n\nexport function createConsumer(query: string, options?: CreateMediaQueryOptions): Signal<boolean> {\n const defaultSsrValue: boolean = inject(NGX_MQ_SSR_VALUE);\n const effectiveSsrValue: boolean = options?.ssrValue ?? defaultSsrValue;\n\n const querySignal: Signal<boolean> = retainUntilDestroy(query, effectiveSsrValue);\n\n return computed(() => querySignal(), { debugName: options?.debugName });\n}\n\nexport function createConsumerLabel(descriptor: string): string {\n return `[NgxMq Signal: ${descriptor}]`;\n}\n","export function normalizeQuery(value: string): string {\n return value.trim().replace(/\\s+/g, ' ').toLowerCase();\n}\n","import { assertInInjectionContext, isDevMode, Signal } from '@angular/core';\nimport { applyMaxEpsilon, resolveBreakpoint } from './utils/breakpoints.utils';\nimport { CreateMediaQueryOptions, DisplayModeOption } from './models';\nimport { createConsumer, createConsumerLabel } from './core';\nimport { normalizeQuery } from './utils/common.utils';\n\n/**\n * Tracks whether the viewport width is **at or above** a breakpoint.\n *\n * Builds a `(min-width: <bp>px)` query from the value registered for `bp` via\n * {@link provideBreakpoints} (or a preset like {@link provideTailwindBreakpoints}).\n *\n * @param bp - Name of a configured breakpoint, e.g. `'md'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the viewport width is `>=` the breakpoint.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * export class LayoutComponent {\n * readonly isDesktop = up('lg');\n * }\n * ```\n *\n * @see {@link down} and {@link between} for the complementary ranges.\n * @category Breakpoints\n */\nexport function up(bp: string, options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(up);\n\n const query: string = normalizeQuery(`(min-width: ${resolveBreakpoint(bp)}px)`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`up(${bp})`);\n\n return consumer;\n}\n\n/**\n * Tracks whether the viewport width is **below** a breakpoint.\n *\n * Builds a `(max-width: <bp - epsilon>px)` query. The upper bound is **exclusive**:\n * a small epsilon is subtracted so `down('md')` and {@link up}`('md')` never overlap.\n *\n * @param bp - Name of a configured breakpoint, e.g. `'md'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the viewport width is `<` the breakpoint.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * export class NavComponent {\n * readonly isMobile = down('md');\n * }\n * ```\n *\n * @see {@link provideBreakpointEpsilon} to tune the exclusive-bound epsilon.\n * @category Breakpoints\n */\nexport function down(bp: string, options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(down);\n\n const query: string = normalizeQuery(`(max-width: ${applyMaxEpsilon(resolveBreakpoint(bp))}px)`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`down(${bp})`);\n\n return consumer;\n}\n\n/**\n * Tracks whether the viewport width falls within the range `[minBp, maxBp)`.\n *\n * Combines `min-width` and `max-width` into a single query. The lower bound is\n * inclusive and the upper bound is **exclusive** (epsilon is subtracted from `maxBp`).\n *\n * @param minBp - Name of the lower (inclusive) breakpoint.\n * @param maxBp - Name of the upper (exclusive) breakpoint.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the width is in `[minBp, maxBp)`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * export class GridComponent {\n * readonly isTablet = between('md', 'lg');\n * }\n * ```\n *\n * @category Breakpoints\n */\nexport function between(minBp: string, maxBp: string, options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(between);\n\n const minPx: number = resolveBreakpoint(minBp);\n const maxPx: number = resolveBreakpoint(maxBp);\n const query: string = normalizeQuery(`(min-width: ${minPx}px) and (max-width: ${applyMaxEpsilon(maxPx)}px)`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`between(${minBp}, ${maxBp})`);\n\n return consumer;\n}\n\n/**\n * Tracks the screen orientation via the `(orientation: ...)` media feature.\n *\n * @param value - `'portrait'` (height `>=` width) or `'landscape'` (width `>` height).\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the orientation matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isLandscape = orientation('landscape');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/orientation | MDN: orientation}\n * @category Media Features\n */\nexport function orientation(value: 'portrait' | 'landscape', options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(orientation);\n\n const query: string = normalizeQuery(`(orientation: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`orientation(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks the user's preferred color scheme via `(prefers-color-scheme: ...)`.\n *\n * @param value - `'light'` or `'dark'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the system scheme matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isDark = colorScheme('dark');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme | MDN: prefers-color-scheme}\n * @category Media Features\n */\nexport function colorScheme(value: 'light' | 'dark', options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(colorScheme);\n\n const query: string = normalizeQuery(`(prefers-color-scheme: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`colorScheme(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks how the app is being displayed via the `(display-mode: ...)` feature,\n * useful for detecting installed PWAs.\n *\n * @param value - One of {@link DisplayModeOption}, e.g. `'standalone'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the display mode matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isInstalledPwa = displayMode('standalone');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/display-mode | MDN: display-mode}\n * @category Media Features\n */\nexport function displayMode(value: DisplayModeOption, options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(displayMode);\n\n const query = normalizeQuery(`(display-mode: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`displayMode(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks whether the user has requested reduced motion via\n * `(prefers-reduced-motion: reduce)`.\n *\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while reduced motion is preferred.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly reduceMotion = reducedMotion();\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion | MDN: prefers-reduced-motion}\n * @category Media Features\n */\nexport function reducedMotion(options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(reducedMotion);\n\n const query: string = normalizeQuery('(prefers-reduced-motion: reduce)');\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel('reducedMotion');\n\n return consumer;\n}\n\n/**\n * Tracks the user's contrast preference via `(prefers-contrast: ...)`.\n *\n * @param value - `'more'`, `'less'`, `'no-preference'`, or `'custom'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the contrast preference matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly wantsMoreContrast = prefersContrast('more');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast | MDN: prefers-contrast}\n * @category Media Features\n */\nexport function prefersContrast(\n value: 'more' | 'less' | 'no-preference' | 'custom',\n options?: CreateMediaQueryOptions\n): Signal<boolean> {\n isDevMode() && assertInInjectionContext(prefersContrast);\n\n const query: string = normalizeQuery(`(prefers-contrast: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`prefersContrast(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks whether the **primary** input device can hover via `(hover: hover)`.\n *\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the primary pointer supports hover.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly canHover = hover();\n * ```\n *\n * @see {@link anyHover} to test **any** available input device.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/hover | MDN: hover}\n * @category Media Features\n */\nexport function hover(options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(hover);\n\n const query: string = normalizeQuery('(hover: hover)');\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel('hover');\n\n return consumer;\n}\n\n/**\n * Tracks whether **any** available input device can hover via `(any-hover: hover)`.\n *\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while at least one pointer supports hover.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly anyCanHover = anyHover();\n * ```\n *\n * @see {@link hover} to test only the primary input device.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-hover | MDN: any-hover}\n * @category Media Features\n */\nexport function anyHover(options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(anyHover);\n\n const query: string = normalizeQuery('(any-hover: hover)');\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel('anyHover');\n\n return consumer;\n}\n\n/**\n * Tracks the accuracy of the **primary** pointer via `(pointer: ...)`.\n *\n * @param value - `'fine'` (mouse/stylus), `'coarse'` (touch), or `'none'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the primary pointer matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isTouch = pointer('coarse');\n * ```\n *\n * @see {@link anyPointer} to test **any** available input device.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/pointer | MDN: pointer}\n * @category Media Features\n */\nexport function pointer(value: 'fine' | 'coarse' | 'none', options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(pointer);\n\n const query: string = normalizeQuery(`(pointer: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`pointer(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks the accuracy of **any** available pointer via `(any-pointer: ...)`.\n *\n * @param value - `'fine'` (mouse/stylus), `'coarse'` (touch), or `'none'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while at least one pointer matches `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly hasFinePointer = anyPointer('fine');\n * ```\n *\n * @see {@link pointer} to test only the primary input device.\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/any-pointer | MDN: any-pointer}\n * @category Media Features\n */\nexport function anyPointer(value: 'fine' | 'coarse' | 'none', options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(anyPointer);\n\n const query: string = normalizeQuery(`(any-pointer: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`anyPointer(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks the approximate color gamut of the display via `(color-gamut: ...)`.\n *\n * @param value - `'srgb'`, `'p3'`, or `'rec2020'` (ordered by increasing range).\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that is `true` while the display covers `value`.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isWideGamut = colorGamut('p3');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/color-gamut | MDN: color-gamut}\n * @category Media Features\n */\nexport function colorGamut(value: 'srgb' | 'p3' | 'rec2020', options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(colorGamut);\n\n const query: string = normalizeQuery(`(color-gamut: ${value})`);\n const consumer: Signal<boolean> = createConsumer(query, options);\n\n consumer.toString = () => createConsumerLabel(`colorGamut(${value})`);\n\n return consumer;\n}\n\n/**\n * Tracks an arbitrary, raw CSS media query.\n *\n * Use this escape hatch for any feature not covered by the dedicated helpers.\n * The query is normalized (trimmed, collapsed whitespace, lower-cased) before use.\n *\n * @param query - A valid CSS media query, e.g. `'(min-resolution: 2dppx)'`.\n * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).\n * @returns A `Signal<boolean>` that reflects the live result of the query.\n *\n * @remarks Must be called within an Angular\n * [injection context](https://angular.dev/guide/di/dependency-injection-context).\n *\n * @example\n * ```ts\n * readonly isRetina = matchMediaSignal('(min-resolution: 2dppx)');\n * ```\n *\n * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries | MDN: CSS media queries}\n * @category Custom Queries\n */\nexport function matchMediaSignal(query: string, options?: CreateMediaQueryOptions): Signal<boolean> {\n isDevMode() && assertInInjectionContext(matchMediaSignal);\n\n const media: string = normalizeQuery(query);\n const consumer: Signal<boolean> = createConsumer(media, options);\n\n consumer.toString = () => createConsumerLabel(`matchMediaSignal(${query})`);\n\n return consumer;\n}\n","import { computed, Signal } from '@angular/core';\nimport { createConsumerLabel } from './core';\n\nconst LABEL_RE = /^\\[NgxMq Signal: (.+)]$/;\n\n/** Extracts the inner descriptor from an ngx-mq signal label, or falls back to its raw toString(). */\nfunction describe(condition: Signal<boolean>): string {\n const raw: string = condition.toString();\n const match: RegExpExecArray | null = LABEL_RE.exec(raw);\n\n return match ? match[1] : raw;\n}\n\n/**\n * Combines boolean signals with logical **AND**.\n *\n * Composition happens at the signal level, so the underlying media-query\n * listeners stay shared and are still cleaned up automatically.\n *\n * @param conditions - Boolean signals to combine. An empty call returns a\n * signal that is always `true` (vacuous truth).\n * @returns A `Signal<boolean>` that is `true` only when **every** condition is `true`.\n *\n * @example\n * ```ts\n * readonly isLandscapeDesktop = and(up('lg'), orientation('landscape'), hover());\n * ```\n *\n * @see {@link or} and {@link not}.\n * @category Combining Signals\n */\nexport function and(...conditions: Signal<boolean>[]): Signal<boolean> {\n const result: Signal<boolean> = computed(() => conditions.every((condition: Signal<boolean>) => condition()));\n\n result.toString = () => createConsumerLabel(`and(${conditions.map(describe).join(', ')})`);\n\n return result;\n}\n\n/**\n * Combines boolean signals with logical **OR**.\n *\n * Composition happens at the signal level, so the underlying media-query\n * listeners stay shared and are still cleaned up automatically.\n *\n * @param conditions - Boolean signals to combine. An empty call returns a\n * signal that is always `false`.\n * @returns A `Signal<boolean>` that is `true` when **at least one** condition is `true`.\n *\n * @example\n * ```ts\n * readonly prefersSimpleUi = or(down('md'), reducedMotion());\n * ```\n *\n * @see {@link and} and {@link not}.\n * @category Combining Signals\n */\nexport function or(...conditions: Signal<boolean>[]): Signal<boolean> {\n const result: Signal<boolean> = computed(() => conditions.some((condition: Signal<boolean>) => condition()));\n\n result.toString = () => createConsumerLabel(`or(${conditions.map(describe).join(', ')})`);\n\n return result;\n}\n\n/**\n * Negates a boolean signal.\n *\n * Useful for features that have no direct inverse helper, such as\n * \"devices without hover\": `not(hover())`.\n *\n * @param condition - The boolean signal to invert.\n * @returns A `Signal<boolean>` that is `true` when `condition` is `false`, and vice versa.\n *\n * @example\n * ```ts\n * readonly isTouchLike = not(hover());\n * ```\n *\n * @see {@link and} and {@link or}.\n * @category Combining Signals\n */\nexport function not(condition: Signal<boolean>): Signal<boolean> {\n const result: Signal<boolean> = computed(() => !condition());\n\n result.toString = () => createConsumerLabel(`not(${describe(condition)})`);\n\n return result;\n}\n","import { isDevMode, Provider } from '@angular/core';\nimport { MQ_BREAKPOINT_EPSILON, MQ_BREAKPOINTS, NGX_MQ_SSR_VALUE } from './tokens';\nimport { normalizeBreakpoints, validateEpsilon } from './utils/breakpoints.utils';\nimport { MqBreakpoints } from './models';\nimport {\n BOOTSTRAP_BREAKPOINTS,\n DEFAULT_BREAKPOINT_EPSILON,\n MATERIAL_BREAKPOINTS,\n TAILWIND_BREAKPOINTS,\n} from './constants';\n\n/**\n * Registers a custom breakpoint map, enabling {@link up}, {@link down} and {@link between}.\n *\n * Provide once at bootstrap, or at any injector level to scope/override breakpoints.\n *\n * @param bps - A {@link MqBreakpoints} map of names to minimum widths in pixels.\n * @returns An Angular {@link Provider}.\n *\n * @example\n * ```ts\n * bootstrapApplication(AppComponent, {\n * providers: [provideBreakpoints({ sm: 640, md: 768, lg: 1024 })],\n * });\n * ```\n *\n * @category Providers\n */\nexport function provideBreakpoints(bps: MqBreakpoints): Provider {\n return { provide: MQ_BREAKPOINTS, useValue: normalizeBreakpoints(bps) };\n}\n\n/**\n * Registers the default Tailwind CSS breakpoints:\n * `sm: 640, md: 768, lg: 1024, xl: 1280, 2xl: 1536`.\n *\n * @returns An Angular {@link Provider}.\n * @category Providers\n */\nexport function provideTailwindBreakpoints(): Provider {\n return provideBreakpoints(TAILWIND_BREAKPOINTS);\n}\n\n/**\n * Registers the default Bootstrap breakpoints:\n * `sm: 576, md: 768, lg: 992, xl: 1200, xxl: 1400`.\n *\n * @returns An Angular {@link Provider}.\n * @category Providers\n */\nexport function provideBootstrapBreakpoints(): Provider {\n return provideBreakpoints(BOOTSTRAP_BREAKPOINTS);\n}\n\n/**\n * Registers the default Material 2 breakpoints:\n * `sm: 600, md: 905, lg: 1240, xl: 1440`.\n *\n * @returns An Angular {@link Provider}.\n * @category Providers\n */\nexport function provideMaterialBreakpoints(): Provider {\n return provideBreakpoints(MATERIAL_BREAKPOINTS);\n}\n\n/**\n * Sets the epsilon subtracted from exclusive upper bounds in {@link down} and\n * {@link between}, preventing adjacent ranges from overlapping.\n *\n * @param epsilon - A value in the range `(0, 1]`. Defaults to `0.02`.\n * @returns An Angular {@link Provider}.\n *\n * @example\n * ```ts\n * provideBreakpointEpsilon(0.02);\n * ```\n *\n * @category Providers\n */\nexport function provideBreakpointEpsilon(epsilon: number = DEFAULT_BREAKPOINT_EPSILON): Provider {\n // Dev-only guard; the false branch never runs in production builds.\n /* v8 ignore next */\n if (isDevMode()) validateEpsilon(epsilon);\n\n return { provide: MQ_BREAKPOINT_EPSILON, useValue: epsilon };\n}\n\n/**\n * Sets the app-wide value query signals report during server-side rendering,\n * where `matchMedia` is unavailable. A per-call `ssrValue` overrides this.\n *\n * @param value - The boolean returned by every signal on the server.\n * @returns An Angular {@link Provider}.\n *\n * @example\n * ```ts\n * provideSsrValue(true);\n * ```\n *\n * @category Providers\n */\nexport function provideSsrValue(value: boolean): Provider {\n return { provide: NGX_MQ_SSR_VALUE, useValue: value };\n}\n","/**\n * @packageDocumentation\n *\n * @document ../guides/getting-started.md\n * @document ../guides/ssr.md\n * @document ../guides/recipes.md\n */\n\nexport * from './lib/api';\nexport * from './lib/composition';\nexport * from './lib/tokens';\nexport * from './lib/providers';\nexport * from './lib/models';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["signal","createSignal"],"mappings":";;AAEO,MAAM,oBAAoB,GAAkB;AACjD,IAAA,EAAE,EAAE,GAAG;AACP,IAAA,EAAE,EAAE,GAAG;AACP,IAAA,EAAE,EAAE,IAAI;AACR,IAAA,EAAE,EAAE,IAAI;AACR,IAAA,KAAK,EAAE,IAAI;CACZ;AAEM,MAAM,qBAAqB,GAAkB;AAClD,IAAA,EAAE,EAAE,GAAG;AACP,IAAA,EAAE,EAAE,GAAG;AACP,IAAA,EAAE,EAAE,GAAG;AACP,IAAA,EAAE,EAAE,IAAI;AACR,IAAA,GAAG,EAAE,IAAI;CACV;AAEM,MAAM,oBAAoB,GAAkB;AACjD,IAAA,EAAE,EAAE,GAAG;AACP,IAAA,EAAE,EAAE,GAAG;AACP,IAAA,EAAE,EAAE,IAAI;AACR,IAAA,EAAE,EAAE,IAAI;CACT;AAEM,MAAM,0BAA0B,GAAW,IAAI;;ACrBtD;;;;;AAKG;MACU,cAAc,GAAkC,IAAI,cAAc,CAAC,gBAAgB;AAEhG;;;;;AAKG;MACU,qBAAqB,GAA2B,IAAI,cAAc,CAAC,uBAAuB,EAAE;AACvG,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM,0BAA0B;AAC1C,CAAA;AAED;;;;;AAKG;MACU,gBAAgB,GAA4B,IAAI,cAAc,CAAC,kBAAkB,EAAE;AAC9F,IAAA,UAAU,EAAE,MAAM;AAClB,IAAA,OAAO,EAAE,MAAM,KAAK;AACrB,CAAA;;AC5BD,SAAS,yBAAyB,GAAA;AAChC,IAAA,MAAM,WAAW,GAAyB,MAAM,CAAC,cAAc,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAEpF,IAAA,IAAI,SAAS,EAAE,IAAI,CAAC,WAAW,EAAE;QAC/B,MAAM,IAAI,KAAK,CACb,sCAAsC;YACpC,uDAAuD;YACvD,sCAAsC;AACtC,YAAA,4FAA4F,CAC/F;IACH;AAEA,IAAA,OAAO,WAAY;AACrB;AAEA,SAAS,sBAAsB,CAAC,EAAU,EAAE,WAA0B,EAAA;IACpE,IAAI,SAAS,EAAE,IAAI,EAAE,EAAE,IAAI,WAAW,CAAC,EAAE;AACvC,QAAA,MAAM,IAAI,KAAK,CACb,CAAA,sBAAA,EAAyB,EAAE,CAAA,wCAAA,CAA0C;AACnE,YAAA,CAAA,uBAAA,EAA0B,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CACnE;IACH;AAEA,IAAA,OAAO,WAAW,CAAC,EAAE,CAAC;AACxB;AAEM,SAAU,iBAAiB,CAAC,EAAU,EAAA;AAC1C,IAAA,MAAM,WAAW,GAAkB,yBAAyB,EAAE;IAE9D,OAAO,sBAAsB,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,WAAW,CAAC;AACvD;AAEA,SAAS,uBAAuB,CAAC,GAAW,EAAE,KAAa,EAAA;IACzD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE;QAC3B,MAAM,IAAI,KAAK,CAAC,CAAA,qBAAA,EAAwB,GAAG,CAAA,+BAAA,EAAkC,KAAK,CAAA,CAAA,CAAG,CAAC;IACxF;AAEA,IAAA,IAAI,KAAK,IAAI,CAAC,EAAE;QACd,MAAM,IAAI,KAAK,CAAC,CAAA,qBAAA,EAAwB,GAAG,CAAA,mBAAA,EAAsB,KAAK,CAAA,CAAA,CAAG,CAAC;IAC5E;AACF;AAEM,SAAU,oBAAoB,CAAC,GAAkB,EAAA;IACrD,MAAM,GAAG,GAA2B,EAAE;AAEtC,IAAA,KAAK,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE;AACjD,QAAA,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE;;;AAIzB,QAAA,IAAI,SAAS,EAAE;AAAE,YAAA,uBAAuB,CAAC,GAAG,EAAE,KAAK,CAAC;AAEpD,QAAA,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK;IAClB;AAEA,IAAA,OAAO,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC;AAC3B;AAEM,SAAU,eAAe,CAAC,OAAe,EAAA;AAC7C,IAAA,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,OAAO,IAAI,CAAC,IAAI,OAAO,GAAG,CAAC,EAAE;AAC5D,QAAA,MAAM,IAAI,KAAK,CAAC,4CAA4C,OAAO,CAAA,CAAE,CAAC;IACxE;AACF;AAEM,SAAU,eAAe,CAAC,KAAa,EAAA;AAC3C,IAAA,MAAM,OAAO,GAAW,MAAM,CAAC,qBAAqB,CAAC;IAErD,OAAO,KAAK,GAAG,OAAO;AACxB;;ACxEM,SAAU,sBAAsB,CAAC,GAAmB,EAAE,QAA+C,EAAA;AACzG,IAAA,IAAI,OAAO,GAAG,CAAC,gBAAgB,KAAK,UAAU,EAAE;;AAE9C,QAAA,GAAG,CAAC,gBAAgB,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC1C;SAAO;;AAEJ,QAAA,GAAW,CAAC,WAAW,CAAC,QAAQ,CAAC;IACpC;AACF;AAEM,SAAU,2BAA2B,CACzC,GAAmB,EACnB,QAA+C,EAAA;AAE/C,IAAA,IAAI,OAAO,GAAG,CAAC,mBAAmB,KAAK,UAAU,EAAE;;AAEjD,QAAA,GAAG,CAAC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC7C;SAAO;;AAEJ,QAAA,GAAW,CAAC,cAAc,CAAC,QAAQ,CAAC;IACvC;AACF;;ACjBA,MAAM,YAAY,GAAW,MAAM,CAAC,GAAG,CAAC,qBAAqB,CAAC;AAE9D,MAAM,WAAW,GAAG,MAAkB;IACpC,MAAM,WAAW,GAAiC,UAAU;IAE5D,QAAQ,WAAW,CAAC,YAAY,CAAC,KAAK,IAAI,GAAG,EAAE;AACjD,CAAC;AAED,MAAM,cAAc,GAAG,CAAC,KAAa,KAAc;AACjD,IAAA,MAAM,GAAG,GAAmB,UAAU,CAAC,KAAK,CAAC;AAC7C,IAAA,MAAMA,QAAM,GAA4BC,MAAY,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,CAAA,QAAA,EAAW,KAAK,CAAA,CAAE,EAAE,CAAC;AAEpG,IAAA,MAAM,QAAQ,GAAG,CAAC,KAA2B,KAAKD,QAAM,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC;AAE3F,IAAA,sBAAsB,CAAC,GAAG,EAAE,QAAQ,CAAC;AAErC,IAAA,OAAO,EAAE,GAAG,UAAEA,QAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,GAAG,EAAE,EAAE;AACxD,CAAC;SAEe,MAAM,CAAC,KAAa,EAAE,KAAoB,EAAE,QAAiB,EAAA;;AAE3E,IAAA,IAAI,OAAO,UAAU,CAAC,UAAU,KAAK,UAAU,EAAE;AAC/C,QAAA,OAAOC,MAAY,CAAC,QAAQ,CAAC,CAAC,UAAU,EAAE;IAC5C;AAEA,IAAA,MAAM,QAAQ,GAAgB,WAAW,EAAE;IAE3C,IAAI,MAAM,GAAyB,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;IAEtD,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC;AAC9B,QAAA,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC;IAC7B;AAEA,IAAA,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC;AAE3B,IAAA,OAAO,MAAM,CAAC,MAAM,CAAC,UAAU,EAAE;AACnC;AAEM,SAAU,OAAO,CAAC,KAAa,EAAE,KAAoB,EAAA;AACzD,IAAA,MAAM,QAAQ,GAAgB,WAAW,EAAE;IAE3C,IAAI,MAAM,GAAyB,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC;AAEtD,IAAA,IAAI,CAAC,MAAM;AAAE,QAAA,OAAO,KAAK;IAEzB,MAAM,OAAO,GAAY,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC;IAEvD,IAAI,MAAM,CAAC,SAAS,CAAC,IAAI,KAAK,CAAC,EAAE;QAC/B,2BAA2B,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC;AACxD,QAAA,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC;IACxB;AAEA,IAAA,OAAO,OAAO;AAChB;AAEA;;AAEG;SACa,YAAY,GAAA;IAC1B,OAAO,WAAW,EAAE;AACtB;AAEA;;AAEG;SACa,cAAc,GAAA;AAC5B,IAAA,MAAM,QAAQ,GAAgB,WAAW,EAAE;AAE3C,IAAA,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAgB,KAAI;QACpC,2BAA2B,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,QAAQ,CAAC;AAC1D,IAAA,CAAC,CAAC;IAEF,QAAQ,CAAC,KAAK,EAAE;AAClB;;AC3EM,SAAU,kBAAkB,CAAC,KAAa,EAAE,QAAiB,EAAA;AACjE,IAAA,MAAM,UAAU,GAAe,MAAM,CAAC,UAAU,CAAC;IAEjD,MAAM,WAAW,GAAoB,MAAM,CAAC,KAAK,EAAE,UAAU,EAAE,QAAQ,CAAC;AAExE,IAAA,UAAU,CAAC,SAAS,CAAC,MAAM,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AAEtD,IAAA,OAAO,WAAW;AACpB;;ACNM,SAAU,cAAc,CAAC,KAAa,EAAE,OAAiC,EAAA;AAC7E,IAAA,MAAM,eAAe,GAAY,MAAM,CAAC,gBAAgB,CAAC;AACzD,IAAA,MAAM,iBAAiB,GAAY,OAAO,EAAE,QAAQ,IAAI,eAAe;IAEvE,MAAM,WAAW,GAAoB,kBAAkB,CAAC,KAAK,EAAE,iBAAiB,CAAC;AAEjF,IAAA,OAAO,QAAQ,CAAC,MAAM,WAAW,EAAE,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AACzE;AAEM,SAAU,mBAAmB,CAAC,UAAkB,EAAA;IACpD,OAAO,CAAA,eAAA,EAAkB,UAAU,CAAA,CAAA,CAAG;AACxC;;AChBM,SAAU,cAAc,CAAC,KAAa,EAAA;AAC1C,IAAA,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,WAAW,EAAE;AACxD;;ACIA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACG,SAAU,EAAE,CAAC,EAAU,EAAE,OAAiC,EAAA;AAC9D,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,EAAE,CAAC;IAE3C,MAAM,KAAK,GAAW,cAAc,CAAC,CAAA,YAAA,EAAe,iBAAiB,CAAC,EAAE,CAAC,CAAA,GAAA,CAAK,CAAC;IAC/E,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,GAAA,EAAM,EAAE,CAAA,CAAA,CAAG,CAAC;AAE1D,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACG,SAAU,IAAI,CAAC,EAAU,EAAE,OAAiC,EAAA;AAChE,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,IAAI,CAAC;AAE7C,IAAA,MAAM,KAAK,GAAW,cAAc,CAAC,eAAe,eAAe,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAA,GAAA,CAAK,CAAC;IAChG,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,KAAA,EAAQ,EAAE,CAAA,CAAA,CAAG,CAAC;AAE5D,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;;;;;;AAsBG;SACa,OAAO,CAAC,KAAa,EAAE,KAAa,EAAE,OAAiC,EAAA;AACrF,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,OAAO,CAAC;AAEhD,IAAA,MAAM,KAAK,GAAW,iBAAiB,CAAC,KAAK,CAAC;AAC9C,IAAA,MAAM,KAAK,GAAW,iBAAiB,CAAC,KAAK,CAAC;AAC9C,IAAA,MAAM,KAAK,GAAW,cAAc,CAAC,CAAA,YAAA,EAAe,KAAK,CAAA,oBAAA,EAAuB,eAAe,CAAC,KAAK,CAAC,CAAA,GAAA,CAAK,CAAC;IAC5G,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,QAAA,EAAW,KAAK,CAAA,EAAA,EAAK,KAAK,CAAA,CAAA,CAAG,CAAC;AAE5E,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACG,SAAU,WAAW,CAAC,KAA+B,EAAE,OAAiC,EAAA;AAC5F,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,WAAW,CAAC;IAEpD,MAAM,KAAK,GAAW,cAAc,CAAC,iBAAiB,KAAK,CAAA,CAAA,CAAG,CAAC;IAC/D,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,YAAA,EAAe,KAAK,CAAA,CAAA,CAAG,CAAC;AAEtE,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACG,SAAU,WAAW,CAAC,KAAuB,EAAE,OAAiC,EAAA;AACpF,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,WAAW,CAAC;IAEpD,MAAM,KAAK,GAAW,cAAc,CAAC,0BAA0B,KAAK,CAAA,CAAA,CAAG,CAAC;IACxE,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,YAAA,EAAe,KAAK,CAAA,CAAA,CAAG,CAAC;AAEtE,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACG,SAAU,WAAW,CAAC,KAAwB,EAAE,OAAiC,EAAA;AACrF,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,WAAW,CAAC;IAEpD,MAAM,KAAK,GAAG,cAAc,CAAC,kBAAkB,KAAK,CAAA,CAAA,CAAG,CAAC;IACxD,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,YAAA,EAAe,KAAK,CAAA,CAAA,CAAG,CAAC;AAEtE,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACG,SAAU,aAAa,CAAC,OAAiC,EAAA;AAC7D,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,aAAa,CAAC;AAEtD,IAAA,MAAM,KAAK,GAAW,cAAc,CAAC,kCAAkC,CAAC;IACxE,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;IAEhE,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,eAAe,CAAC;AAE9D,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACG,SAAU,eAAe,CAC7B,KAAmD,EACnD,OAAiC,EAAA;AAEjC,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,eAAe,CAAC;IAExD,MAAM,KAAK,GAAW,cAAc,CAAC,sBAAsB,KAAK,CAAA,CAAA,CAAG,CAAC;IACpE,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,gBAAA,EAAmB,KAAK,CAAA,CAAA,CAAG,CAAC;AAE1E,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACG,SAAU,KAAK,CAAC,OAAiC,EAAA;AACrD,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,KAAK,CAAC;AAE9C,IAAA,MAAM,KAAK,GAAW,cAAc,CAAC,gBAAgB,CAAC;IACtD,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;IAEhE,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,OAAO,CAAC;AAEtD,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACG,SAAU,QAAQ,CAAC,OAAiC,EAAA;AACxD,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,QAAQ,CAAC;AAEjD,IAAA,MAAM,KAAK,GAAW,cAAc,CAAC,oBAAoB,CAAC;IAC1D,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;IAEhE,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,UAAU,CAAC;AAEzD,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACG,SAAU,OAAO,CAAC,KAAiC,EAAE,OAAiC,EAAA;AAC1F,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,OAAO,CAAC;IAEhD,MAAM,KAAK,GAAW,cAAc,CAAC,aAAa,KAAK,CAAA,CAAA,CAAG,CAAC;IAC3D,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,QAAA,EAAW,KAAK,CAAA,CAAA,CAAG,CAAC;AAElE,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;;AAkBG;AACG,SAAU,UAAU,CAAC,KAAiC,EAAE,OAAiC,EAAA;AAC7F,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,UAAU,CAAC;IAEnD,MAAM,KAAK,GAAW,cAAc,CAAC,iBAAiB,KAAK,CAAA,CAAA,CAAG,CAAC;IAC/D,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,WAAA,EAAc,KAAK,CAAA,CAAA,CAAG,CAAC;AAErE,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACG,SAAU,UAAU,CAAC,KAAgC,EAAE,OAAiC,EAAA;AAC5F,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,UAAU,CAAC;IAEnD,MAAM,KAAK,GAAW,cAAc,CAAC,iBAAiB,KAAK,CAAA,CAAA,CAAG,CAAC;IAC/D,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,WAAA,EAAc,KAAK,CAAA,CAAA,CAAG,CAAC;AAErE,IAAA,OAAO,QAAQ;AACjB;AAEA;;;;;;;;;;;;;;;;;;;;AAoBG;AACG,SAAU,gBAAgB,CAAC,KAAa,EAAE,OAAiC,EAAA;AAC/E,IAAA,SAAS,EAAE,IAAI,wBAAwB,CAAC,gBAAgB,CAAC;AAEzD,IAAA,MAAM,KAAK,GAAW,cAAc,CAAC,KAAK,CAAC;IAC3C,MAAM,QAAQ,GAAoB,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC;AAEhE,IAAA,QAAQ,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,iBAAA,EAAoB,KAAK,CAAA,CAAA,CAAG,CAAC;AAE3E,IAAA,OAAO,QAAQ;AACjB;;ACjbA,MAAM,QAAQ,GAAG,yBAAyB;AAE1C;AACA,SAAS,QAAQ,CAAC,SAA0B,EAAA;AAC1C,IAAA,MAAM,GAAG,GAAW,SAAS,CAAC,QAAQ,EAAE;IACxC,MAAM,KAAK,GAA2B,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;AAExD,IAAA,OAAO,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,GAAG,GAAG;AAC/B;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACG,SAAU,GAAG,CAAC,GAAG,UAA6B,EAAA;IAClD,MAAM,MAAM,GAAoB,QAAQ,CAAC,MAAM,UAAU,CAAC,KAAK,CAAC,CAAC,SAA0B,KAAK,SAAS,EAAE,CAAC,kDAAC;IAE7G,MAAM,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,IAAA,EAAO,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAAC;AAE1F,IAAA,OAAO,MAAM;AACf;AAEA;;;;;;;;;;;;;;;;;AAiBG;AACG,SAAU,EAAE,CAAC,GAAG,UAA6B,EAAA;IACjD,MAAM,MAAM,GAAoB,QAAQ,CAAC,MAAM,UAAU,CAAC,IAAI,CAAC,CAAC,SAA0B,KAAK,SAAS,EAAE,CAAC,kDAAC;IAE5G,MAAM,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,GAAA,EAAM,UAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA,CAAA,CAAG,CAAC;AAEzF,IAAA,OAAO,MAAM;AACf;AAEA;;;;;;;;;;;;;;;;AAgBG;AACG,SAAU,GAAG,CAAC,SAA0B,EAAA;IAC5C,MAAM,MAAM,GAAoB,QAAQ,CAAC,MAAM,CAAC,SAAS,EAAE,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,QAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;AAE5D,IAAA,MAAM,CAAC,QAAQ,GAAG,MAAM,mBAAmB,CAAC,CAAA,IAAA,EAAO,QAAQ,CAAC,SAAS,CAAC,CAAA,CAAA,CAAG,CAAC;AAE1E,IAAA,OAAO,MAAM;AACf;;AC7EA;;;;;;;;;;;;;;;;AAgBG;AACG,SAAU,kBAAkB,CAAC,GAAkB,EAAA;AACnD,IAAA,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,oBAAoB,CAAC,GAAG,CAAC,EAAE;AACzE;AAEA;;;;;;AAMG;SACa,0BAA0B,GAAA;AACxC,IAAA,OAAO,kBAAkB,CAAC,oBAAoB,CAAC;AACjD;AAEA;;;;;;AAMG;SACa,2BAA2B,GAAA;AACzC,IAAA,OAAO,kBAAkB,CAAC,qBAAqB,CAAC;AAClD;AAEA;;;;;;AAMG;SACa,0BAA0B,GAAA;AACxC,IAAA,OAAO,kBAAkB,CAAC,oBAAoB,CAAC;AACjD;AAEA;;;;;;;;;;;;;AAaG;AACG,SAAU,wBAAwB,CAAC,OAAA,GAAkB,0BAA0B,EAAA;;;AAGnF,IAAA,IAAI,SAAS,EAAE;QAAE,eAAe,CAAC,OAAO,CAAC;IAEzC,OAAO,EAAE,OAAO,EAAE,qBAAqB,EAAE,QAAQ,EAAE,OAAO,EAAE;AAC9D;AAEA;;;;;;;;;;;;;AAaG;AACG,SAAU,eAAe,CAAC,KAAc,EAAA;IAC5C,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,KAAK,EAAE;AACvD;;ACvGA;;;;;;AAMG;;ACNH;;AAEG;;;;"}
package/index.d.ts CHANGED
@@ -190,6 +190,25 @@ declare function displayMode(value: DisplayModeOption, options?: CreateMediaQuer
190
190
  * @category Media Features
191
191
  */
192
192
  declare function reducedMotion(options?: CreateMediaQueryOptions): Signal<boolean>;
193
+ /**
194
+ * Tracks the user's contrast preference via `(prefers-contrast: ...)`.
195
+ *
196
+ * @param value - `'more'`, `'less'`, `'no-preference'`, or `'custom'`.
197
+ * @param options - Optional per-call settings ({@link CreateMediaQueryOptions}).
198
+ * @returns A `Signal<boolean>` that is `true` while the contrast preference matches `value`.
199
+ *
200
+ * @remarks Must be called within an Angular
201
+ * [injection context](https://angular.dev/guide/di/dependency-injection-context).
202
+ *
203
+ * @example
204
+ * ```ts
205
+ * readonly wantsMoreContrast = prefersContrast('more');
206
+ * ```
207
+ *
208
+ * @see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-contrast | MDN: prefers-contrast}
209
+ * @category Media Features
210
+ */
211
+ declare function prefersContrast(value: 'more' | 'less' | 'no-preference' | 'custom', options?: CreateMediaQueryOptions): Signal<boolean>;
193
212
  /**
194
213
  * Tracks whether the **primary** input device can hover via `(hover: hover)`.
195
214
  *
@@ -462,5 +481,5 @@ declare function provideBreakpointEpsilon(epsilon?: number): Provider;
462
481
  */
463
482
  declare function provideSsrValue(value: boolean): Provider;
464
483
 
465
- export { MQ_BREAKPOINTS, MQ_BREAKPOINT_EPSILON, NGX_MQ_SSR_VALUE, and, anyHover, anyPointer, between, colorGamut, colorScheme, displayMode, down, hover, matchMediaSignal, not, or, orientation, pointer, provideBootstrapBreakpoints, provideBreakpointEpsilon, provideBreakpoints, provideMaterialBreakpoints, provideSsrValue, provideTailwindBreakpoints, reducedMotion, up };
484
+ 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 };
466
485
  export type { CreateMediaQueryOptions, DisplayModeOption, MqBreakpoints };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ngx-mq",
3
- "version": "3.0.0",
3
+ "version": "3.1.0",
4
4
  "description": "Signal-powered breakpoints and media queries for Angular. SSR-safe, zoneless-ready, no RxJS.",
5
5
  "repository": {
6
6
  "type": "git",