diff --git a/src/material/datepicker/BUILD.bazel b/src/material/datepicker/BUILD.bazel index e16ded85e99a..cb8d9f65b696 100644 --- a/src/material/datepicker/BUILD.bazel +++ b/src/material/datepicker/BUILD.bazel @@ -35,7 +35,6 @@ ng_module( "//src/cdk/portal", "//src/material/button", "//src/material/core", - "//src/material/dialog", "//src/material/form-field", "//src/material/input", "@npm//@angular/animations", @@ -102,7 +101,6 @@ ng_test_library( "//src/cdk/scrolling", "//src/cdk/testing/private", "//src/material/core", - "//src/material/dialog", "//src/material/form-field", "//src/material/input", "//src/material/testing", diff --git a/src/material/datepicker/_datepicker-theme.scss b/src/material/datepicker/_datepicker-theme.scss index 4f5de5b5138d..584447a9c3e5 100644 --- a/src/material/datepicker/_datepicker-theme.scss +++ b/src/material/datepicker/_datepicker-theme.scss @@ -162,7 +162,7 @@ $calendar-weekday-table-font-size: 11px !default; } .mat-datepicker-content-touch { - @include private.private-theme-elevation(0, $config); + @include private.private-theme-elevation(24, $config); } .mat-datepicker-toggle-active { diff --git a/src/material/datepicker/calendar-body.scss b/src/material/datepicker/calendar-body.scss index d4236eaae907..6af6f522b3eb 100644 --- a/src/material/datepicker/calendar-body.scss +++ b/src/material/datepicker/calendar-body.scss @@ -192,12 +192,6 @@ $calendar-range-end-body-cell-size: } } -// Allows for the screen reader close button to be seen in touch UI mode. -.mat-datepicker-dialog .mat-dialog-container { - position: relative; - overflow: visible; -} - @include a11y.high-contrast(active, off) { .mat-datepicker-popup:not(:empty), .mat-calendar-body-selected { diff --git a/src/material/datepicker/datepicker-animations.ts b/src/material/datepicker/datepicker-animations.ts index 1da9d55be6e0..48b4e8667785 100644 --- a/src/material/datepicker/datepicker-animations.ts +++ b/src/material/datepicker/datepicker-animations.ts @@ -11,6 +11,7 @@ import { style, transition, trigger, + keyframes, AnimationTriggerMetadata, } from '@angular/animations'; @@ -24,14 +25,14 @@ export const matDatepickerAnimations: { } = { /** Transforms the height of the datepicker's calendar. */ transformPanel: trigger('transformPanel', [ - state('void', style({ - opacity: 0, - transform: 'scale(1, 0.8)' - })), - transition('void => enter', animate('120ms cubic-bezier(0, 0, 0.2, 1)', style({ - opacity: 1, - transform: 'scale(1, 1)' - }))), + transition('void => enter-dropdown', animate('120ms cubic-bezier(0, 0, 0.2, 1)', keyframes([ + style({opacity: 0, transform: 'scale(1, 0.8)'}), + style({opacity: 1, transform: 'scale(1, 1)'}) + ]))), + transition('void => enter-dialog', animate('150ms cubic-bezier(0, 0, 0.2, 1)', keyframes([ + style({opacity: 0, transform: 'scale(0.7)'}), + style({transform: 'none', opacity: 1}) + ]))), transition('* => void', animate('100ms linear', style({opacity: 0}))) ]), diff --git a/src/material/datepicker/datepicker-base.ts b/src/material/datepicker/datepicker-base.ts index 012101e95b41..bf5def8e8964 100644 --- a/src/material/datepicker/datepicker-base.ts +++ b/src/material/datepicker/datepicker-base.ts @@ -48,7 +48,6 @@ import { mixinColor, ThemePalette, } from '@angular/material/core'; -import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {merge, Subject, Observable, Subscription} from 'rxjs'; import {filter, take} from 'rxjs/operators'; import {MatCalendar, MatCalendarView} from './calendar'; @@ -101,9 +100,9 @@ const _MatDatepickerContentMixinBase: CanColorCtor & typeof MatDatepickerContent mixinColor(MatDatepickerContentBase); /** - * Component used as the content for the datepicker dialog and popup. We use this instead of using + * Component used as the content for the datepicker overlay. We use this instead of using * MatCalendar directly as the content so we can control the initial focus. This also gives us a - * place to put additional features of the popup that are not part of the calendar itself in the + * place to put additional features of the overlay that are not part of the calendar itself in the * future. (e.g. confirmation buttons). * @docs-private */ @@ -147,7 +146,7 @@ export class MatDatepickerContent> _isAbove: boolean; /** Current state of the animation. */ - _animationState: 'enter' | 'void' = 'enter'; + _animationState: 'enter-dropdown' | 'enter-dialog' | 'void'; /** Emits when an animation has finished. */ readonly _animationDone = new Subject(); @@ -178,6 +177,7 @@ export class MatDatepickerContent> // otherwise update the global model directly. Note that we want to assign this as soon as // possible, but `_actionsPortal` isn't available in the constructor so we do it in `ngOnInit`. this._model = this._actionsPortal ? this._globalModel.clone() : this._globalModel; + this._animationState = this.datepicker.touchUi ? 'enter-dialog' : 'enter-dropdown'; } ngAfterViewInit() { @@ -211,7 +211,7 @@ export class MatDatepickerContent> this._model.add(value); } - // Delegate closing the popup to the actions. + // Delegate closing the overlay to the actions. if ((!this._model || this._model.isComplete()) && !this._actionsPortal) { this.datepicker.close(); } @@ -310,7 +310,7 @@ export abstract class MatDatepickerBase, S, /** * Whether the calendar UI is in touch mode. In touch mode the calendar opens in a dialog rather - * than a popup and elements have more padding to allow for bigger touch targets. + * than a dropdown and elements have more padding to allow for bigger touch targets. */ @Input() get touchUi(): boolean { return this._touchUi; } @@ -418,14 +418,11 @@ export abstract class MatDatepickerBase, S, return this.datepickerInput && this.datepickerInput.dateFilter; } - /** A reference to the overlay when the calendar is opened as a popup. */ - private _popupRef: OverlayRef | null; + /** A reference to the overlay into which we've rendered the calendar. */ + private _overlayRef: OverlayRef | null; - /** A reference to the dialog when the calendar is opened as a dialog. */ - private _dialogRef: MatDialogRef> | null; - - /** Reference to the component instantiated in popup mode. */ - private _popupComponentRef: ComponentRef> | null; + /** Reference to the component instance rendered in the overlay. */ + private _componentRef: ComponentRef> | null; /** The element that was focused before the datepicker was opened. */ private _focusedElementBeforeOpen: HTMLElement | null = null; @@ -442,15 +439,20 @@ export abstract class MatDatepickerBase, S, /** Emits when the datepicker's state changes. */ readonly stateChanges = new Subject(); - constructor(private _dialog: MatDialog, - private _overlay: Overlay, - private _ngZone: NgZone, - private _viewContainerRef: ViewContainerRef, - @Inject(MAT_DATEPICKER_SCROLL_STRATEGY) scrollStrategy: any, - @Optional() private _dateAdapter: DateAdapter, - @Optional() private _dir: Directionality, - @Optional() @Inject(DOCUMENT) private _document: any, - private _model: MatDateSelectionModel) { + constructor( + /** + * @deprecated `_dialog` parameter is no longer being used and it will be removed. + * @breaking-change 13.0.0 + */ + @Inject(ElementRef) _dialog: any, + private _overlay: Overlay, + private _ngZone: NgZone, + private _viewContainerRef: ViewContainerRef, + @Inject(MAT_DATEPICKER_SCROLL_STRATEGY) scrollStrategy: any, + @Optional() private _dateAdapter: DateAdapter, + @Optional() private _dir: Directionality, + @Optional() @Inject(DOCUMENT) private _document: any, + private _model: MatDateSelectionModel) { if (!this._dateAdapter && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw createMissingDateImplError('DateAdapter'); } @@ -461,12 +463,15 @@ export abstract class MatDatepickerBase, S, ngOnChanges(changes: SimpleChanges) { const positionChange = changes['xPosition'] || changes['yPosition']; - if (positionChange && !positionChange.firstChange && this._popupRef) { - this._setConnectedPositions( - this._popupRef.getConfig().positionStrategy as FlexibleConnectedPositionStrategy); + if (positionChange && !positionChange.firstChange && this._overlayRef) { + const positionStrategy = this._overlayRef.getConfig().positionStrategy; - if (this.opened) { - this._popupRef.updatePosition(); + if (positionStrategy instanceof FlexibleConnectedPositionStrategy) { + this._setConnectedPositions(positionStrategy); + + if (this.opened) { + this._overlayRef.updatePosition(); + } } } @@ -474,7 +479,7 @@ export abstract class MatDatepickerBase, S, } ngOnDestroy() { - this._destroyPopup(); + this._destroyOverlay(); this.close(); this._inputStateChanges.unsubscribe(); this.stateChanges.complete(); @@ -542,6 +547,7 @@ export abstract class MatDatepickerBase, S, if (this._opened || this.disabled) { return; } + if (!this.datepickerInput && (typeof ngDevMode === 'undefined' || ngDevMode)) { throw Error('Attempted to open an MatDatepicker with no associated input.'); } @@ -551,7 +557,7 @@ export abstract class MatDatepickerBase, S, const activeElement: HTMLElement|null = this._document?.activeElement; this._focusedElementBeforeOpen = activeElement?.shadowRoot?.activeElement as HTMLElement || activeElement; - this.touchUi ? this._openAsDialog() : this._openAsPopup(); + this._openOverlay(); this._opened = true; this.openedStream.emit(); } @@ -561,14 +567,11 @@ export abstract class MatDatepickerBase, S, if (!this._opened) { return; } - if (this._popupComponentRef && this._popupRef) { - const instance = this._popupComponentRef.instance; + + if (this._componentRef) { + const instance = this._componentRef.instance; instance._startExitAnimation(); - instance._animationDone.pipe(take(1)).subscribe(() => this._destroyPopup()); - } - if (this._dialogRef) { - this._dialogRef.close(); - this._dialogRef = null; + instance._animationDone.pipe(take(1)).subscribe(() => this._destroyOverlay()); } const completeClose = () => { @@ -595,71 +598,9 @@ export abstract class MatDatepickerBase, S, } } - /** Applies the current pending selection on the popup to the model. */ + /** Applies the current pending selection on the overlay to the model. */ _applyPendingSelection() { - const instance = this._popupComponentRef?.instance || this._dialogRef?.componentInstance; - instance?._applyPendingSelection(); - } - - /** Open the calendar as a dialog. */ - private _openAsDialog(): void { - // Usually this would be handled by `open` which ensures that we can only have one overlay - // open at a time, however since we reset the variables in async handlers some overlays - // may slip through if the user opens and closes multiple times in quick succession (e.g. - // by holding down the enter key). - if (this._dialogRef) { - this._dialogRef.close(); - } - - this._dialogRef = this._dialog.open>(MatDatepickerContent, { - direction: this._dir ? this._dir.value : 'ltr', - viewContainerRef: this._viewContainerRef, - panelClass: 'mat-datepicker-dialog', - - // These values are all the same as the defaults, but we set them explicitly so that the - // datepicker dialog behaves consistently even if the user changed the defaults. - hasBackdrop: true, - disableClose: false, - backdropClass: ['cdk-overlay-dark-backdrop', this._backdropHarnessClass], - width: '', - height: '', - minWidth: '', - minHeight: '', - maxWidth: '80vw', - maxHeight: '', - position: {}, - - // Disable the dialog's automatic focus capturing, because it'll go to the close button - // automatically. The calendar will move focus on its own once it renders. - autoFocus: false, - - // `MatDialog` has focus restoration built in, however we want to disable it since the - // datepicker also has focus restoration for dropdown mode. We want to do this, in order - // to ensure that the timing is consistent between dropdown and dialog modes since `MatDialog` - // restores focus when the animation is finished, but the datepicker does it immediately. - // Furthermore, this avoids any conflicts where the datepicker consumer might move focus - // inside the `closed` event which is dispatched immediately. - restoreFocus: false - }); - - this._dialogRef.afterClosed().subscribe(() => this.close()); - this._forwardContentValues(this._dialogRef.componentInstance); - } - - /** Open the calendar as a popup. */ - private _openAsPopup(): void { - const portal = new ComponentPortal>(MatDatepickerContent, - this._viewContainerRef); - - this._destroyPopup(); - this._createPopup(); - this._popupComponentRef = this._popupRef!.attach(portal); - this._forwardContentValues(this._popupComponentRef.instance); - - // Update the position once the calendar has rendered. - this._ngZone.onStable.pipe(take(1)).subscribe(() => { - this._popupRef!.updatePosition(); - }); + this._componentRef?.instance?._applyPendingSelection(); } /** Forwards relevant values from the datepicker to the datepicker content inside the overlay. */ @@ -669,52 +610,71 @@ export abstract class MatDatepickerBase, S, instance._actionsPortal = this._actionsPortal; } - /** Create the popup. */ - private _createPopup(): void { - const positionStrategy = this._overlay.position() - .flexibleConnectedTo(this.datepickerInput.getConnectedOverlayOrigin()) - .withTransformOriginOn('.mat-datepicker-content') - .withFlexibleDimensions(false) - .withViewportMargin(8) - .withLockedPosition(); + /** Opens the overlay with the calendar. */ + private _openOverlay(): void { + this._destroyOverlay(); - const overlayConfig = new OverlayConfig({ - positionStrategy: this._setConnectedPositions(positionStrategy), + const isDialog = this.touchUi; + const portal = new ComponentPortal>(MatDatepickerContent, + this._viewContainerRef); + const overlayRef = this._overlayRef = this._overlay.create(new OverlayConfig({ + positionStrategy: isDialog ? this._getDialogStrategy() : this._getDropdownStrategy(), hasBackdrop: true, - backdropClass: ['mat-overlay-transparent-backdrop', this._backdropHarnessClass], + backdropClass: [ + isDialog ? 'cdk-overlay-dark-backdrop' : 'mat-overlay-transparent-backdrop', + this._backdropHarnessClass + ], direction: this._dir, - scrollStrategy: this._scrollStrategy(), - panelClass: 'mat-datepicker-popup', - }); + scrollStrategy: isDialog ? this._overlay.scrollStrategies.block() : this._scrollStrategy(), + panelClass: `mat-datepicker-${isDialog ? 'dialog' : 'popup'}`, + })); + overlayRef.overlayElement.setAttribute('role', 'dialog'); - this._popupRef = this._overlay.create(overlayConfig); - this._popupRef.overlayElement.setAttribute('role', 'dialog'); + if (isDialog) { + overlayRef.overlayElement.setAttribute('aria-modal', 'true'); + } - merge( - this._popupRef.backdropClick(), - this._popupRef.detachments(), - this._popupRef.keydownEvents().pipe(filter(event => { - // Closing on alt + up is only valid when there's an input associated with the datepicker. - return (event.keyCode === ESCAPE && !hasModifierKey(event)) || (this.datepickerInput && - hasModifierKey(event, 'altKey') && event.keyCode === UP_ARROW); - })) - ).subscribe(event => { + this._getCloseStream(overlayRef).subscribe(event => { if (event) { event.preventDefault(); } - this.close(); }); + + this._componentRef = overlayRef.attach(portal); + this._forwardContentValues(this._componentRef.instance); + + // Update the position once the calendar has rendered. Only relevant in dropdown mode. + if (!isDialog) { + this._ngZone.onStable.pipe(take(1)).subscribe(() => overlayRef.updatePosition()); + } } - /** Destroys the current popup overlay. */ - private _destroyPopup() { - if (this._popupRef) { - this._popupRef.dispose(); - this._popupRef = this._popupComponentRef = null; + /** Destroys the current overlay. */ + private _destroyOverlay() { + if (this._overlayRef) { + this._overlayRef.dispose(); + this._overlayRef = this._componentRef = null; } } + /** Gets a position strategy that will open the calendar as a dropdown. */ + private _getDialogStrategy() { + return this._overlay.position().global().centerHorizontally().centerVertically(); + } + + /** Gets a position strategy that will open the calendar as a dropdown. */ + private _getDropdownStrategy() { + const strategy = this._overlay.position() + .flexibleConnectedTo(this.datepickerInput.getConnectedOverlayOrigin()) + .withTransformOriginOn('.mat-datepicker-content') + .withFlexibleDimensions(false) + .withViewportMargin(8) + .withLockedPosition(); + + return this._setConnectedPositions(strategy); + } + /** Sets the positions of the datepicker in dropdown mode based on the current configuration. */ private _setConnectedPositions(strategy: FlexibleConnectedPositionStrategy) { const primaryX = this.xPosition === 'end' ? 'end' : 'start'; @@ -750,6 +710,19 @@ export abstract class MatDatepickerBase, S, ]); } + /** Gets an observable that will emit when the overlay is supposed to be closed. */ + private _getCloseStream(overlayRef: OverlayRef) { + return merge( + overlayRef.backdropClick(), + overlayRef.detachments(), + overlayRef.keydownEvents().pipe(filter(event => { + // Closing on alt + up is only valid when there's an input associated with the datepicker. + return (event.keyCode === ESCAPE && !hasModifierKey(event)) || (this.datepickerInput && + hasModifierKey(event, 'altKey') && event.keyCode === UP_ARROW); + })) + ); + } + static ngAcceptInputType_disabled: BooleanInput; static ngAcceptInputType_opened: BooleanInput; static ngAcceptInputType_touchUi: BooleanInput; diff --git a/src/material/datepicker/datepicker-content.scss b/src/material/datepicker/datepicker-content.scss index bfb51aaccd59..4ffd85714503 100644 --- a/src/material/datepicker/datepicker-content.scss +++ b/src/material/datepicker/datepicker-content.scss @@ -57,13 +57,13 @@ $touch-max-height: 788px; .mat-datepicker-content-touch { display: block; - // Make sure the dialog scrolls rather than being cropped on ludicrously small screens max-height: 80vh; - overflow: auto; - // Offsets the padding of the dialog. - // TODO(mmalerba): Remove when we switch away from using dialog. - margin: -24px; + // Allows for the screen reader close button to be seen in touch UI mode. + position: relative; + + // Prevents the content from jumping around on Windows while the animation is running. + overflow: visible; .mat-datepicker-content-container { min-height: $touch-min-height; diff --git a/src/material/datepicker/datepicker-module.ts b/src/material/datepicker/datepicker-module.ts index 9a863ab2e12d..5ce8072cbbda 100644 --- a/src/material/datepicker/datepicker-module.ts +++ b/src/material/datepicker/datepicker-module.ts @@ -12,7 +12,6 @@ import {PortalModule} from '@angular/cdk/portal'; import {CommonModule} from '@angular/common'; import {NgModule} from '@angular/core'; import {MatButtonModule} from '@angular/material/button'; -import {MatDialogModule} from '@angular/material/dialog'; import {CdkScrollableModule} from '@angular/cdk/scrolling'; import {MatCommonModule} from '@angular/material/core'; import {MatCalendar, MatCalendarHeader} from './calendar'; @@ -38,7 +37,6 @@ import {MatDatepickerActions, MatDatepickerApply, MatDatepickerCancel} from './d imports: [ CommonModule, MatButtonModule, - MatDialogModule, OverlayModule, A11yModule, PortalModule, diff --git a/src/material/datepicker/datepicker.spec.ts b/src/material/datepicker/datepicker.spec.ts index 6714e3d58346..2bc7dd4c2edc 100644 --- a/src/material/datepicker/datepicker.spec.ts +++ b/src/material/datepicker/datepicker.spec.ts @@ -30,7 +30,6 @@ import {By} from '@angular/platform-browser'; import {_supportsShadowDom} from '@angular/cdk/platform'; import {BrowserDynamicTestingModule} from '@angular/platform-browser-dynamic/testing'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; -import {MAT_DIALOG_DEFAULT_OPTIONS, MatDialogConfig} from '@angular/material/dialog'; import {Subject} from 'rxjs'; import {MatInputModule} from '../input/index'; import {MatDatepicker} from './datepicker'; @@ -122,13 +121,12 @@ describe('MatDatepicker', () => { testComponent.touch = true; fixture.detectChanges(); - expect(document.querySelector('.mat-datepicker-dialog mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); testComponent.datepicker.open(); fixture.detectChanges(); - expect(document.querySelector('.mat-datepicker-dialog mat-dialog-container')) - .not.toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).not.toBeNull(); }); it('should not be able to open more than one dialog', fakeAsync(() => { @@ -172,13 +170,13 @@ describe('MatDatepicker', () => { fixture.detectChanges(); expect(document.querySelector('.cdk-overlay-pane')).toBeNull(); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); testComponent.datepicker.open(); fixture.detectChanges(); expect(document.querySelector('.cdk-overlay-pane')).toBeNull(); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); }); it('disabled datepicker input should open the calendar if datepicker is enabled', () => { @@ -258,13 +256,13 @@ describe('MatDatepicker', () => { testComponent.datepicker.open(); fixture.detectChanges(); - expect(document.querySelector('mat-dialog-container')).not.toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).not.toBeNull(); testComponent.datepicker.close(); fixture.detectChanges(); flush(); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); })); it('setting selected via click should update input and close calendar', fakeAsync(() => { @@ -275,7 +273,7 @@ describe('MatDatepicker', () => { fixture.detectChanges(); flush(); - expect(document.querySelector('mat-dialog-container')).not.toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).not.toBeNull(); expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 1)); let cells = document.querySelectorAll('.mat-calendar-body-cell'); @@ -283,7 +281,7 @@ describe('MatDatepicker', () => { fixture.detectChanges(); flush(); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2)); })); @@ -296,7 +294,7 @@ describe('MatDatepicker', () => { fixture.detectChanges(); flush(); - expect(document.querySelector('mat-dialog-container')).not.toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).not.toBeNull(); expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 1)); let calendarBodyEl = document.querySelector('.mat-calendar-body') as HTMLElement; @@ -308,7 +306,7 @@ describe('MatDatepicker', () => { fixture.detectChanges(); flush(); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2)); })); @@ -332,7 +330,7 @@ describe('MatDatepicker', () => { } expect(spy).toHaveBeenCalledTimes(1); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 2)); selectedSubscription.unsubscribe(); })); @@ -354,7 +352,7 @@ describe('MatDatepicker', () => { fixture.whenStable().then(() => { expect(spy).not.toHaveBeenCalled(); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); expect(testComponent.datepickerInput.value).toEqual(new Date(2020, JAN, 1)); selectedSubscription.unsubscribe(); }); @@ -1067,13 +1065,13 @@ describe('MatDatepicker', () => { }); it('should open calendar when toggle clicked', () => { - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); let toggle = fixture.debugElement.query(By.css('button'))!; dispatchMouseEvent(toggle.nativeElement, 'click'); fixture.detectChanges(); - expect(document.querySelector('mat-dialog-container')).not.toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).not.toBeNull(); }); it('should not open calendar when toggle clicked if datepicker is disabled', () => { @@ -1082,12 +1080,12 @@ describe('MatDatepicker', () => { const toggle = fixture.debugElement.query(By.css('button'))!.nativeElement; expect(toggle.hasAttribute('disabled')).toBe(true); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); dispatchMouseEvent(toggle, 'click'); fixture.detectChanges(); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); }); it('should not open calendar when toggle clicked if input is disabled', () => { @@ -1098,12 +1096,12 @@ describe('MatDatepicker', () => { const toggle = fixture.debugElement.query(By.css('button'))!.nativeElement; expect(toggle.hasAttribute('disabled')).toBe(true); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); dispatchMouseEvent(toggle, 'click'); fixture.detectChanges(); - expect(document.querySelector('mat-dialog-container')).toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).toBeNull(); }); it('should set the `button` type on the trigger to prevent form submissions', () => { @@ -1550,7 +1548,7 @@ describe('MatDatepicker', () => { testComponent.datepicker.open(); fixture.detectChanges(); - expect(document.querySelector('mat-dialog-container')).not.toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).not.toBeNull(); let cells = document.querySelectorAll('.mat-calendar-body-cell'); expect(cells[0].classList).toContain('mat-calendar-body-disabled'); @@ -1661,7 +1659,7 @@ describe('MatDatepicker', () => { testComponent.datepicker.open(); fixture.detectChanges(); - expect(document.querySelector('mat-dialog-container')).not.toBeNull(); + expect(document.querySelector('.mat-datepicker-dialog')).not.toBeNull(); const cells = document.querySelectorAll('.mat-calendar-body-cell'); dispatchMouseEvent(cells[0], 'click'); @@ -2099,24 +2097,6 @@ describe('MatDatepicker', () => { })); }); - it('should not pick up values from the global dialog config', () => { - const fixture = createComponent(StandardDatepicker, [MatNativeDateModule], [{ - provide: MAT_DIALOG_DEFAULT_OPTIONS, - useValue: { - minWidth: '1337px', - hasBackdrop: false - } as MatDialogConfig - }]); - fixture.componentInstance.touch = true; - fixture.detectChanges(); - fixture.componentInstance.datepicker.open(); - fixture.detectChanges(); - - const overlay = document.querySelector('.cdk-overlay-pane') as HTMLElement; - expect(document.querySelector('.cdk-overlay-backdrop')).toBeTruthy(); - expect(overlay.style.minWidth).toBeFalsy(); - }); - it('should not trigger validators if new date object for same date is set for `min`', () => { const fixture = createComponent(DatepickerInputWithCustomValidator, [MatNativeDateModule], undefined, undefined, [CustomValidator]); @@ -2225,9 +2205,8 @@ describe('MatDatepicker', () => { testComponent.datepicker.open(); fixture.detectChanges(); - const datepickerContent = testComponent.datepicker['_dialogRef']!!.componentInstance; const actualClasses = - datepickerContent._elementRef.nativeElement.querySelector('.mat-calendar').classList; + document.querySelector('.mat-datepicker-content .mat-calendar')!.classList; expect(actualClasses.contains('foo')).toBe(true); expect(actualClasses.contains('bar')).toBe(true); }); diff --git a/tools/public_api_guard/material/datepicker.d.ts b/tools/public_api_guard/material/datepicker.d.ts index 852bd5865761..1c1c6ee59dcb 100644 --- a/tools/public_api_guard/material/datepicker.d.ts +++ b/tools/public_api_guard/material/datepicker.d.ts @@ -215,7 +215,7 @@ export declare class MatDatepickerCancel { export declare class MatDatepickerContent> extends _MatDatepickerContentMixinBase implements OnInit, AfterViewInit, OnDestroy, CanColor { _actionsPortal: TemplatePortal | null; readonly _animationDone: Subject; - _animationState: 'enter' | 'void'; + _animationState: 'enter-dropdown' | 'enter-dialog' | 'void'; _calendar: MatCalendar; _closeButtonFocused: boolean; _closeButtonText: string; @@ -292,7 +292,7 @@ export declare class MatDatepickerIntl { export declare class MatDatepickerModule { static ɵfac: i0.ɵɵFactoryDeclaration; static ɵinj: i0.ɵɵInjectorDeclaration; - static ɵmod: i0.ɵɵNgModuleDeclaration; + static ɵmod: i0.ɵɵNgModuleDeclaration; } export declare class MatDatepickerToggle implements AfterContentInit, OnChanges, OnDestroy {