diff --git a/components/date-picker/date-picker.component.spec.ts b/components/date-picker/date-picker.component.spec.ts index bd9246b661..516d56b75b 100644 --- a/components/date-picker/date-picker.component.spec.ts +++ b/components/date-picker/date-picker.component.spec.ts @@ -19,8 +19,10 @@ import { dispatchMouseEvent, typeInElement } from 'ng-zorro-antd/core/testing'; -import { NgStyleInterface } from 'ng-zorro-antd/core/types'; +import { ComponentBed, createComponentBed } from 'ng-zorro-antd/core/testing/component-bed'; +import { NgStyleInterface, NzStatus } from 'ng-zorro-antd/core/types'; import { NzI18nModule, NzI18nService, NZ_DATE_LOCALE } from 'ng-zorro-antd/i18n'; +import { NzIconModule } from 'ng-zorro-antd/icon'; import en_US from '../i18n/languages/en_US'; import { NzDatePickerComponent } from './date-picker.component'; @@ -1185,6 +1187,31 @@ describe('date-fns testing', () => { })); }); +describe('status', () => { + let testBed: ComponentBed; + let fixture: ComponentFixture; + let fixtureInstance: NzTestDatePickerStatusComponent; + let datePickerElement!: HTMLElement; + beforeEach(() => { + testBed = createComponentBed(NzTestDatePickerStatusComponent, { imports: [NzDatePickerModule, NzIconModule] }); + fixture = testBed.fixture; + fixtureInstance = fixture.componentInstance; + datePickerElement = fixture.debugElement.query(By.directive(NzDatePickerComponent)).nativeElement; + fixture.detectChanges(); + }); + it('should classname correct', () => { + expect(datePickerElement.classList).toContain('ant-picker-status-error'); + + fixtureInstance.status = 'warning'; + fixture.detectChanges(); + expect(datePickerElement.classList).toContain('ant-picker-status-warning'); + + fixtureInstance.status = ''; + fixture.detectChanges(); + expect(datePickerElement.classList).not.toContain('ant-picker-status-warning'); + }); +}); + @Component({ template: ` @@ -1298,3 +1325,10 @@ class NzTestDatePickerComponent { firstValue!: Date; secondValue!: Date; } + +@Component({ + template: ` ` +}) +class NzTestDatePickerStatusComponent { + status: NzStatus = 'error'; +} diff --git a/components/date-picker/date-picker.component.ts b/components/date-picker/date-picker.component.ts index 573a4668eb..0ce822c451 100644 --- a/components/date-picker/date-picker.component.ts +++ b/components/date-picker/date-picker.component.ts @@ -48,8 +48,16 @@ import { slideMotion } from 'ng-zorro-antd/core/animation'; import { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config'; import { NzNoAnimationDirective } from 'ng-zorro-antd/core/no-animation'; import { CandyDate, cloneDate, CompatibleValue, wrongSortOrder } from 'ng-zorro-antd/core/time'; -import { BooleanInput, FunctionProp, NzSafeAny, OnChangeType, OnTouchedType } from 'ng-zorro-antd/core/types'; -import { InputBoolean, toBoolean, valueFunctionProp } from 'ng-zorro-antd/core/util'; +import { + BooleanInput, + FunctionProp, + NgClassInterface, + NzSafeAny, + NzStatus, + OnChangeType, + OnTouchedType +} from 'ng-zorro-antd/core/types'; +import { getStatusClassNames, InputBoolean, toBoolean, valueFunctionProp } from 'ng-zorro-antd/core/util'; import { DateHelperService, NzDatePickerI18nInterface, @@ -253,6 +261,10 @@ export class NzDatePickerComponent implements OnInit, OnChanges, OnDestroy, Afte extraFooter?: TemplateRef | string; dir: Direction = 'ltr'; + // status + statusCls: NgClassInterface = {}; + hasFeedback: boolean = false; + public panelMode: NzDateMode | NzDateMode[] = 'date'; private destroyed$: Subject = new Subject(); private isCustomPlaceHolder: boolean = false; @@ -273,6 +285,7 @@ export class NzDatePickerComponent implements OnInit, OnChanges, OnDestroy, Afte @Input() nzPopupStyle: object = POPUP_STYLE_PATCH; @Input() nzDropdownClassName?: string; @Input() nzSize: NzDatePickerSizeType = 'default'; + @Input() nzStatus?: NzStatus; @Input() nzFormat!: string; @Input() nzDateRender?: TemplateRef | string | FunctionProp | string>; @Input() nzDisabledTime?: DisabledTimeFn; @@ -648,6 +661,7 @@ export class NzDatePickerComponent implements OnInit, OnChanges, OnDestroy, Afte } ngOnChanges(changes: SimpleChanges): void { + const { nzStatus } = changes; if (changes.nzPopupStyle) { // Always assign the popup style patch this.nzPopupStyle = this.nzPopupStyle ? { ...this.nzPopupStyle, ...POPUP_STYLE_PATCH } : POPUP_STYLE_PATCH; @@ -675,6 +689,10 @@ export class NzDatePickerComponent implements OnInit, OnChanges, OnDestroy, Afte this.setDefaultPlaceHolder(); this.setModeAndFormat(); } + + if (nzStatus) { + this.setStatusStyles(); + } } ngOnDestroy(): void { @@ -823,4 +841,17 @@ export class NzDatePickerComponent implements OnInit, OnChanges, OnDestroy, Afte } } } + + // status + private setStatusStyles(): void { + // render status if nzStatus is set + this.statusCls = getStatusClassNames(this.prefixCls, this.nzStatus, this.hasFeedback); + Object.keys(this.statusCls).forEach(status => { + if (this.statusCls[status]) { + this.renderer.addClass(this.elementRef.nativeElement, status); + } else { + this.renderer.removeClass(this.elementRef.nativeElement, status); + } + }); + } } diff --git a/components/date-picker/demo/status.md b/components/date-picker/demo/status.md new file mode 100644 index 0000000000..915d07ab09 --- /dev/null +++ b/components/date-picker/demo/status.md @@ -0,0 +1,14 @@ +--- +order: 13 +title: + zh-CN: 自定义状态 + en-US: Status +--- + +## zh-CN + +使用 `nzStatus` 为 DatePicker 添加状态,可选 `error` 或者 `warning`。 + +## en-US + +Add status to DatePicker with `nzStatus`, which could be `error` or `warning`. \ No newline at end of file diff --git a/components/date-picker/demo/status.ts b/components/date-picker/demo/status.ts new file mode 100644 index 0000000000..7126858af1 --- /dev/null +++ b/components/date-picker/demo/status.ts @@ -0,0 +1,14 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'nz-demo-date-picker-status', + template: ` + + + + + + + ` +}) +export class NzDemoDatePickerStatusComponent {} diff --git a/components/date-picker/doc/index.en-US.md b/components/date-picker/doc/index.en-US.md index 67c74bee1e..961b67bb75 100644 --- a/components/date-picker/doc/index.en-US.md +++ b/components/date-picker/doc/index.en-US.md @@ -50,6 +50,7 @@ The following APIs are shared by nz-date-picker, nz-range-picker. | `[nzPopupStyle]` | to customize the style of the popup calendar | `object` | `{}` | - | | `[nzRenderExtraFooter]` | render extra footer in panel | `TemplateRef \| string \| (() => TemplateRef \| string)` | - | | `[nzSize]` | determine the size of the input box, the height of `large` and `small`, are 40px and 24px respectively, while default size is 32px | `'large' \| 'small'` | - | - | +| `[nzStatus]` | Set validation status | `'error' \| 'warning'` | - | | `[nzSuffixIcon]` | the custom suffix icon | `string` \| `TemplateRef` | - | ✅ | | `[nzBorderless]` | remove the border | `boolean` | `false` | - | | `[nzInline]` | inline mode | `boolean` | `false` | - | diff --git a/components/date-picker/doc/index.zh-CN.md b/components/date-picker/doc/index.zh-CN.md index 748852113b..d1f27e4ad8 100644 --- a/components/date-picker/doc/index.zh-CN.md +++ b/components/date-picker/doc/index.zh-CN.md @@ -50,6 +50,7 @@ registerLocaleData(zh); | `[nzPopupStyle]` | 额外的弹出日历样式 | `object` | `{}` | - | | `[nzRenderExtraFooter]` | 在面板中添加额外的页脚 | `TemplateRef \| string \| (() => TemplateRef \| string)` | - | | `[nzSize]` | 输入框大小,`large` 高度为 40px,`small` 为 24px,默认是 32px | `'large' \| 'small'` | - | - | +| `[nzStatus]` | 设置校验状态 | `'error' \| 'warning'` | - | | `[nzSuffixIcon]` | 自定义的后缀图标 | `string` \| `TemplateRef` | - | ✅ | | `[nzBorderless]` | 移除边框 | `boolean` | `false` | - | | `[nzInline]` | 内联模式 | `boolean` | `false` | - | diff --git a/components/date-picker/range-picker.component.spec.ts b/components/date-picker/range-picker.component.spec.ts index 69a982e0ab..7d5f42d410 100644 --- a/components/date-picker/range-picker.component.spec.ts +++ b/components/date-picker/range-picker.component.spec.ts @@ -18,7 +18,8 @@ import { typeInElement } from 'ng-zorro-antd/core/testing'; import { CandyDate } from 'ng-zorro-antd/core/time'; -import { NgStyleInterface } from 'ng-zorro-antd/core/types'; +import { NgStyleInterface, NzStatus } from 'ng-zorro-antd/core/types'; +import { NzRangePickerComponent } from 'ng-zorro-antd/date-picker/range-picker.component'; import { RangePartType } from 'ng-zorro-antd/date-picker/standard-types'; import { ENTER_EVENT, @@ -43,7 +44,7 @@ describe('NzRangePickerComponent', () => { TestBed.configureTestingModule({ imports: [FormsModule, NoopAnimationsModule, NzDatePickerModule], providers: [], - declarations: [NzTestRangePickerComponent] + declarations: [NzTestRangePickerComponent, NzTestRangePickerStatusComponent] }); TestBed.compileComponents(); @@ -984,6 +985,30 @@ describe('NzRangePickerComponent', () => { })); }); + describe('status', () => { + let fixtureStatus: ComponentFixture; + let fixtureStatusInstance: NzTestRangePickerStatusComponent; + let rangePickerElement!: HTMLElement; + beforeEach(() => { + fixtureStatus = TestBed.createComponent(NzTestRangePickerStatusComponent); + fixtureStatusInstance = fixtureStatus.componentInstance; + rangePickerElement = fixtureStatus.debugElement.query(By.directive(NzRangePickerComponent)).nativeElement; + fixtureStatus.detectChanges(); + }); + + it('should classname correct', fakeAsync(() => { + expect(rangePickerElement.classList).toContain('ant-picker-status-error'); + + fixtureStatusInstance.status = 'warning'; + fixtureStatus.detectChanges(); + expect(rangePickerElement.classList).toContain('ant-picker-status-warning'); + + fixtureStatusInstance.status = ''; + fixtureStatus.detectChanges(); + expect(rangePickerElement.classList).not.toContain('ant-picker-status-warning'); + })); + }); + //////////// function getCssIndex(part: RangePartType): string { @@ -1168,3 +1193,10 @@ class NzTestRangePickerComponent { // --- Suite 4 singleValue!: Date; } + +@Component({ + template: ` ` +}) +class NzTestRangePickerStatusComponent { + status: NzStatus = 'error'; +}