import * as i0 from '@angular/core'; import { NgModule, CSP_NONCE, Injectable, Optional, Inject } from '@angular/core'; import { coerceArray } from '@angular/cdk/coercion'; import { Subject, combineLatest, concat, Observable } from 'rxjs'; import { take, skip, debounceTime, map, startWith, takeUntil } from 'rxjs/operators'; import * as i1 from '@angular/cdk/platform'; class LayoutModule { static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: LayoutModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); } static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "16.1.1", ngImport: i0, type: LayoutModule }); } static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: LayoutModule }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: LayoutModule, decorators: [{ type: NgModule, args: [{}] }] }); /** Global registry for all dynamically-created, injected media queries. */ const mediaQueriesForWebkitCompatibility = new Set(); /** Style tag that holds all of the dynamically-created media queries. */ let mediaQueryStyleNode; /** A utility for calling matchMedia queries. */ class MediaMatcher { constructor(_platform, _nonce) { this._platform = _platform; this._nonce = _nonce; this._matchMedia = this._platform.isBrowser && window.matchMedia ? // matchMedia is bound to the window scope intentionally as it is an illegal invocation to // call it from a different scope. window.matchMedia.bind(window) : noopMatchMedia; } /** * Evaluates the given media query and returns the native MediaQueryList from which results * can be retrieved. * Confirms the layout engine will trigger for the selector query provided and returns the * MediaQueryList for the query provided. */ matchMedia(query) { if (this._platform.WEBKIT || this._platform.BLINK) { createEmptyStyleRule(query, this._nonce); } return this._matchMedia(query); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: MediaMatcher, deps: [{ token: i1.Platform }, { token: CSP_NONCE, optional: true }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: MediaMatcher, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: MediaMatcher, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: i1.Platform }, { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [CSP_NONCE] }] }]; } }); /** * Creates an empty stylesheet that is used to work around browser inconsistencies related to * `matchMedia`. At the time of writing, it handles the following cases: * 1. On WebKit browsers, a media query has to have at least one rule in order for `matchMedia` * to fire. We work around it by declaring a dummy stylesheet with a `@media` declaration. * 2. In some cases Blink browsers will stop firing the `matchMedia` listener if none of the rules * inside the `@media` match existing elements on the page. We work around it by having one rule * targeting the `body`. See https://github.com/angular/components/issues/23546. */ function createEmptyStyleRule(query, nonce) { if (mediaQueriesForWebkitCompatibility.has(query)) { return; } try { if (!mediaQueryStyleNode) { mediaQueryStyleNode = document.createElement('style'); if (nonce) { mediaQueryStyleNode.nonce = nonce; } mediaQueryStyleNode.setAttribute('type', 'text/css'); document.head.appendChild(mediaQueryStyleNode); } if (mediaQueryStyleNode.sheet) { mediaQueryStyleNode.sheet.insertRule(`@media ${query} {body{ }}`, 0); mediaQueriesForWebkitCompatibility.add(query); } } catch (e) { console.error(e); } } /** No-op matchMedia replacement for non-browser platforms. */ function noopMatchMedia(query) { // Use `as any` here to avoid adding additional necessary properties for // the noop matcher. return { matches: query === 'all' || query === '', media: query, addListener: () => { }, removeListener: () => { }, }; } /** Utility for checking the matching state of @media queries. */ class BreakpointObserver { constructor(_mediaMatcher, _zone) { this._mediaMatcher = _mediaMatcher; this._zone = _zone; /** A map of all media queries currently being listened for. */ this._queries = new Map(); /** A subject for all other observables to takeUntil based on. */ this._destroySubject = new Subject(); } /** Completes the active subject, signalling to all other observables to complete. */ ngOnDestroy() { this._destroySubject.next(); this._destroySubject.complete(); } /** * Whether one or more media queries match the current viewport size. * @param value One or more media queries to check. * @returns Whether any of the media queries match. */ isMatched(value) { const queries = splitQueries(coerceArray(value)); return queries.some(mediaQuery => this._registerQuery(mediaQuery).mql.matches); } /** * Gets an observable of results for the given queries that will emit new results for any changes * in matching of the given queries. * @param value One or more media queries to check. * @returns A stream of matches for the given queries. */ observe(value) { const queries = splitQueries(coerceArray(value)); const observables = queries.map(query => this._registerQuery(query).observable); let stateObservable = combineLatest(observables); // Emit the first state immediately, and then debounce the subsequent emissions. stateObservable = concat(stateObservable.pipe(take(1)), stateObservable.pipe(skip(1), debounceTime(0))); return stateObservable.pipe(map(breakpointStates => { const response = { matches: false, breakpoints: {}, }; breakpointStates.forEach(({ matches, query }) => { response.matches = response.matches || matches; response.breakpoints[query] = matches; }); return response; })); } /** Registers a specific query to be listened for. */ _registerQuery(query) { // Only set up a new MediaQueryList if it is not already being listened for. if (this._queries.has(query)) { return this._queries.get(query); } const mql = this._mediaMatcher.matchMedia(query); // Create callback for match changes and add it is as a listener. const queryObservable = new Observable((observer) => { // Listener callback methods are wrapped to be placed back in ngZone. Callbacks must be placed // back into the zone because matchMedia is only included in Zone.js by loading the // webapis-media-query.js file alongside the zone.js file. Additionally, some browsers do not // have MediaQueryList inherit from EventTarget, which causes inconsistencies in how Zone.js // patches it. const handler = (e) => this._zone.run(() => observer.next(e)); mql.addListener(handler); return () => { mql.removeListener(handler); }; }).pipe(startWith(mql), map(({ matches }) => ({ query, matches })), takeUntil(this._destroySubject)); // Add the MediaQueryList to the set of queries. const output = { observable: queryObservable, mql }; this._queries.set(query, output); return output; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: BreakpointObserver, deps: [{ token: MediaMatcher }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Injectable }); } static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: BreakpointObserver, providedIn: 'root' }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.1.1", ngImport: i0, type: BreakpointObserver, decorators: [{ type: Injectable, args: [{ providedIn: 'root' }] }], ctorParameters: function () { return [{ type: MediaMatcher }, { type: i0.NgZone }]; } }); /** * Split each query string into separate query strings if two queries are provided as comma * separated. */ function splitQueries(queries) { return queries .map(query => query.split(',')) .reduce((a1, a2) => a1.concat(a2)) .map(query => query.trim()); } // PascalCase is being used as Breakpoints is used like an enum. // tslint:disable-next-line:variable-name const Breakpoints = { XSmall: '(max-width: 599.98px)', Small: '(min-width: 600px) and (max-width: 959.98px)', Medium: '(min-width: 960px) and (max-width: 1279.98px)', Large: '(min-width: 1280px) and (max-width: 1919.98px)', XLarge: '(min-width: 1920px)', Handset: '(max-width: 599.98px) and (orientation: portrait), ' + '(max-width: 959.98px) and (orientation: landscape)', Tablet: '(min-width: 600px) and (max-width: 839.98px) and (orientation: portrait), ' + '(min-width: 960px) and (max-width: 1279.98px) and (orientation: landscape)', Web: '(min-width: 840px) and (orientation: portrait), ' + '(min-width: 1280px) and (orientation: landscape)', HandsetPortrait: '(max-width: 599.98px) and (orientation: portrait)', TabletPortrait: '(min-width: 600px) and (max-width: 839.98px) and (orientation: portrait)', WebPortrait: '(min-width: 840px) and (orientation: portrait)', HandsetLandscape: '(max-width: 959.98px) and (orientation: landscape)', TabletLandscape: '(min-width: 960px) and (max-width: 1279.98px) and (orientation: landscape)', WebLandscape: '(min-width: 1280px) and (orientation: landscape)', }; /** * Generated bundle index. Do not edit. */ export { BreakpointObserver, Breakpoints, LayoutModule, MediaMatcher }; //# sourceMappingURL=layout.mjs.map