diff --git a/components/date-picker/date-picker.component.spec.ts b/components/date-picker/date-picker.component.spec.ts index 2f356ef7bb8..8b8380e97ee 100644 --- a/components/date-picker/date-picker.component.spec.ts +++ b/components/date-picker/date-picker.component.spec.ts @@ -13,7 +13,7 @@ import isSameDay from 'date-fns/isSameDay'; import { enUS } from 'date-fns/locale'; -import { dispatchKeyboardEvent, dispatchMouseEvent, typeInElement } from 'ng-zorro-antd/core/testing'; +import { dispatchFakeEvent, dispatchKeyboardEvent, dispatchMouseEvent, typeInElement } from 'ng-zorro-antd/core/testing'; import { NgStyleInterface } from 'ng-zorro-antd/core/types'; import { NzI18nModule, NzI18nService, NZ_DATE_LOCALE } from 'ng-zorro-antd/i18n'; import en_US from '../i18n/languages/en_US'; @@ -70,7 +70,7 @@ describe('NzDatePickerComponent', () => { openPickerByClickTrigger(); expect(getPickerContainer()).not.toBeNull(); - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -96,7 +96,7 @@ describe('NzDatePickerComponent', () => { fixture.detectChanges(); openPickerByClickTrigger(); - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -151,16 +151,23 @@ describe('NzDatePickerComponent', () => { })); it('should open by click and close by tab', fakeAsync(() => { + const nzOnChange = spyOn(fixtureInstance, 'nzOnChange'); fixtureInstance.useSuite = 5; fixture.detectChanges(); openPickerByClickTrigger(); expect(getPickerContainer()).not.toBeNull(); - getSecondPickerInput(fixture.debugElement).focus(); + typeInElement('2021-04-12', getPickerInput(fixture.debugElement)); fixture.detectChanges(); - flush(); + + triggerInputBlur(); + fixture.detectChanges(); + tick(500); fixture.detectChanges(); + + const result = (nzOnChange.calls.allArgs()[0] as Date[])[0]; + expect(isSameDay(new Date('2021-04-12'), result)).toBeTruthy(); expect(getPickerContainer()).toBeNull(); })); @@ -379,7 +386,7 @@ describe('NzDatePickerComponent', () => { openPickerByClickTrigger(); expect(nzOnOpenChange).toHaveBeenCalledWith(true); - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); flush(); expect(nzOnOpenChange).toHaveBeenCalledWith(false); @@ -481,10 +488,6 @@ describe('NzDatePickerComponent', () => { openPickerByClickTrigger(); expect(overlayContainerElement.children[0].classList).toContain('cdk-overlay-backdrop'); })); - - function getSecondPickerInput(fixtureDebugElement: DebugElement): HTMLInputElement { - return fixtureDebugElement.queryAll(By.css(`.${PREFIX_CLASS}-input input`))[1].nativeElement as HTMLInputElement; - } }); describe('panel switch and move forward/afterward', () => { @@ -826,7 +829,7 @@ describe('NzDatePickerComponent', () => { fixture.detectChanges(); expect(getPickerContainer()).not.toBeNull(); - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -980,7 +983,7 @@ describe('NzDatePickerComponent', () => { flush(); fixture.detectChanges(); - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -1067,6 +1070,10 @@ describe('NzDatePickerComponent', () => { tick(500); fixture.detectChanges(); } + + function triggerInputBlur(): void { + dispatchFakeEvent(getPickerInput(fixture.debugElement), 'blur'); + } }); describe('date-fns testing', () => { @@ -1162,7 +1169,7 @@ describe('date-fns testing', () => { - + diff --git a/components/date-picker/date-picker.component.ts b/components/date-picker/date-picker.component.ts index 6ae1b1da253..c831dd62918 100644 --- a/components/date-picker/date-picker.component.ts +++ b/components/date-picker/date-picker.component.ts @@ -78,6 +78,7 @@ export type NzDatePickerSizeType = 'large' | 'default' | 'small'; [nzId]="nzId" > | string; dir: Direction = 'ltr'; @@ -383,16 +383,12 @@ export class NzDatePickerComponent implements OnInit, OnChanges, OnDestroy, Cont this.datePickerService.initialValue = newValue; } - onFocusChange(value: FocusEvent): void { - // When the relatedTarget is part of the elementRef, it means that it's a range-picker and you are navigating to - // the other input in that range picker. In that case we don't want to close the picker. - this.focused = (value.type === 'blur' && this.elementRef.nativeElement.contains(value.relatedTarget)) || value.type === 'focus'; + onFocusChange(value: boolean): void { // TODO: avoid autoFocus cause change after checked error - if (this.focused) { + if (value) { this.renderer.addClass(this.elementRef.nativeElement, 'ant-picker-focused'); } else { this.renderer.removeClass(this.elementRef.nativeElement, 'ant-picker-focused'); - this.close(); } } diff --git a/components/date-picker/month-picker.component.spec.ts b/components/date-picker/month-picker.component.spec.ts index 71cf80805bd..6a531acb72f 100644 --- a/components/date-picker/month-picker.component.spec.ts +++ b/components/date-picker/month-picker.component.spec.ts @@ -8,7 +8,7 @@ import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; import isBefore from 'date-fns/isBefore'; -import { dispatchMouseEvent } from 'ng-zorro-antd/core/testing'; +import { dispatchFakeEvent, dispatchMouseEvent } from 'ng-zorro-antd/core/testing'; import { NgStyleInterface } from 'ng-zorro-antd/core/types'; import { getPickerAbstract, getPickerInput } from 'ng-zorro-antd/date-picker/testing/util'; import { PREFIX_CLASS } from 'ng-zorro-antd/date-picker/util'; @@ -56,7 +56,7 @@ describe('NzMonthPickerComponent', () => { openPickerByClickTrigger(); expect(getPickerContainer()).not.toBeNull(); - dispatchMouseEvent(document.body, 'click'); + dispatchFakeEvent(getPickerInput(fixture.debugElement), 'blur'); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -205,7 +205,7 @@ describe('NzMonthPickerComponent', () => { openPickerByClickTrigger(); expect(nzOnOpenChange).toHaveBeenCalledWith(true); - dispatchMouseEvent(document.body, 'click'); + dispatchFakeEvent(getPickerInput(fixture.debugElement), 'blur'); fixture.detectChanges(); flush(); expect(nzOnOpenChange).toHaveBeenCalledWith(false); diff --git a/components/date-picker/picker.component.ts b/components/date-picker/picker.component.ts index f039c0032f5..5ced4f74c59 100644 --- a/components/date-picker/picker.component.ts +++ b/components/date-picker/picker.component.ts @@ -155,7 +155,6 @@ import { PREFIX_CLASS } from './util'; (positionChange)="onPositionChange($event)" (detach)="onOverlayDetach()" (overlayKeydown)="onOverlayKeydown($event)" - (overlayOutsideClick)="onClickOutside($event)" > @@ -182,7 +181,7 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe @Input() nzId: string | null = null; @Input() hasBackdrop = false; - @Output() readonly focusChange = new EventEmitter(); + @Output() readonly focusChange = new EventEmitter(); @Output() readonly valueChange = new EventEmitter(); @Output() readonly openChange = new EventEmitter(); // Emitted when overlay's open state change @@ -312,7 +311,6 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe this.activeBarStyle = { ...baseStyle, left: `${this.datePickerService.arrowLeft}px` }; } - this.panel.cdr.markForCheck(); this.cdr.markForCheck(); } @@ -336,7 +334,7 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe onFocus(event: FocusEvent, partType?: RangePartType): void { event.preventDefault(); - this.focusChange.emit(event); + this.focusChange.emit(true); if (partType) { this.datePickerService.inputPartChange$.next(partType); } @@ -344,7 +342,12 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe onBlur(event: FocusEvent): void { event.preventDefault(); - this.focusChange.emit(event); + this.focusChange.emit(false); + + const isFocus = this.elementRef.nativeElement.contains(event.relatedTarget); + if (!isFocus) { + this.checkAndClose(); + } } // Show overlay content @@ -356,7 +359,6 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe this.updateInputWidthAndArrowLeft(); this.overlayOpen = true; this.focus(); - this.panel.init(); this.openChange.emit(true); this.cdr.markForCheck(); } @@ -376,16 +378,8 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe return !this.disabled && !this.isEmptyValue(this.datePickerService.value) && !!this.allowClear; } - onClickInputBox(event: MouseEvent): void { - event.stopPropagation(); - this.focus(); - if (!this.isOpenHandledByUser()) { - this.showOverlay(); - } - } - - onClickOutside(event: MouseEvent): void { - if (this.elementRef.nativeElement.contains(event.target)) { + checkAndClose(): void { + if (!this.realOpenState) { return; } @@ -404,6 +398,14 @@ export class NzPickerComponent implements OnInit, AfterViewInit, OnChanges, OnDe } } + onClickInputBox(event: MouseEvent): void { + event.stopPropagation(); + this.focus(); + if (!this.isOpenHandledByUser()) { + this.showOverlay(); + } + } + onOverlayDetach(): void { this.hideOverlay(); } diff --git a/components/date-picker/range-picker.component.spec.ts b/components/date-picker/range-picker.component.spec.ts index 2cdf6c503f5..224de0f7479 100644 --- a/components/date-picker/range-picker.component.spec.ts +++ b/components/date-picker/range-picker.component.spec.ts @@ -60,7 +60,7 @@ describe('NzRangePickerComponent', () => { openPickerByClickTrigger(); expect(getPickerContainer()).not.toBeNull(); - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -81,6 +81,7 @@ describe('NzRangePickerComponent', () => { fixture.detectChanges(); expect(getPickerContainer()).not.toBeNull(); + triggerInputBlur(); getRegularPickerInput(fixture.debugElement).focus(); fixture.detectChanges(); tick(500); @@ -92,7 +93,7 @@ describe('NzRangePickerComponent', () => { fixture.detectChanges(); openPickerByClickTrigger(); - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -237,7 +238,7 @@ describe('NzRangePickerComponent', () => { openPickerByClickTrigger(); expect(nzOnOpenChange).toHaveBeenCalledWith(true); - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -402,7 +403,7 @@ describe('NzRangePickerComponent', () => { dispatchMouseEvent(getSuperNextBtn('left'), 'click'); fixture.detectChanges(); - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -476,7 +477,7 @@ describe('NzRangePickerComponent', () => { fixture.detectChanges(); expect(getRangePickerRightInput(fixture.debugElement) === document.activeElement).toBeTruthy(); - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -557,7 +558,7 @@ describe('NzRangePickerComponent', () => { ).toBeTruthy(); // Close left panel - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -583,7 +584,7 @@ describe('NzRangePickerComponent', () => { fixture.detectChanges(); // Close left panel - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur('right'); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -594,7 +595,7 @@ describe('NzRangePickerComponent', () => { expect(+queryFromOverlay('.ant-picker-time-panel-column:nth-child(3) li:first-child').textContent!.trim()).toBe(1); // Close left panel - dispatchMouseEvent(document.body, 'click'); + triggerInputBlur(); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -955,10 +956,6 @@ describe('NzRangePickerComponent', () => { return fixtureDebugElement.queryAll(By.css(`.${PREFIX_CLASS}-input input`))[2].nativeElement as HTMLInputElement; } - // function getSecondSelectedDayCell(): HTMLElement { - // return queryFromOverlay('.ant-picker-panel:last-child td.ant-picker-cell-selected .ant-picker-cell-inner') as HTMLElement; - // } - function getPreBtn(part: RangePartType): HTMLElement { return queryFromOverlay(`.ant-picker-panel:${getCssIndex(part)} .${PREFIX_CLASS}-header-prev-btn`); } @@ -1017,6 +1014,14 @@ describe('NzRangePickerComponent', () => { tick(500); fixture.detectChanges(); } + + function triggerInputBlur(part: 'left' | 'right' = 'left'): void { + if (part === 'left') { + dispatchFakeEvent(getPickerInput(fixture.debugElement), 'blur'); + } else { + dispatchFakeEvent(getRangePickerRightInput(fixture.debugElement), 'blur'); + } + } }); @Component({ diff --git a/components/date-picker/year-picker.component.spec.ts b/components/date-picker/year-picker.component.spec.ts index beba82fdd87..141fe6dc262 100644 --- a/components/date-picker/year-picker.component.spec.ts +++ b/components/date-picker/year-picker.component.spec.ts @@ -5,7 +5,7 @@ import { FormsModule } from '@angular/forms'; import { By } from '@angular/platform-browser'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { dispatchMouseEvent } from 'ng-zorro-antd/core/testing'; +import { dispatchFakeEvent, dispatchMouseEvent } from 'ng-zorro-antd/core/testing'; import { NgStyleInterface } from 'ng-zorro-antd/core/types'; import { getPickerAbstract, getPickerInput } from 'ng-zorro-antd/date-picker/testing/util'; import { PREFIX_CLASS } from 'ng-zorro-antd/date-picker/util'; @@ -51,7 +51,7 @@ describe('NzYearPickerComponent', () => { openPickerByClickTrigger(); expect(getPickerContainer()).not.toBeNull(); - dispatchMouseEvent(document.body, 'click'); + dispatchFakeEvent(getPickerInput(fixture.debugElement), 'blur'); fixture.detectChanges(); tick(500); fixture.detectChanges(); @@ -197,7 +197,7 @@ describe('NzYearPickerComponent', () => { openPickerByClickTrigger(); expect(nzOnOpenChange).toHaveBeenCalledWith(true); - dispatchMouseEvent(document.body, 'click'); + dispatchFakeEvent(getPickerInput(fixture.debugElement), 'blur'); fixture.detectChanges(); flush(); expect(nzOnOpenChange).toHaveBeenCalledWith(false);