diff --git a/components/time-picker/demo/module b/components/time-picker/demo/module
index 1e2e57c55e..c029b233b2 100644
--- a/components/time-picker/demo/module
+++ b/components/time-picker/demo/module
@@ -1,4 +1,5 @@
import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
import { NzButtonModule } from 'ng-zorro-antd/button';
+import { NzSpaceModule } from 'ng-zorro-antd/space';
-export const moduleList = [ NzTimePickerModule, NzButtonModule ];
+export const moduleList = [ NzTimePickerModule, NzButtonModule, NzSpaceModule ];
diff --git a/components/time-picker/demo/status.md b/components/time-picker/demo/status.md
new file mode 100644
index 0000000000..e12a7ba834
--- /dev/null
+++ b/components/time-picker/demo/status.md
@@ -0,0 +1,14 @@
+---
+order: 10
+title:
+ zh-CN: 自定义状态
+ en-US: Status
+---
+
+## zh-CN
+
+使用 `nzStatus` 为 TimePicker 添加状态,可选 `error` 或者 `warning`。
+
+## en-US
+
+Add status to TimePicker with `nzStatus`, which could be `error` or `warning`.
\ No newline at end of file
diff --git a/components/time-picker/demo/status.ts b/components/time-picker/demo/status.ts
new file mode 100644
index 0000000000..a98fc03e4e
--- /dev/null
+++ b/components/time-picker/demo/status.ts
@@ -0,0 +1,12 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'nz-demo-time-picker-status',
+ template: `
+
+
+ >
+
+ `
+})
+export class NzDemoTimePickerStatusComponent {}
diff --git a/components/time-picker/doc/index.en-US.md b/components/time-picker/doc/index.en-US.md
index 2ac53bc2a6..922487878f 100644
--- a/components/time-picker/doc/index.en-US.md
+++ b/components/time-picker/doc/index.en-US.md
@@ -44,6 +44,8 @@ import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
| `[nzHourStep]` | interval between hours in picker | `number` | `1` | ✅ |
| `[nzMinuteStep]` | interval between minutes in picker | `number` | `1` | ✅ |
| `[nzSecondStep]` | interval between seconds in picker | `number` | `1` | ✅ |
+| `[nzSize]` | width of time picker box | `'large' \| 'small' \| 'default'` | `'default'` |
+| `[nzStatus]` | Set validation status | `'error' \| 'warning'` | - |
| `[nzOpen]` | whether to popup panel, double binding | `boolean` | `false` |
| `[nzPlaceHolder]` | display when there's no value | `string` | `"Select a time"` |
| `[nzPopupClassName]` | className of panel | `string` | `''` | ✅ |
diff --git a/components/time-picker/doc/index.zh-CN.md b/components/time-picker/doc/index.zh-CN.md
index 61536611fc..09f2b74794 100644
--- a/components/time-picker/doc/index.zh-CN.md
+++ b/components/time-picker/doc/index.zh-CN.md
@@ -45,6 +45,8 @@ import { NzTimePickerModule } from 'ng-zorro-antd/time-picker';
| `[nzHourStep]` | 小时选项间隔 | `number` | `1` | ✅ |
| `[nzMinuteStep]` | 分钟选项间隔 | `number` | `1` | ✅ |
| `[nzSecondStep]` | 秒选项间隔 | `number` | `1` | ✅ |
+| `[nzSize]` | 时间选择框大小 | `'large'\|'small'\|'default'` | `'default'` |
+| `[nzStatus]` | 设置校验状态 | `'error' \| 'warning'` | - |
| `[nzOpen]` | 面板是否打开,可双向绑定 | `boolean` | `false` |
| `[nzPlaceHolder]` | 没有值的时候显示的内容 | `string` | `"请选择时间"` |
| `[nzPopupClassName]` | 弹出层类名 | `string` | `''` | ✅ |
diff --git a/components/time-picker/time-picker.component.spec.ts b/components/time-picker/time-picker.component.spec.ts
index ff1e6d4911..ffd4716f2c 100644
--- a/components/time-picker/time-picker.component.spec.ts
+++ b/components/time-picker/time-picker.component.spec.ts
@@ -1,3 +1,4 @@
+import { BidiModule, Direction } from '@angular/cdk/bidi';
import { OverlayContainer } from '@angular/cdk/overlay';
import { registerLocaleData } from '@angular/common';
import zh from '@angular/common/locales/zh';
@@ -8,6 +9,7 @@ import { By } from '@angular/platform-browser';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { dispatchFakeEvent, dispatchMouseEvent, typeInElement } from 'ng-zorro-antd/core/testing';
+import { NzStatus } from 'ng-zorro-antd/core/types';
import { PREFIX_CLASS } from 'ng-zorro-antd/date-picker';
import { getPickerInput, getPickerOkButton } from 'ng-zorro-antd/date-picker/testing/util';
@@ -24,9 +26,9 @@ describe('time-picker', () => {
beforeEach(
waitForAsync(() => {
TestBed.configureTestingModule({
- imports: [NoopAnimationsModule, FormsModule, NzI18nModule, NzTimePickerModule],
+ imports: [BidiModule, NoopAnimationsModule, FormsModule, NzI18nModule, NzTimePickerModule],
schemas: [NO_ERRORS_SCHEMA],
- declarations: [NzTestTimePickerComponent]
+ declarations: [NzTestTimePickerComponent, NzTestTimePickerStatusComponent, NzTestTimePickerDirComponent]
});
TestBed.compileComponents();
inject([OverlayContainer], (oc: OverlayContainer) => {
@@ -292,6 +294,48 @@ describe('time-picker', () => {
});
});
+ describe('time-picker status', () => {
+ let testComponent: NzTestTimePickerStatusComponent;
+ let fixture: ComponentFixture;
+ let timeElement: DebugElement;
+ beforeEach(() => {
+ fixture = TestBed.createComponent(NzTestTimePickerStatusComponent);
+ testComponent = fixture.debugElement.componentInstance;
+ fixture.detectChanges();
+ timeElement = fixture.debugElement.query(By.directive(NzTimePickerComponent));
+ });
+ it('should className correct with nzStatus', () => {
+ fixture.detectChanges();
+ expect(timeElement.nativeElement.classList).toContain('ant-picker-status-error');
+
+ testComponent.status = 'warning';
+ fixture.detectChanges();
+ expect(timeElement.nativeElement.className).toContain('ant-picker-status-warning');
+
+ testComponent.status = '';
+ fixture.detectChanges();
+ expect(timeElement.nativeElement.className).not.toContain('ant-picker-status-warning');
+ });
+ });
+
+ describe('time-picker RTL', () => {
+ let testComponent: NzTestTimePickerDirComponent;
+ let fixture: ComponentFixture;
+ let timeElement: DebugElement;
+ beforeEach(() => {
+ fixture = TestBed.createComponent(NzTestTimePickerDirComponent);
+ testComponent = fixture.debugElement.componentInstance;
+ fixture.detectChanges();
+ timeElement = fixture.debugElement.query(By.directive(NzTimePickerComponent));
+ });
+ it('should className correct on dir change', () => {
+ expect(timeElement.nativeElement.classList).not.toContain('ant-picker-rtl');
+ testComponent.dir = 'rtl';
+ fixture.detectChanges();
+ expect(timeElement.nativeElement.classList).toContain('ant-picker-rtl');
+ });
+ });
+
function queryFromOverlay(selector: string): HTMLElement {
return overlayContainerElement.querySelector(selector) as HTMLElement;
}
@@ -334,3 +378,17 @@ export class NzTestTimePickerComponent {
onChange(_: Date | null): void {}
@ViewChild(NzTimePickerComponent, { static: false }) nzTimePickerComponent!: NzTimePickerComponent;
}
+
+@Component({
+ template: ` `
+})
+export class NzTestTimePickerStatusComponent {
+ status: NzStatus = 'error';
+}
+
+@Component({
+ template: `
`
+})
+export class NzTestTimePickerDirComponent {
+ dir: Direction = 'ltr';
+}
diff --git a/components/time-picker/time-picker.component.ts b/components/time-picker/time-picker.component.ts
index e937001761..301776d926 100644
--- a/components/time-picker/time-picker.component.ts
+++ b/components/time-picker/time-picker.component.ts
@@ -34,8 +34,8 @@ import { isValid } from 'date-fns';
import { slideMotion } from 'ng-zorro-antd/core/animation';
import { NzConfigKey, NzConfigService, WithConfig } from 'ng-zorro-antd/core/config';
import { warn } from 'ng-zorro-antd/core/logger';
-import { BooleanInput, NzSafeAny } from 'ng-zorro-antd/core/types';
-import { InputBoolean, isNil } from 'ng-zorro-antd/core/util';
+import { BooleanInput, NgClassInterface, NzSafeAny, NzStatus } from 'ng-zorro-antd/core/types';
+import { getStatusClassNames, InputBoolean, isNil } from 'ng-zorro-antd/core/util';
import { DateHelperService, NzI18nInterface, NzI18nService } from 'ng-zorro-antd/i18n';
const NZ_CONFIG_MODULE_NAME: NzConfigKey = 'timePicker';
@@ -176,10 +176,15 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
}
] as ConnectionPositionPair[];
dir: Direction = 'ltr';
+ // status
+ prefixCls: string = 'ant-picker';
+ statusCls: NgClassInterface = {};
+ hasFeedback: boolean = false;
@ViewChild('inputElement', { static: true }) inputRef!: ElementRef;
@Input() nzId: string | null = null;
@Input() nzSize: string | null = null;
+ @Input() nzStatus?: NzStatus;
@Input() @WithConfig() nzHourStep: number = 1;
@Input() @WithConfig() nzMinuteStep: number = 1;
@Input() @WithConfig() nzSecondStep: number = 1;
@@ -347,7 +352,7 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
}
ngOnChanges(changes: SimpleChanges): void {
- const { nzUse12Hours, nzFormat, nzDisabled, nzAutoFocus } = changes;
+ const { nzUse12Hours, nzFormat, nzDisabled, nzAutoFocus, nzStatus } = changes;
if (nzUse12Hours && !nzUse12Hours.previousValue && nzUse12Hours.currentValue && !nzFormat) {
this.nzFormat = 'h:mm:ss a';
}
@@ -363,6 +368,9 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
if (nzAutoFocus) {
this.updateAutoFocus();
}
+ if (nzStatus) {
+ this.setStatusStyles();
+ }
}
parseTimeString(str: string): void {
@@ -421,4 +429,16 @@ export class NzTimePickerComponent implements ControlValueAccessor, OnInit, Afte
disabledSeconds?.includes(value.getSeconds())
);
}
+
+ 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.element.nativeElement, status);
+ } else {
+ this.renderer.removeClass(this.element.nativeElement, status);
+ }
+ });
+ }
}