<commit_before>import {
    AfterContentInit,
    Component,
    ContentChild,
    ElementRef,
    EventEmitter,
    HostBinding,
    Inject,
    Input,
    OnChanges,
    OnDestroy,
    OnInit,
    Optional,
    Output,
    Renderer,
    SimpleChange,
    TemplateRef,
    ViewChild
} from '@angular/core';
import { fromEvent, interval, Observable, Subscription } from 'rxjs';
import { debounce } from 'rxjs/operators';
import { BaseComponent } from '../core/base';
import { IgxNavigationService, IToggleView } from '../core/navigation';
import { HammerGesturesManager } from '../core/touch';
import { IgxNavDrawerMiniTemplateDirective, IgxNavDrawerTemplateDirective } from './navigation-drawer.directives';

let NEXT_ID = 0;
/**
 * **Ignite UI for Angular Navigation Drawer** -
 * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navdrawer.html)
 *
 * The Ignite UI Navigation Drawer is a collapsible side navigation container commonly used in combination with the Navbar.
 *
 * Example:
 * ```html
 * <igx-nav-drawer id="navigation" [isOpen]="true">
 *   <ng-template igxDrawer>
 *     <nav>
 *       <span igxDrawerItem [isHeader]="true">Email</span>
 *       <span igxDrawerItem igxRipple>Inbox</span>
 *       <span igxDrawerItem igxRipple>Deleted</span>
 *       <span igxDrawerItem igxRipple>Sent</span>
 *     </nav>
 *   </ng-template>
 * </igx-nav-drawer>
 * ```
 */
@Component({
    providers: [HammerGesturesManager],
    selector: 'igx-nav-drawer',
    templateUrl: 'navigation-drawer.component.html'
})
export class IgxNavigationDrawerComponent implements
    IToggleView,
    OnInit,
    AfterContentInit,
    OnDestroy,
    OnChanges {

    @HostBinding('class') public cssClass = 'igx-nav-drawer';

    /**
     * ID of the component
     *
     * ```typescript
     * // get
     * let myNavDrawerId = this.navdrawer.id;
     * ```
     *
     * ```html
     * <!--set-->
     *  <igx-nav-drawer id='navdrawer'></igx-nav-drawer>
     * ```
     */
    @HostBinding('attr.id')
    @Input() public id = `igx-nav-drawer-${NEXT_ID++}`;

    /**
     * Position of the Navigation Drawer. Can be "left"(default) or "right".
     * Only has effect when not pinned.
     *
     * ```typescript
     * // get
     * let myNavDrawerPosition = this.navdrawer.position;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [position]="'left'"></igx-nav-drawer>
     * ```
     */
    @Input() public position = 'left';

    /**
     * Enables the use of touch gestures to manipulate the drawer:
     * - swipe/pan from edge to open, swipe-toggle and pan-drag.
     *
     * ```typescript
     * // get
     * let gesturesEnabled = this.navdrawer.enableGestures;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [enableGestures]='true'></igx-nav-drawer>
     * ```
     */
    @Input() public enableGestures = true;

    /**
     * State of the drawer.
     *
     * ```typescript
     * // get
     * let navDrawerIsOpen = this.navdrawer.isOpen;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [isOpen]='false'></igx-nav-drawer>
     * ```
     */
    @Input() public isOpen = false;

    /**
     * When pinned the drawer is relatively positioned instead of sitting above content.
     * May require additional layout styling.
     *
     * ```typescript
     * // get
     * let navDrawerIsPinned = this.navdrawer.pin;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [pin]='false'></igx-nav-drawer>
     * ```
     */
    @Input() public pin = false;

    /**
     * Minimum device width required for automatic pin to be toggled.
     * Default is 1024, can be set to a falsy value to disable this behavior.
     *
     * ```typescript
     * // get
     * let navDrawerPinTreshold = this.navdrawer.pinThreshold;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [pinTreshold]='1024'></igx-nav-drawer>
     * ```
     */
    @Input() public pinThreshold = 1024;

    /**
     * Returns nativeElement of the component.
     *
     * @hidden
     */
    get element() {
        return this.elementRef.nativeElement;
    }

    /**
     * Width of the drawer in its open state. Defaults to "280px".
     *
     * ```typescript
     * // get
     * let navDrawerWidth = this.navdrawer.width;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [width]="'228px'"></igx-nav-drawer>
     * ```
     */
    @Input() public width = '280px';

    /**
     * Width of the drawer in its mini state. Defaults to 60px.
     *
     * ```typescript
     * // get
     * let navDrawerMiniWidth = this.navdrawer.miniWidth;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [miniWidth]="'34px'"></igx-nav-drawer>
     * ```
     */
    @Input() public miniWidth = '60px';

    /**
     * Pinned state change output for two-way binding.
     *
     * ```html
     * <igx-nav-drawer [(pin)]='isPinned'></igx-nav-drawer>
     * ```
     */
    @Output() public pinChange = new EventEmitter<boolean>(true);
    /**
     * Event fired as the Navigation Drawer is about to open.
     *
     * ```html
     *  <igx-nav-drawer (opening)='onOpening()'></igx-nav-drawer>
     * ```
     */
    @Output() public opening = new EventEmitter();
    /**
     * Event fired when the Navigation Drawer has opened.
     *
     * ```html
     * <igx-nav-drawer (opened)='onOpened()'></igx-nav-drawer>
     * ```
     */
    @Output() public opened = new EventEmitter();
    /**
     * Event fired as the Navigation Drawer is about to close.
     *
     * ```html
     * <igx-nav-drawer (closing)='onClosing()'></igx-nav-drawer>
     * ```
     */
    @Output() public closing = new EventEmitter();
    /**
     * Event fired when the Navigation Drawer has closed.
     *
     * ```html
     * <igx-nav-drawer (closed)='onClosed()'></igx-nav-drawer>
     * ```
     */
    @Output() public closed = new EventEmitter();

    /**
     * @hidden
     */
    get template() {
        if (this.miniTemplate && !this.isOpen) {
            return this.miniTemplate.template;
        } else if (this.contentTemplate) {
            return this.contentTemplate.template;
        }
    }

    private _miniTemplate: IgxNavDrawerMiniTemplateDirective;
    /**
     * @hidden
     */
    public get miniTemplate(): IgxNavDrawerMiniTemplateDirective {
        return this._miniTemplate;
    }

    /**
     * @hidden
     */
    @ContentChild(IgxNavDrawerMiniTemplateDirective, { read: IgxNavDrawerMiniTemplateDirective })
    public set miniTemplate(v: IgxNavDrawerMiniTemplateDirective) {
        if (!this.isOpen) {
            this.setDrawerWidth(v ? this.miniWidth : '');
        }
        this._miniTemplate = v;
    }

    /**
     * @hidden
     */
    @ContentChild(IgxNavDrawerTemplateDirective, { read: IgxNavDrawerTemplateDirective })
    protected contentTemplate: IgxNavDrawerTemplateDirective;

    /**
     * @hidden
     */
    @HostBinding('style.flexBasis')
    get flexWidth() {
        if (!this.pin) {
            return '0px';
        }
        if (this.isOpen) {
            return this.width;
        }
        if (this.miniTemplate && this.miniWidth) {
            return this.miniWidth;
        }

        return '0px';
    }

    private _gesturesAttached = false;
    private _widthCache: { width: number, miniWidth: number } = { width: null, miniWidth: null };
    private _resizeObserver: Subscription;
    private css: { [name: string]: string; } = {
        drawer: 'igx-nav-drawer__aside',
        mini: 'igx-nav-drawer__aside--mini',
        overlay: 'igx-nav-drawer__overlay',
        styleDummy: 'igx-nav-drawer__style-dummy'
    };

    @ViewChild('aside') private _drawer: ElementRef;
    @ViewChild('overlay') private _overlay: ElementRef;
    @ViewChild('dummy') private _styleDummy: ElementRef;

    /**
     *  @hidden
     */
    get drawer() {
        return this._drawer.nativeElement;
    }

    /**
     * @hidden
     */
    get overlay() {
        return this._overlay.nativeElement;
    }

    /**
     *  @hidden
     */
    get styleDummy() {
        return this._styleDummy.nativeElement;
    }

    /** Pan animation properties */
    private _panning = false;
    private _panStartWidth: number;
    private _panLimit: number;
    private _previousDeltaX: number;

    /**
     * Property to decide whether to change width or translate the drawer from pan gesture.
     *
     * @hidden
     */
    public get hasAnimateWidth(): boolean {
        return this.pin || !!this.miniTemplate;
    }

    private _maxEdgeZone = 50;
    /**
     * Used for touch gestures (swipe and pan).
     * Defaults to 50 (in px) and is extended to at least 110% of the mini template width if available.
     *
     * @hidden
     */
    public get maxEdgeZone() {
        return this._maxEdgeZone;
    }

    /**
     * Gets the Drawer width for specific state.
     * Will attempt to evaluate requested state and cache.
     *
     *
     * @hidden
     */
    public get expectedWidth() {
        return this.getExpectedWidth(false);
    }

    /**
     * Get the Drawer mini width for specific state.
     * Will attempt to evaluate requested state and cache.
     *
     * @hidden
     */
    public get expectedMiniWidth() {
        return this.getExpectedWidth(true);
    }

    /**
     * @hidden
     */
    public get touchManager() {
        return this._touchManager;
    }

    /**
     * Exposes optional navigation service
     *
     * @hidden
     */
    public get state() {
        return this._state;
    }

    constructor(
        @Inject(ElementRef) private elementRef: ElementRef,
        @Optional() private _state: IgxNavigationService,
        // private animate: AnimationBuilder, TODO
        protected renderer: Renderer,
        private _touchManager: HammerGesturesManager) {
    }

    /**
     * @hidden
     */
    public ngOnInit() {
        // DOM and @Input()-s initialized
        if (this._state) {
            this._state.add(this.id, this);
        }
        if (this.isOpen) {
            this.setDrawerWidth(this.width);
        }
    }

    /**
     * @hidden
     */
    public ngAfterContentInit() {
        // wait for template and ng-content to be ready
        this.updateEdgeZone();
        this.checkPinThreshold();

        // need to set height without absolute positioning
        this.ensureDrawerHeight();
        this.ensureEvents();

        // TODO: apply platform-safe Ruler from http://plnkr.co/edit/81nWDyreYMzkunihfRgX?p=preview
        // (https://github.com/angular/angular/issues/6515), blocked by https://github.com/angular/angular/issues/6904
    }

    /**
     * @hidden
     */
    public ngOnDestroy() {
        this._touchManager.destroy();
        if (this._state) {
            this._state.remove(this.id);
        }
        if (this._resizeObserver) {
            this._resizeObserver.unsubscribe();
        }
    }

    /**
     * @hidden
     */
    public ngOnChanges(changes: { [propName: string]: SimpleChange }) {
        // simple settings can come from attribute set (rather than binding), make sure boolean props are converted
        if (changes.enableGestures && changes.enableGestures.currentValue !== undefined) {
            this.enableGestures = !!(this.enableGestures && this.enableGestures.toString() === 'true');
            this.ensureEvents();
        }
        if (changes.pin && changes.pin.currentValue !== undefined) {
            this.pin = !!(this.pin && this.pin.toString() === 'true');
            this.ensureDrawerHeight();
            if (this.pin) {
                this._touchManager.destroy();
                this._gesturesAttached = false;
            } else {
                this.ensureEvents();
            }
        }

        if (changes.pinThreshold) {
            if (this.pinThreshold) {
                this.ensureEvents();
                this.checkPinThreshold();
            } else if (this._resizeObserver) {
                this._resizeObserver.unsubscribe();
                this._resizeObserver = null;
            }
        }

        if (changes.width && this.isOpen) {
            this.setDrawerWidth(changes.width.currentValue);
        }

        if (changes.miniWidth) {
            if (!this.isOpen) {
                this.setDrawerWidth(changes.miniWidth.currentValue);
            }
            this.updateEdgeZone();
        }
    }

    /**
     * Toggle the open state of the Navigation Drawer.
     *
     * ```typescript
     * let fireEvents = true;
     * this.navdrawer.toggle(fireEvents);
     * ```
     *
     * @param [fireEvents] - Optional flag determining whether events should be fired or not.
     */
    public toggle(fireEvents?: boolean) {
        if (this.isOpen) {
            this.close(fireEvents);
        } else {<commit_msg>fix(igx-grid): Remove code that unsubscribe from resize event, #1641<commit_after>import {
    AfterContentInit,
    Component,
    ContentChild,
    ElementRef,
    EventEmitter,
    HostBinding,
    Inject,
    Input,
    OnChanges,
    OnDestroy,
    OnInit,
    Optional,
    Output,
    Renderer,
    SimpleChange,
    TemplateRef,
    ViewChild
} from '@angular/core';
import { fromEvent, interval, Observable, Subscription } from 'rxjs';
import { debounce } from 'rxjs/operators';
import { BaseComponent } from '../core/base';
import { IgxNavigationService, IToggleView } from '../core/navigation';
import { HammerGesturesManager } from '../core/touch';
import { IgxNavDrawerMiniTemplateDirective, IgxNavDrawerTemplateDirective } from './navigation-drawer.directives';

let NEXT_ID = 0;
/**
 * **Ignite UI for Angular Navigation Drawer** -
 * [Documentation](https://www.infragistics.com/products/ignite-ui-angular/angular/components/navdrawer.html)
 *
 * The Ignite UI Navigation Drawer is a collapsible side navigation container commonly used in combination with the Navbar.
 *
 * Example:
 * ```html
 * <igx-nav-drawer id="navigation" [isOpen]="true">
 *   <ng-template igxDrawer>
 *     <nav>
 *       <span igxDrawerItem [isHeader]="true">Email</span>
 *       <span igxDrawerItem igxRipple>Inbox</span>
 *       <span igxDrawerItem igxRipple>Deleted</span>
 *       <span igxDrawerItem igxRipple>Sent</span>
 *     </nav>
 *   </ng-template>
 * </igx-nav-drawer>
 * ```
 */
@Component({
    providers: [HammerGesturesManager],
    selector: 'igx-nav-drawer',
    templateUrl: 'navigation-drawer.component.html'
})
export class IgxNavigationDrawerComponent implements
    IToggleView,
    OnInit,
    AfterContentInit,
    OnDestroy,
    OnChanges {

    @HostBinding('class') public cssClass = 'igx-nav-drawer';

    /**
     * ID of the component
     *
     * ```typescript
     * // get
     * let myNavDrawerId = this.navdrawer.id;
     * ```
     *
     * ```html
     * <!--set-->
     *  <igx-nav-drawer id='navdrawer'></igx-nav-drawer>
     * ```
     */
    @HostBinding('attr.id')
    @Input() public id = `igx-nav-drawer-${NEXT_ID++}`;

    /**
     * Position of the Navigation Drawer. Can be "left"(default) or "right".
     * Only has effect when not pinned.
     *
     * ```typescript
     * // get
     * let myNavDrawerPosition = this.navdrawer.position;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [position]="'left'"></igx-nav-drawer>
     * ```
     */
    @Input() public position = 'left';

    /**
     * Enables the use of touch gestures to manipulate the drawer:
     * - swipe/pan from edge to open, swipe-toggle and pan-drag.
     *
     * ```typescript
     * // get
     * let gesturesEnabled = this.navdrawer.enableGestures;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [enableGestures]='true'></igx-nav-drawer>
     * ```
     */
    @Input() public enableGestures = true;

    /**
     * State of the drawer.
     *
     * ```typescript
     * // get
     * let navDrawerIsOpen = this.navdrawer.isOpen;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [isOpen]='false'></igx-nav-drawer>
     * ```
     */
    @Input() public isOpen = false;

    /**
     * When pinned the drawer is relatively positioned instead of sitting above content.
     * May require additional layout styling.
     *
     * ```typescript
     * // get
     * let navDrawerIsPinned = this.navdrawer.pin;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [pin]='false'></igx-nav-drawer>
     * ```
     */
    @Input() public pin = false;

    /**
     * Minimum device width required for automatic pin to be toggled.
     * Default is 1024, can be set to a falsy value to disable this behavior.
     *
     * ```typescript
     * // get
     * let navDrawerPinTreshold = this.navdrawer.pinThreshold;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [pinTreshold]='1024'></igx-nav-drawer>
     * ```
     */
    @Input() public pinThreshold = 1024;

    /**
     * Returns nativeElement of the component.
     *
     * @hidden
     */
    get element() {
        return this.elementRef.nativeElement;
    }

    /**
     * Width of the drawer in its open state. Defaults to "280px".
     *
     * ```typescript
     * // get
     * let navDrawerWidth = this.navdrawer.width;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [width]="'228px'"></igx-nav-drawer>
     * ```
     */
    @Input() public width = '280px';

    /**
     * Width of the drawer in its mini state. Defaults to 60px.
     *
     * ```typescript
     * // get
     * let navDrawerMiniWidth = this.navdrawer.miniWidth;
     * ```
     *
     * ```html
     * <!--set-->
     * <igx-nav-drawer [miniWidth]="'34px'"></igx-nav-drawer>
     * ```
     */
    @Input() public miniWidth = '60px';

    /**
     * Pinned state change output for two-way binding.
     *
     * ```html
     * <igx-nav-drawer [(pin)]='isPinned'></igx-nav-drawer>
     * ```
     */
    @Output() public pinChange = new EventEmitter<boolean>(true);
    /**
     * Event fired as the Navigation Drawer is about to open.
     *
     * ```html
     *  <igx-nav-drawer (opening)='onOpening()'></igx-nav-drawer>
     * ```
     */
    @Output() public opening = new EventEmitter();
    /**
     * Event fired when the Navigation Drawer has opened.
     *
     * ```html
     * <igx-nav-drawer (opened)='onOpened()'></igx-nav-drawer>
     * ```
     */
    @Output() public opened = new EventEmitter();
    /**
     * Event fired as the Navigation Drawer is about to close.
     *
     * ```html
     * <igx-nav-drawer (closing)='onClosing()'></igx-nav-drawer>
     * ```
     */
    @Output() public closing = new EventEmitter();
    /**
     * Event fired when the Navigation Drawer has closed.
     *
     * ```html
     * <igx-nav-drawer (closed)='onClosed()'></igx-nav-drawer>
     * ```
     */
    @Output() public closed = new EventEmitter();

    /**
     * @hidden
     */
    get template() {
        if (this.miniTemplate && !this.isOpen) {
            return this.miniTemplate.template;
        } else if (this.contentTemplate) {
            return this.contentTemplate.template;
        }
    }

    private _miniTemplate: IgxNavDrawerMiniTemplateDirective;
    /**
     * @hidden
     */
    public get miniTemplate(): IgxNavDrawerMiniTemplateDirective {
        return this._miniTemplate;
    }

    /**
     * @hidden
     */
    @ContentChild(IgxNavDrawerMiniTemplateDirective, { read: IgxNavDrawerMiniTemplateDirective })
    public set miniTemplate(v: IgxNavDrawerMiniTemplateDirective) {
        if (!this.isOpen) {
            this.setDrawerWidth(v ? this.miniWidth : '');
        }
        this._miniTemplate = v;
    }

    /**
     * @hidden
     */
    @ContentChild(IgxNavDrawerTemplateDirective, { read: IgxNavDrawerTemplateDirective })
    protected contentTemplate: IgxNavDrawerTemplateDirective;

    /**
     * @hidden
     */
    @HostBinding('style.flexBasis')
    get flexWidth() {
        if (!this.pin) {
            return '0px';
        }
        if (this.isOpen) {
            return this.width;
        }
        if (this.miniTemplate && this.miniWidth) {
            return this.miniWidth;
        }

        return '0px';
    }

    private _gesturesAttached = false;
    private _widthCache: { width: number, miniWidth: number } = { width: null, miniWidth: null };
    private _resizeObserver: Subscription;
    private css: { [name: string]: string; } = {
        drawer: 'igx-nav-drawer__aside',
        mini: 'igx-nav-drawer__aside--mini',
        overlay: 'igx-nav-drawer__overlay',
        styleDummy: 'igx-nav-drawer__style-dummy'
    };

    @ViewChild('aside') private _drawer: ElementRef;
    @ViewChild('overlay') private _overlay: ElementRef;
    @ViewChild('dummy') private _styleDummy: ElementRef;

    /**
     *  @hidden
     */
    get drawer() {
        return this._drawer.nativeElement;
    }

    /**
     * @hidden
     */
    get overlay() {
        return this._overlay.nativeElement;
    }

    /**
     *  @hidden
     */
    get styleDummy() {
        return this._styleDummy.nativeElement;
    }

    /** Pan animation properties */
    private _panning = false;
    private _panStartWidth: number;
    private _panLimit: number;
    private _previousDeltaX: number;

    /**
     * Property to decide whether to change width or translate the drawer from pan gesture.
     *
     * @hidden
     */
    public get hasAnimateWidth(): boolean {
        return this.pin || !!this.miniTemplate;
    }

    private _maxEdgeZone = 50;
    /**
     * Used for touch gestures (swipe and pan).
     * Defaults to 50 (in px) and is extended to at least 110% of the mini template width if available.
     *
     * @hidden
     */
    public get maxEdgeZone() {
        return this._maxEdgeZone;
    }

    /**
     * Gets the Drawer width for specific state.
     * Will attempt to evaluate requested state and cache.
     *
     *
     * @hidden
     */
    public get expectedWidth() {
        return this.getExpectedWidth(false);
    }

    /**
     * Get the Drawer mini width for specific state.
     * Will attempt to evaluate requested state and cache.
     *
     * @hidden
     */
    public get expectedMiniWidth() {
        return this.getExpectedWidth(true);
    }

    /**
     * @hidden
     */
    public get touchManager() {
        return this._touchManager;
    }

    /**
     * Exposes optional navigation service
     *
     * @hidden
     */
    public get state() {
        return this._state;
    }

    constructor(
        @Inject(ElementRef) private elementRef: ElementRef,
        @Optional() private _state: IgxNavigationService,
        // private animate: AnimationBuilder, TODO
        protected renderer: Renderer,
        private _touchManager: HammerGesturesManager) {
    }

    /**
     * @hidden
     */
    public ngOnInit() {
        // DOM and @Input()-s initialized
        if (this._state) {
            this._state.add(this.id, this);
        }
        if (this.isOpen) {
            this.setDrawerWidth(this.width);
        }
    }

    /**
     * @hidden
     */
    public ngAfterContentInit() {
        // wait for template and ng-content to be ready
        this.updateEdgeZone();
        this.checkPinThreshold();

        // need to set height without absolute positioning
        this.ensureDrawerHeight();
        this.ensureEvents();

        // TODO: apply platform-safe Ruler from http://plnkr.co/edit/81nWDyreYMzkunihfRgX?p=preview
        // (https://github.com/angular/angular/issues/6515), blocked by https://github.com/angular/angular/issues/6904
    }

    /**
     * @hidden
     */
    public ngOnDestroy() {
        this._touchManager.destroy();
        if (this._state) {
            this._state.remove(this.id);
        }
        if (this._resizeObserver) {
            this._resizeObserver.unsubscribe();
        }
    }

    /**
     * @hidden
     */
    public ngOnChanges(changes: { [propName: string]: SimpleChange }) {
        // simple settings can come from attribute set (rather than binding), make sure boolean props are converted
        if (changes.enableGestures && changes.enableGestures.currentValue !== undefined) {
            this.enableGestures = !!(this.enableGestures && this.enableGestures.toString() === 'true');
            this.ensureEvents();
        }
        if (changes.pin && changes.pin.currentValue !== undefined) {
            this.pin = !!(this.pin && this.pin.toString() === 'true');
            this.ensureDrawerHeight();
            if (this.pin) {
                this._touchManager.destroy();
                this._gesturesAttached = false;
            } else {
                this.ensureEvents();
            }
        }

        if (changes.pinThreshold) {
            if (this.pinThreshold) {
                this.ensureEvents();
                this.checkPinThreshold();
            }
        }

        if (changes.width && this.isOpen) {
            this.setDrawerWidth(changes.width.currentValue);
        }

        if (changes.miniWidth) {
            if (!this.isOpen) {
                this.setDrawerWidth(changes.miniWidth.currentValue);
            }
            this.updateEdgeZone();
        }
    }

    /**
     * Toggle the open state of the Navigation Drawer.
     *
     * ```typescript
     * let fireEvents = true;
     * this.navdrawer.toggle(fireEvents);
     * ```
     *
     * @param [fireEvents] - Optional flag determining whether events should be fired or not.
     */
    public toggle(fireEvents?: boolean) {
        if (this.isOpen) {
            this.close(fireEvents);
        } else {
{'fraction_non_alphanumeric': 0.13688553302455922, 'fraction_numerical': 0.0038142684777955085, 'mean_word_length': 2.031740412979351, 'pattern_counts': {'":': 0, '<': 101, '<?xml version=': 0, '>': 101, 'https://': 6, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2657370', 'n_tokens_mistral': 8091, 'n_tokens_neox': 7873, 'n_words': 1700}