@angular/material
Version:
Angular Material
1 lines • 76.4 kB
Source Map (JSON)
{"version":3,"file":"sidenav.mjs","sources":["../../../../../darwin_arm64-fastbuild-ST-46c76129e412/bin/src/material/sidenav/drawer.ts","../../../../../darwin_arm64-fastbuild-ST-46c76129e412/bin/src/material/sidenav/drawer.html","../../../../../darwin_arm64-fastbuild-ST-46c76129e412/bin/src/material/sidenav/drawer-container.html","../../../../../darwin_arm64-fastbuild-ST-46c76129e412/bin/src/material/sidenav/sidenav.ts","../../../../../darwin_arm64-fastbuild-ST-46c76129e412/bin/src/material/sidenav/sidenav-container.html","../../../../../darwin_arm64-fastbuild-ST-46c76129e412/bin/src/material/sidenav/sidenav-module.ts","../../../../../darwin_arm64-fastbuild-ST-46c76129e412/bin/src/material/sidenav/drawer-animations.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\nimport {\n FocusMonitor,\n FocusOrigin,\n FocusTrap,\n FocusTrapFactory,\n InteractivityChecker,\n} from '@angular/cdk/a11y';\nimport {Directionality} from '@angular/cdk/bidi';\nimport {BooleanInput, coerceBooleanProperty} from '@angular/cdk/coercion';\nimport {ESCAPE, hasModifierKey} from '@angular/cdk/keycodes';\nimport {Platform} from '@angular/cdk/platform';\nimport {CdkScrollable, ScrollDispatcher, ViewportRuler} from '@angular/cdk/scrolling';\nimport {DOCUMENT} from '@angular/common';\nimport {\n AfterContentInit,\n afterNextRender,\n AfterViewInit,\n ANIMATION_MODULE_TYPE,\n ChangeDetectionStrategy,\n ChangeDetectorRef,\n Component,\n ContentChild,\n ContentChildren,\n DoCheck,\n ElementRef,\n EventEmitter,\n inject,\n InjectionToken,\n Injector,\n Input,\n NgZone,\n OnDestroy,\n Output,\n QueryList,\n Renderer2,\n ViewChild,\n ViewEncapsulation,\n} from '@angular/core';\nimport {fromEvent, merge, Observable, Subject} from 'rxjs';\nimport {debounceTime, filter, map, mapTo, startWith, take, takeUntil} from 'rxjs/operators';\n\n/**\n * Throws an exception when two MatDrawer are matching the same position.\n * @docs-private\n */\nexport function throwMatDuplicatedDrawerError(position: string) {\n throw Error(`A drawer was already declared for 'position=\"${position}\"'`);\n}\n\n/** Options for where to set focus to automatically on dialog open */\nexport type AutoFocusTarget = 'dialog' | 'first-tabbable' | 'first-heading';\n\n/** Result of the toggle promise that indicates the state of the drawer. */\nexport type MatDrawerToggleResult = 'open' | 'close';\n\n/** Drawer and SideNav display modes. */\nexport type MatDrawerMode = 'over' | 'push' | 'side';\n\n/** Configures whether drawers should use auto sizing by default. */\nexport const MAT_DRAWER_DEFAULT_AUTOSIZE = new InjectionToken<boolean>(\n 'MAT_DRAWER_DEFAULT_AUTOSIZE',\n {\n providedIn: 'root',\n factory: MAT_DRAWER_DEFAULT_AUTOSIZE_FACTORY,\n },\n);\n\n/**\n * Used to provide a drawer container to a drawer while avoiding circular references.\n * @docs-private\n */\nexport const MAT_DRAWER_CONTAINER = new InjectionToken('MAT_DRAWER_CONTAINER');\n\n/**\n * @docs-private\n * @deprecated No longer used, will be removed.\n * @breaking-change 21.0.0\n */\nexport function MAT_DRAWER_DEFAULT_AUTOSIZE_FACTORY(): boolean {\n return false;\n}\n\n@Component({\n selector: 'mat-drawer-content',\n template: '<ng-content></ng-content>',\n host: {\n 'class': 'mat-drawer-content',\n '[style.margin-left.px]': '_container._contentMargins.left',\n '[style.margin-right.px]': '_container._contentMargins.right',\n '[class.mat-drawer-content-hidden]': '_shouldBeHidden()',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n providers: [\n {\n provide: CdkScrollable,\n useExisting: MatDrawerContent,\n },\n ],\n})\nexport class MatDrawerContent extends CdkScrollable implements AfterContentInit {\n private _platform = inject(Platform);\n private _changeDetectorRef = inject(ChangeDetectorRef);\n _container = inject(MatDrawerContainer);\n\n constructor(...args: unknown[]);\n\n constructor() {\n const elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n const scrollDispatcher = inject(ScrollDispatcher);\n const ngZone = inject(NgZone);\n\n super(elementRef, scrollDispatcher, ngZone);\n }\n\n ngAfterContentInit() {\n this._container._contentMarginChanges.subscribe(() => {\n this._changeDetectorRef.markForCheck();\n });\n }\n\n /** Determines whether the content element should be hidden from the user. */\n protected _shouldBeHidden(): boolean {\n // In some modes the content is pushed based on the width of the opened sidenavs, however on\n // the server we can't measure the sidenav so the margin is always zero. This can cause the\n // content to jump around when it's rendered on the server and hydrated on the client. We\n // avoid it by hiding the content on the initial render and then showing it once the sidenav\n // has been measured on the client.\n if (this._platform.isBrowser) {\n return false;\n }\n\n const {start, end} = this._container;\n return (\n (start != null && start.mode !== 'over' && start.opened) ||\n (end != null && end.mode !== 'over' && end.opened)\n );\n }\n}\n\n/**\n * This component corresponds to a drawer that can be opened on the drawer container.\n */\n@Component({\n selector: 'mat-drawer',\n exportAs: 'matDrawer',\n templateUrl: 'drawer.html',\n host: {\n 'class': 'mat-drawer',\n // must prevent the browser from aligning text based on value\n '[attr.align]': 'null',\n '[class.mat-drawer-end]': 'position === \"end\"',\n '[class.mat-drawer-over]': 'mode === \"over\"',\n '[class.mat-drawer-push]': 'mode === \"push\"',\n '[class.mat-drawer-side]': 'mode === \"side\"',\n // The styles that render the sidenav off-screen come from the drawer container. Prior to #30235\n // this was also done by the animations module which some internal tests seem to depend on.\n // Simulate it by toggling the `hidden` attribute instead.\n '[style.visibility]': '(!_container && !opened) ? \"hidden\" : null',\n 'tabIndex': '-1',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [CdkScrollable],\n})\nexport class MatDrawer implements AfterViewInit, OnDestroy {\n private _elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n private _focusTrapFactory = inject(FocusTrapFactory);\n private _focusMonitor = inject(FocusMonitor);\n private _platform = inject(Platform);\n private _ngZone = inject(NgZone);\n private _renderer = inject(Renderer2);\n private readonly _interactivityChecker = inject(InteractivityChecker);\n private _doc = inject(DOCUMENT, {optional: true})!;\n _container? = inject<MatDrawerContainer>(MAT_DRAWER_CONTAINER, {optional: true});\n\n private _focusTrap: FocusTrap | null = null;\n private _elementFocusedBeforeDrawerWasOpened: HTMLElement | null = null;\n private _eventCleanups: (() => void)[];\n\n /** Whether the view of the component has been attached. */\n private _isAttached: boolean;\n\n /** Anchor node used to restore the drawer to its initial position. */\n private _anchor: Comment | null;\n\n /** The side that the drawer is attached to. */\n @Input()\n get position(): 'start' | 'end' {\n return this._position;\n }\n set position(value: 'start' | 'end') {\n // Make sure we have a valid value.\n value = value === 'end' ? 'end' : 'start';\n if (value !== this._position) {\n // Static inputs in Ivy are set before the element is in the DOM.\n if (this._isAttached) {\n this._updatePositionInParent(value);\n }\n\n this._position = value;\n this.onPositionChanged.emit();\n }\n }\n private _position: 'start' | 'end' = 'start';\n\n /** Mode of the drawer; one of 'over', 'push' or 'side'. */\n @Input()\n get mode(): MatDrawerMode {\n return this._mode;\n }\n set mode(value: MatDrawerMode) {\n this._mode = value;\n this._updateFocusTrapState();\n this._modeChanged.next();\n }\n private _mode: MatDrawerMode = 'over';\n\n /** Whether the drawer can be closed with the escape key or by clicking on the backdrop. */\n @Input()\n get disableClose(): boolean {\n return this._disableClose;\n }\n set disableClose(value: BooleanInput) {\n this._disableClose = coerceBooleanProperty(value);\n }\n private _disableClose: boolean = false;\n\n /**\n * Whether the drawer should focus the first focusable element automatically when opened.\n * Defaults to false in when `mode` is set to `side`, otherwise defaults to `true`. If explicitly\n * enabled, focus will be moved into the sidenav in `side` mode as well.\n * @breaking-change 14.0.0 Remove boolean option from autoFocus. Use string or AutoFocusTarget\n * instead.\n */\n @Input()\n get autoFocus(): AutoFocusTarget | string | boolean {\n const value = this._autoFocus;\n\n // Note that usually we don't allow autoFocus to be set to `first-tabbable` in `side` mode,\n // because we don't know how the sidenav is being used, but in some cases it still makes\n // sense to do it. The consumer can explicitly set `autoFocus`.\n if (value == null) {\n if (this.mode === 'side') {\n return 'dialog';\n } else {\n return 'first-tabbable';\n }\n }\n return value;\n }\n set autoFocus(value: AutoFocusTarget | string | BooleanInput) {\n if (value === 'true' || value === 'false' || value == null) {\n value = coerceBooleanProperty(value);\n }\n this._autoFocus = value;\n }\n private _autoFocus: AutoFocusTarget | string | boolean | undefined;\n\n /**\n * Whether the drawer is opened. We overload this because we trigger an event when it\n * starts or end.\n */\n @Input()\n get opened(): boolean {\n return this._opened;\n }\n set opened(value: BooleanInput) {\n this.toggle(coerceBooleanProperty(value));\n }\n private _opened: boolean = false;\n\n /** How the sidenav was opened (keypress, mouse click etc.) */\n private _openedVia: FocusOrigin | null;\n\n /** Emits whenever the drawer has started animating. */\n readonly _animationStarted = new Subject();\n\n /** Emits whenever the drawer is done animating. */\n readonly _animationEnd = new Subject();\n\n /** Event emitted when the drawer open state is changed. */\n @Output() readonly openedChange: EventEmitter<boolean> =\n // Note this has to be async in order to avoid some issues with two-bindings (see #8872).\n new EventEmitter<boolean>(/* isAsync */ true);\n\n /** Event emitted when the drawer has been opened. */\n @Output('opened')\n readonly _openedStream = this.openedChange.pipe(\n filter(o => o),\n map(() => {}),\n );\n\n /** Event emitted when the drawer has started opening. */\n @Output()\n readonly openedStart: Observable<void> = this._animationStarted.pipe(\n filter(() => this.opened),\n mapTo(undefined),\n );\n\n /** Event emitted when the drawer has been closed. */\n @Output('closed')\n readonly _closedStream = this.openedChange.pipe(\n filter(o => !o),\n map(() => {}),\n );\n\n /** Event emitted when the drawer has started closing. */\n @Output()\n readonly closedStart: Observable<void> = this._animationStarted.pipe(\n filter(() => !this.opened),\n mapTo(undefined),\n );\n\n /** Emits when the component is destroyed. */\n private readonly _destroyed = new Subject<void>();\n\n /** Event emitted when the drawer's position changes. */\n // tslint:disable-next-line:no-output-on-prefix\n @Output('positionChanged') readonly onPositionChanged = new EventEmitter<void>();\n\n /** Reference to the inner element that contains all the content. */\n @ViewChild('content') _content: ElementRef<HTMLElement>;\n\n /**\n * An observable that emits when the drawer mode changes. This is used by the drawer container to\n * to know when to when the mode changes so it can adapt the margins on the content.\n */\n readonly _modeChanged = new Subject<void>();\n\n private _injector = inject(Injector);\n private _changeDetectorRef = inject(ChangeDetectorRef);\n\n constructor(...args: unknown[]);\n\n constructor() {\n this.openedChange.pipe(takeUntil(this._destroyed)).subscribe((opened: boolean) => {\n if (opened) {\n if (this._doc) {\n this._elementFocusedBeforeDrawerWasOpened = this._doc.activeElement as HTMLElement;\n }\n this._takeFocus();\n } else if (this._isFocusWithinDrawer()) {\n this._restoreFocus(this._openedVia || 'program');\n }\n });\n\n /**\n * Listen to `keydown` events outside the zone so that change detection is not run every\n * time a key is pressed. Instead we re-enter the zone only if the `ESC` key is pressed\n * and we don't have close disabled.\n */\n this._ngZone.runOutsideAngular(() => {\n const element = this._elementRef.nativeElement;\n (fromEvent(element, 'keydown') as Observable<KeyboardEvent>)\n .pipe(\n filter(event => {\n return event.keyCode === ESCAPE && !this.disableClose && !hasModifierKey(event);\n }),\n takeUntil(this._destroyed),\n )\n .subscribe(event =>\n this._ngZone.run(() => {\n this.close();\n event.stopPropagation();\n event.preventDefault();\n }),\n );\n\n this._eventCleanups = [\n this._renderer.listen(element, 'transitionrun', this._handleTransitionEvent),\n this._renderer.listen(element, 'transitionend', this._handleTransitionEvent),\n this._renderer.listen(element, 'transitioncancel', this._handleTransitionEvent),\n ];\n });\n\n this._animationEnd.subscribe(() => {\n this.openedChange.emit(this._opened);\n });\n }\n\n /**\n * Focuses the provided element. If the element is not focusable, it will add a tabIndex\n * attribute to forcefully focus it. The attribute is removed after focus is moved.\n * @param element The element to focus.\n */\n private _forceFocus(element: HTMLElement, options?: FocusOptions) {\n if (!this._interactivityChecker.isFocusable(element)) {\n element.tabIndex = -1;\n // The tabindex attribute should be removed to avoid navigating to that element again\n this._ngZone.runOutsideAngular(() => {\n const callback = () => {\n cleanupBlur();\n cleanupMousedown();\n element.removeAttribute('tabindex');\n };\n\n const cleanupBlur = this._renderer.listen(element, 'blur', callback);\n const cleanupMousedown = this._renderer.listen(element, 'mousedown', callback);\n });\n }\n element.focus(options);\n }\n\n /**\n * Focuses the first element that matches the given selector within the focus trap.\n * @param selector The CSS selector for the element to set focus to.\n */\n private _focusByCssSelector(selector: string, options?: FocusOptions) {\n let elementToFocus = this._elementRef.nativeElement.querySelector(\n selector,\n ) as HTMLElement | null;\n if (elementToFocus) {\n this._forceFocus(elementToFocus, options);\n }\n }\n\n /**\n * Moves focus into the drawer. Note that this works even if\n * the focus trap is disabled in `side` mode.\n */\n private _takeFocus() {\n if (!this._focusTrap) {\n return;\n }\n\n const element = this._elementRef.nativeElement;\n\n // When autoFocus is not on the sidenav, if the element cannot be focused or does\n // not exist, focus the sidenav itself so the keyboard navigation still works.\n // We need to check that `focus` is a function due to Universal.\n switch (this.autoFocus) {\n case false:\n case 'dialog':\n return;\n case true:\n case 'first-tabbable':\n afterNextRender(\n () => {\n const hasMovedFocus = this._focusTrap!.focusInitialElement();\n if (!hasMovedFocus && typeof element.focus === 'function') {\n element.focus();\n }\n },\n {injector: this._injector},\n );\n break;\n case 'first-heading':\n this._focusByCssSelector('h1, h2, h3, h4, h5, h6, [role=\"heading\"]');\n break;\n default:\n this._focusByCssSelector(this.autoFocus!);\n break;\n }\n }\n\n /**\n * Restores focus to the element that was originally focused when the drawer opened.\n * If no element was focused at that time, the focus will be restored to the drawer.\n */\n private _restoreFocus(focusOrigin: Exclude<FocusOrigin, null>) {\n if (this.autoFocus === 'dialog') {\n return;\n }\n\n if (this._elementFocusedBeforeDrawerWasOpened) {\n this._focusMonitor.focusVia(this._elementFocusedBeforeDrawerWasOpened, focusOrigin);\n } else {\n this._elementRef.nativeElement.blur();\n }\n\n this._elementFocusedBeforeDrawerWasOpened = null;\n }\n\n /** Whether focus is currently within the drawer. */\n private _isFocusWithinDrawer(): boolean {\n const activeEl = this._doc.activeElement;\n return !!activeEl && this._elementRef.nativeElement.contains(activeEl);\n }\n\n ngAfterViewInit() {\n this._isAttached = true;\n\n // Only update the DOM position when the sidenav is positioned at\n // the end since we project the sidenav before the content by default.\n if (this._position === 'end') {\n this._updatePositionInParent('end');\n }\n\n // Needs to happen after the position is updated\n // so the focus trap anchors are in the right place.\n if (this._platform.isBrowser) {\n this._focusTrap = this._focusTrapFactory.create(this._elementRef.nativeElement);\n this._updateFocusTrapState();\n }\n }\n\n ngOnDestroy() {\n this._eventCleanups.forEach(cleanup => cleanup());\n this._focusTrap?.destroy();\n this._anchor?.remove();\n this._anchor = null;\n this._animationStarted.complete();\n this._animationEnd.complete();\n this._modeChanged.complete();\n this._destroyed.next();\n this._destroyed.complete();\n }\n\n /**\n * Open the drawer.\n * @param openedVia Whether the drawer was opened by a key press, mouse click or programmatically.\n * Used for focus management after the sidenav is closed.\n */\n open(openedVia?: FocusOrigin): Promise<MatDrawerToggleResult> {\n return this.toggle(true, openedVia);\n }\n\n /** Close the drawer. */\n close(): Promise<MatDrawerToggleResult> {\n return this.toggle(false);\n }\n\n /** Closes the drawer with context that the backdrop was clicked. */\n _closeViaBackdropClick(): Promise<MatDrawerToggleResult> {\n // If the drawer is closed upon a backdrop click, we always want to restore focus. We\n // don't need to check whether focus is currently in the drawer, as clicking on the\n // backdrop causes blurs the active element.\n return this._setOpen(/* isOpen */ false, /* restoreFocus */ true, 'mouse');\n }\n\n /**\n * Toggle this drawer.\n * @param isOpen Whether the drawer should be open.\n * @param openedVia Whether the drawer was opened by a key press, mouse click or programmatically.\n * Used for focus management after the sidenav is closed.\n */\n toggle(isOpen: boolean = !this.opened, openedVia?: FocusOrigin): Promise<MatDrawerToggleResult> {\n // If the focus is currently inside the drawer content and we are closing the drawer,\n // restore the focus to the initially focused element (when the drawer opened).\n if (isOpen && openedVia) {\n this._openedVia = openedVia;\n }\n\n const result = this._setOpen(\n isOpen,\n /* restoreFocus */ !isOpen && this._isFocusWithinDrawer(),\n this._openedVia || 'program',\n );\n\n if (!isOpen) {\n this._openedVia = null;\n }\n\n return result;\n }\n\n /**\n * Toggles the opened state of the drawer.\n * @param isOpen Whether the drawer should open or close.\n * @param restoreFocus Whether focus should be restored on close.\n * @param focusOrigin Origin to use when restoring focus.\n */\n private _setOpen(\n isOpen: boolean,\n restoreFocus: boolean,\n focusOrigin: Exclude<FocusOrigin, null>,\n ): Promise<MatDrawerToggleResult> {\n if (isOpen === this._opened) {\n return Promise.resolve(isOpen ? 'open' : 'close');\n }\n\n this._opened = isOpen;\n\n if (this._container?._transitionsEnabled) {\n // Note: it's importatnt to set this as early as possible,\n // otherwise the animation can look glitchy in some cases.\n this._setIsAnimating(true);\n } else {\n // Simulate the animation events if animations are disabled.\n setTimeout(() => {\n this._animationStarted.next();\n this._animationEnd.next();\n });\n }\n\n this._elementRef.nativeElement.classList.toggle('mat-drawer-opened', isOpen);\n\n if (!isOpen && restoreFocus) {\n this._restoreFocus(focusOrigin);\n }\n\n // Needed to ensure that the closing sequence fires off correctly.\n this._changeDetectorRef.markForCheck();\n this._updateFocusTrapState();\n\n return new Promise<MatDrawerToggleResult>(resolve => {\n this.openedChange.pipe(take(1)).subscribe(open => resolve(open ? 'open' : 'close'));\n });\n }\n\n /** Toggles whether the drawer is currently animating. */\n private _setIsAnimating(isAnimating: boolean) {\n this._elementRef.nativeElement.classList.toggle('mat-drawer-animating', isAnimating);\n }\n\n _getWidth(): number {\n return this._elementRef.nativeElement.offsetWidth || 0;\n }\n\n /** Updates the enabled state of the focus trap. */\n private _updateFocusTrapState() {\n if (this._focusTrap) {\n // Trap focus only if the backdrop is enabled. Otherwise, allow end user to interact with the\n // sidenav content.\n this._focusTrap.enabled = !!this._container?.hasBackdrop && this.opened;\n }\n }\n\n /**\n * Updates the position of the drawer in the DOM. We need to move the element around ourselves\n * when it's in the `end` position so that it comes after the content and the visual order\n * matches the tab order. We also need to be able to move it back to `start` if the sidenav\n * started off as `end` and was changed to `start`.\n */\n private _updatePositionInParent(newPosition: 'start' | 'end'): void {\n // Don't move the DOM node around on the server, because it can throw off hydration.\n if (!this._platform.isBrowser) {\n return;\n }\n\n const element = this._elementRef.nativeElement;\n const parent = element.parentNode!;\n\n if (newPosition === 'end') {\n if (!this._anchor) {\n this._anchor = this._doc.createComment('mat-drawer-anchor')!;\n parent.insertBefore(this._anchor!, element);\n }\n\n parent.appendChild(element);\n } else if (this._anchor) {\n this._anchor.parentNode!.insertBefore(element, this._anchor);\n }\n }\n\n /** Event handler for animation events. */\n private _handleTransitionEvent = (event: TransitionEvent) => {\n const element = this._elementRef.nativeElement;\n\n if (event.target === element) {\n this._ngZone.run(() => {\n if (event.type === 'transitionrun') {\n this._animationStarted.next(event);\n } else {\n // Don't toggle the animating state on `transitioncancel` since another animation should\n // start afterwards. This prevents the drawer from blinking if an animation is interrupted.\n if (event.type === 'transitionend') {\n this._setIsAnimating(false);\n }\n\n this._animationEnd.next(event);\n }\n });\n }\n };\n}\n\n/**\n * `<mat-drawer-container>` component.\n *\n * This is the parent component to one or two `<mat-drawer>`s that validates the state internally\n * and coordinates the backdrop and content styling.\n */\n@Component({\n selector: 'mat-drawer-container',\n exportAs: 'matDrawerContainer',\n templateUrl: 'drawer-container.html',\n styleUrl: 'drawer.css',\n host: {\n 'class': 'mat-drawer-container',\n '[class.mat-drawer-container-explicit-backdrop]': '_backdropOverride',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n providers: [\n {\n provide: MAT_DRAWER_CONTAINER,\n useExisting: MatDrawerContainer,\n },\n ],\n imports: [MatDrawerContent],\n})\nexport class MatDrawerContainer implements AfterContentInit, DoCheck, OnDestroy {\n private _dir = inject(Directionality, {optional: true});\n private _element = inject<ElementRef<HTMLElement>>(ElementRef);\n private _ngZone = inject(NgZone);\n private _changeDetectorRef = inject(ChangeDetectorRef);\n private _animationMode = inject(ANIMATION_MODULE_TYPE, {optional: true});\n _transitionsEnabled = false;\n\n /** All drawers in the container. Includes drawers from inside nested containers. */\n @ContentChildren(MatDrawer, {\n // We need to use `descendants: true`, because Ivy will no longer match\n // indirect descendants if it's left as false.\n descendants: true,\n })\n _allDrawers: QueryList<MatDrawer>;\n\n /** Drawers that belong to this container. */\n _drawers = new QueryList<MatDrawer>();\n\n @ContentChild(MatDrawerContent) _content: MatDrawerContent;\n @ViewChild(MatDrawerContent) _userContent: MatDrawerContent;\n\n /** The drawer child with the `start` position. */\n get start(): MatDrawer | null {\n return this._start;\n }\n\n /** The drawer child with the `end` position. */\n get end(): MatDrawer | null {\n return this._end;\n }\n\n /**\n * Whether to automatically resize the container whenever\n * the size of any of its drawers changes.\n *\n * **Use at your own risk!** Enabling this option can cause layout thrashing by measuring\n * the drawers on every change detection cycle. Can be configured globally via the\n * `MAT_DRAWER_DEFAULT_AUTOSIZE` token.\n */\n @Input()\n get autosize(): boolean {\n return this._autosize;\n }\n set autosize(value: BooleanInput) {\n this._autosize = coerceBooleanProperty(value);\n }\n private _autosize = inject(MAT_DRAWER_DEFAULT_AUTOSIZE);\n\n /**\n * Whether the drawer container should have a backdrop while one of the sidenavs is open.\n * If explicitly set to `true`, the backdrop will be enabled for drawers in the `side`\n * mode as well.\n */\n @Input()\n get hasBackdrop(): boolean {\n return this._drawerHasBackdrop(this._start) || this._drawerHasBackdrop(this._end);\n }\n set hasBackdrop(value: BooleanInput) {\n this._backdropOverride = value == null ? null : coerceBooleanProperty(value);\n }\n _backdropOverride: boolean | null;\n\n /** Event emitted when the drawer backdrop is clicked. */\n @Output() readonly backdropClick: EventEmitter<void> = new EventEmitter<void>();\n\n /** The drawer at the start/end position, independent of direction. */\n private _start: MatDrawer | null;\n private _end: MatDrawer | null;\n\n /**\n * The drawer at the left/right. When direction changes, these will change as well.\n * They're used as aliases for the above to set the left/right style properly.\n * In LTR, _left == _start and _right == _end.\n * In RTL, _left == _end and _right == _start.\n */\n private _left: MatDrawer | null;\n private _right: MatDrawer | null;\n\n /** Emits when the component is destroyed. */\n private readonly _destroyed = new Subject<void>();\n\n /** Emits on every ngDoCheck. Used for debouncing reflows. */\n private readonly _doCheckSubject = new Subject<void>();\n\n /**\n * Margins to be applied to the content. These are used to push / shrink the drawer content when a\n * drawer is open. We use margin rather than transform even for push mode because transform breaks\n * fixed position elements inside of the transformed element.\n */\n _contentMargins: {left: number | null; right: number | null} = {left: null, right: null};\n\n readonly _contentMarginChanges = new Subject<{left: number | null; right: number | null}>();\n\n /** Reference to the CdkScrollable instance that wraps the scrollable content. */\n get scrollable(): CdkScrollable {\n return this._userContent || this._content;\n }\n\n private _injector = inject(Injector);\n\n constructor(...args: unknown[]);\n\n constructor() {\n const platform = inject(Platform);\n const viewportRuler = inject(ViewportRuler);\n\n // If a `Dir` directive exists up the tree, listen direction changes\n // and update the left/right properties to point to the proper start/end.\n this._dir?.change.pipe(takeUntil(this._destroyed)).subscribe(() => {\n this._validateDrawers();\n this.updateContentMargins();\n });\n\n // Since the minimum width of the sidenav depends on the viewport width,\n // we need to recompute the margins if the viewport changes.\n viewportRuler\n .change()\n .pipe(takeUntil(this._destroyed))\n .subscribe(() => this.updateContentMargins());\n\n if (this._animationMode !== 'NoopAnimations' && platform.isBrowser) {\n this._ngZone.runOutsideAngular(() => {\n // Enable the animations after a delay in order to skip\n // the initial transition if a drawer is open by default.\n setTimeout(() => {\n this._element.nativeElement.classList.add('mat-drawer-transition');\n this._transitionsEnabled = true;\n }, 200);\n });\n }\n }\n\n ngAfterContentInit() {\n this._allDrawers.changes\n .pipe(startWith(this._allDrawers), takeUntil(this._destroyed))\n .subscribe((drawer: QueryList<MatDrawer>) => {\n this._drawers.reset(drawer.filter(item => !item._container || item._container === this));\n this._drawers.notifyOnChanges();\n });\n\n this._drawers.changes.pipe(startWith(null)).subscribe(() => {\n this._validateDrawers();\n\n this._drawers.forEach((drawer: MatDrawer) => {\n this._watchDrawerToggle(drawer);\n this._watchDrawerPosition(drawer);\n this._watchDrawerMode(drawer);\n });\n\n if (\n !this._drawers.length ||\n this._isDrawerOpen(this._start) ||\n this._isDrawerOpen(this._end)\n ) {\n this.updateContentMargins();\n }\n\n this._changeDetectorRef.markForCheck();\n });\n\n // Avoid hitting the NgZone through the debounce timeout.\n this._ngZone.runOutsideAngular(() => {\n this._doCheckSubject\n .pipe(\n debounceTime(10), // Arbitrary debounce time, less than a frame at 60fps\n takeUntil(this._destroyed),\n )\n .subscribe(() => this.updateContentMargins());\n });\n }\n\n ngOnDestroy() {\n this._contentMarginChanges.complete();\n this._doCheckSubject.complete();\n this._drawers.destroy();\n this._destroyed.next();\n this._destroyed.complete();\n }\n\n /** Calls `open` of both start and end drawers */\n open(): void {\n this._drawers.forEach(drawer => drawer.open());\n }\n\n /** Calls `close` of both start and end drawers */\n close(): void {\n this._drawers.forEach(drawer => drawer.close());\n }\n\n /**\n * Recalculates and updates the inline styles for the content. Note that this should be used\n * sparingly, because it causes a reflow.\n */\n updateContentMargins() {\n // 1. For drawers in `over` mode, they don't affect the content.\n // 2. For drawers in `side` mode they should shrink the content. We do this by adding to the\n // left margin (for left drawer) or right margin (for right the drawer).\n // 3. For drawers in `push` mode the should shift the content without resizing it. We do this by\n // adding to the left or right margin and simultaneously subtracting the same amount of\n // margin from the other side.\n let left = 0;\n let right = 0;\n\n if (this._left && this._left.opened) {\n if (this._left.mode == 'side') {\n left += this._left._getWidth();\n } else if (this._left.mode == 'push') {\n const width = this._left._getWidth();\n left += width;\n right -= width;\n }\n }\n\n if (this._right && this._right.opened) {\n if (this._right.mode == 'side') {\n right += this._right._getWidth();\n } else if (this._right.mode == 'push') {\n const width = this._right._getWidth();\n right += width;\n left -= width;\n }\n }\n\n // If either `right` or `left` is zero, don't set a style to the element. This\n // allows users to specify a custom size via CSS class in SSR scenarios where the\n // measured widths will always be zero. Note that we reset to `null` here, rather\n // than below, in order to ensure that the types in the `if` below are consistent.\n left = left || null!;\n right = right || null!;\n\n if (left !== this._contentMargins.left || right !== this._contentMargins.right) {\n this._contentMargins = {left, right};\n\n // Pull back into the NgZone since in some cases we could be outside. We need to be careful\n // to do it only when something changed, otherwise we can end up hitting the zone too often.\n this._ngZone.run(() => this._contentMarginChanges.next(this._contentMargins));\n }\n }\n\n ngDoCheck() {\n // If users opted into autosizing, do a check every change detection cycle.\n if (this._autosize && this._isPushed()) {\n // Run outside the NgZone, otherwise the debouncer will throw us into an infinite loop.\n this._ngZone.runOutsideAngular(() => this._doCheckSubject.next());\n }\n }\n\n /**\n * Subscribes to drawer events in order to set a class on the main container element when the\n * drawer is open and the backdrop is visible. This ensures any overflow on the container element\n * is properly hidden.\n */\n private _watchDrawerToggle(drawer: MatDrawer): void {\n drawer._animationStarted.pipe(takeUntil(this._drawers.changes)).subscribe(() => {\n this.updateContentMargins();\n this._changeDetectorRef.markForCheck();\n });\n\n if (drawer.mode !== 'side') {\n drawer.openedChange\n .pipe(takeUntil(this._drawers.changes))\n .subscribe(() => this._setContainerClass(drawer.opened));\n }\n }\n\n /**\n * Subscribes to drawer onPositionChanged event in order to\n * re-validate drawers when the position changes.\n */\n private _watchDrawerPosition(drawer: MatDrawer): void {\n // NOTE: We need to wait for the microtask queue to be empty before validating,\n // since both drawers may be swapping positions at the same time.\n drawer.onPositionChanged.pipe(takeUntil(this._drawers.changes)).subscribe(() => {\n afterNextRender({read: () => this._validateDrawers()}, {injector: this._injector});\n });\n }\n\n /** Subscribes to changes in drawer mode so we can run change detection. */\n private _watchDrawerMode(drawer: MatDrawer): void {\n drawer._modeChanged\n .pipe(takeUntil(merge(this._drawers.changes, this._destroyed)))\n .subscribe(() => {\n this.updateContentMargins();\n this._changeDetectorRef.markForCheck();\n });\n }\n\n /** Toggles the 'mat-drawer-opened' class on the main 'mat-drawer-container' element. */\n private _setContainerClass(isAdd: boolean): void {\n const classList = this._element.nativeElement.classList;\n const className = 'mat-drawer-container-has-open';\n\n if (isAdd) {\n classList.add(className);\n } else {\n classList.remove(className);\n }\n }\n\n /** Validate the state of the drawer children components. */\n private _validateDrawers() {\n this._start = this._end = null;\n\n // Ensure that we have at most one start and one end drawer.\n this._drawers.forEach(drawer => {\n if (drawer.position == 'end') {\n if (this._end != null && (typeof ngDevMode === 'undefined' || ngDevMode)) {\n throwMatDuplicatedDrawerError('end');\n }\n this._end = drawer;\n } else {\n if (this._start != null && (typeof ngDevMode === 'undefined' || ngDevMode)) {\n throwMatDuplicatedDrawerError('start');\n }\n this._start = drawer;\n }\n });\n\n this._right = this._left = null;\n\n // Detect if we're LTR or RTL.\n if (this._dir && this._dir.value === 'rtl') {\n this._left = this._end;\n this._right = this._start;\n } else {\n this._left = this._start;\n this._right = this._end;\n }\n }\n\n /** Whether the container is being pushed to the side by one of the drawers. */\n private _isPushed() {\n return (\n (this._isDrawerOpen(this._start) && this._start.mode != 'over') ||\n (this._isDrawerOpen(this._end) && this._end.mode != 'over')\n );\n }\n\n _onBackdropClicked() {\n this.backdropClick.emit();\n this._closeModalDrawersViaBackdrop();\n }\n\n _closeModalDrawersViaBackdrop() {\n // Close all open drawers where closing is not disabled and the mode is not `side`.\n [this._start, this._end]\n .filter(drawer => drawer && !drawer.disableClose && this._drawerHasBackdrop(drawer))\n .forEach(drawer => drawer!._closeViaBackdropClick());\n }\n\n _isShowingBackdrop(): boolean {\n return (\n (this._isDrawerOpen(this._start) && this._drawerHasBackdrop(this._start)) ||\n (this._isDrawerOpen(this._end) && this._drawerHasBackdrop(this._end))\n );\n }\n\n private _isDrawerOpen(drawer: MatDrawer | null): drawer is MatDrawer {\n return drawer != null && drawer.opened;\n }\n\n // Whether argument drawer should have a backdrop when it opens\n private _drawerHasBackdrop(drawer: MatDrawer | null) {\n if (this._backdropOverride == null) {\n return !!drawer && drawer.mode !== 'side';\n }\n\n return this._backdropOverride;\n }\n}\n","<div class=\"mat-drawer-inner-container\" cdkScrollable #content>\r\n <ng-content></ng-content>\r\n</div>\r\n","@if (hasBackdrop) {\n <div class=\"mat-drawer-backdrop\" (click)=\"_onBackdropClicked()\"\n [class.mat-drawer-shown]=\"_isShowingBackdrop()\"></div>\n}\n\n<ng-content select=\"mat-drawer\"></ng-content>\n\n<ng-content select=\"mat-drawer-content\">\n</ng-content>\n\n@if (!_content) {\n <mat-drawer-content>\n <ng-content></ng-content>\n </mat-drawer-content>\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {\n ChangeDetectionStrategy,\n Component,\n ContentChild,\n ContentChildren,\n Input,\n ViewEncapsulation,\n QueryList,\n} from '@angular/core';\nimport {MatDrawer, MatDrawerContainer, MatDrawerContent, MAT_DRAWER_CONTAINER} from './drawer';\nimport {\n BooleanInput,\n coerceBooleanProperty,\n coerceNumberProperty,\n NumberInput,\n} from '@angular/cdk/coercion';\nimport {CdkScrollable} from '@angular/cdk/scrolling';\n\n@Component({\n selector: 'mat-sidenav-content',\n template: '<ng-content></ng-content>',\n host: {\n 'class': 'mat-drawer-content mat-sidenav-content',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n providers: [\n {\n provide: CdkScrollable,\n useExisting: MatSidenavContent,\n },\n ],\n})\nexport class MatSidenavContent extends MatDrawerContent {}\n\n@Component({\n selector: 'mat-sidenav',\n exportAs: 'matSidenav',\n templateUrl: 'drawer.html',\n host: {\n 'class': 'mat-drawer mat-sidenav',\n 'tabIndex': '-1',\n // must prevent the browser from aligning text based on value\n '[attr.align]': 'null',\n '[class.mat-drawer-end]': 'position === \"end\"',\n '[class.mat-drawer-over]': 'mode === \"over\"',\n '[class.mat-drawer-push]': 'mode === \"push\"',\n '[class.mat-drawer-side]': 'mode === \"side\"',\n '[class.mat-sidenav-fixed]': 'fixedInViewport',\n '[style.top.px]': 'fixedInViewport ? fixedTopGap : null',\n '[style.bottom.px]': 'fixedInViewport ? fixedBottomGap : null',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n imports: [CdkScrollable],\n providers: [{provide: MatDrawer, useExisting: MatSidenav}],\n})\nexport class MatSidenav extends MatDrawer {\n /** Whether the sidenav is fixed in the viewport. */\n @Input()\n get fixedInViewport(): boolean {\n return this._fixedInViewport;\n }\n set fixedInViewport(value: BooleanInput) {\n this._fixedInViewport = coerceBooleanProperty(value);\n }\n private _fixedInViewport = false;\n\n /**\n * The gap between the top of the sidenav and the top of the viewport when the sidenav is in fixed\n * mode.\n */\n @Input()\n get fixedTopGap(): number {\n return this._fixedTopGap;\n }\n set fixedTopGap(value: NumberInput) {\n this._fixedTopGap = coerceNumberProperty(value);\n }\n private _fixedTopGap = 0;\n\n /**\n * The gap between the bottom of the sidenav and the bottom of the viewport when the sidenav is in\n * fixed mode.\n */\n @Input()\n get fixedBottomGap(): number {\n return this._fixedBottomGap;\n }\n set fixedBottomGap(value: NumberInput) {\n this._fixedBottomGap = coerceNumberProperty(value);\n }\n private _fixedBottomGap = 0;\n}\n\n@Component({\n selector: 'mat-sidenav-container',\n exportAs: 'matSidenavContainer',\n templateUrl: 'sidenav-container.html',\n styleUrl: 'drawer.css',\n host: {\n 'class': 'mat-drawer-container mat-sidenav-container',\n '[class.mat-drawer-container-explicit-backdrop]': '_backdropOverride',\n },\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.None,\n providers: [\n {\n provide: MAT_DRAWER_CONTAINER,\n useExisting: MatSidenavContainer,\n },\n {\n provide: MatDrawerContainer,\n useExisting: MatSidenavContainer,\n },\n ],\n imports: [MatSidenavContent],\n})\nexport class MatSidenavContainer extends MatDrawerContainer {\n @ContentChildren(MatSidenav, {\n // We need to use `descendants: true`, because Ivy will no longer match\n // indirect descendants if it's left as false.\n descendants: true,\n })\n // We need an initializer here to avoid a TS error.\n override _allDrawers: QueryList<MatSidenav> = undefined!;\n\n // We need an initializer here to avoid a TS error.\n @ContentChild(MatSidenavContent) override _content: MatSidenavContent = undefined!;\n}\n","@if (hasBackdrop) {\n <div class=\"mat-drawer-backdrop\" (click)=\"_onBackdropClicked()\"\n [class.mat-drawer-shown]=\"_isShowingBackdrop()\"></div>\n}\n\n<ng-content select=\"mat-sidenav\"></ng-content>\n\n<ng-content select=\"mat-sidenav-content\">\n</ng-content>\n\n@if (!_content) {\n <mat-sidenav-content>\n <ng-content></ng-content>\n </mat-sidenav-content>\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\nimport {CdkScrollableModule} from '@angular/cdk/scrolling';\nimport {NgModule} from '@angular/core';\nimport {MatCommonModule} from '../core';\nimport {MatDrawer, MatDrawerContainer, MatDrawerContent} from './drawer';\nimport {MatSidenav, MatSidenavContainer, MatSidenavContent} from './sidenav';\n\n@NgModule({\n imports: [\n MatCommonModule,\n CdkScrollableModule,\n MatDrawer,\n MatDrawerContainer,\n MatDrawerContent,\n MatSidenav,\n MatSidenavContainer,\n MatSidenavContent,\n ],\n exports: [\n CdkScrollableModule,\n MatCommonModule,\n MatDrawer,\n MatDrawerContainer,\n MatDrawerContent,\n MatSidenav,\n MatSidenavContainer,\n MatSidenavContent,\n ],\n})\nexport class MatSidenavModule {}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\n/**\n * Animations used by the Material drawers.\n * @docs-private\n * @deprecated No longer used, will be removed.\n * @breaking-change 21.0.0\n */\nexport const matDrawerAnimations: {\n readonly transformDrawer: any;\n} = {\n // Represents\n // trigger('transform', [\n // // We remove the `transform` here completely, rather than setting it to zero, because:\n // // 1. Having a transform can cause elements with ripples or an animated\n // // transform to shift around in Chrome with an RTL layout (see #10023).\n // // 2. 3d transforms causes text to appear blurry on IE and Edge.\n // state(\n // 'open, open-instant',\n // style({\n // 'transform': 'none',\n // 'visibility': 'visible',\n // }),\n // ),\n // state(\n // 'void',\n // style({\n // // Avoids the shadow showing up when closed in SSR.\n // 'box-shadow': 'none',\n // 'visibility': 'hidden',\n // }),\n // ),\n // transition('void => open-instant', animate('0ms')),\n // transition(\n // 'void <=> open, open-instant => void',\n // animate('400ms cubic-bezier(0.25, 0.8, 0.25, 1)'),\n // ),\n // ])\n\n /** Animation that slides a drawer in and out. */\n transformDrawer: {\n type: 7,\n name: 'transform',\n definitions: [\n {\n type: 0,\n name: 'open, open-instant',\n styles: {\n type: 6,\n styles: {transform: 'none', visibility: 'visible'},\n offset: null,\n },\n },\n {\n type: 0,\n name: 'void',\n styles: {\n type: 6,\n styles: {'box-shadow': 'none', visibility: 'hidden'},\n offset: null,\n },\n },\n {\n type: 1,\n expr: 'void => open-instant',\n animation: {type: 4, styles: null, timings: '0ms'},\n options: null,\n },\n {\n type: 1,\n expr: 'void <=> open, open-instant => void',\n animation: {\n type: 4,\n styles: null,\n timings: '400ms cubic-bezier(0.25, 0.8, 0.25, 1)',\n },\n options: null,\n },\n ],\n options: {},\n },\n};\n"],"names":[],"mappings":"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