From 0d8249b31e70c28ea47f37b818ff1c5fe0ac8239 Mon Sep 17 00:00:00 2001 From: simplejason Date: Tue, 31 May 2022 10:33:00 +0800 Subject: [PATCH] feat(module:time-picker): support setting status (#7473) * feat(module:time-picker): support setting status * feat(module:time-picker): add tests --- components/time-picker/demo/module | 3 +- components/time-picker/demo/status.md | 14 +++++ components/time-picker/demo/status.ts | 12 ++++ components/time-picker/doc/index.en-US.md | 2 + components/time-picker/doc/index.zh-CN.md | 2 + .../time-picker/time-picker.component.spec.ts | 62 ++++++++++++++++++- .../time-picker/time-picker.component.ts | 26 +++++++- 7 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 components/time-picker/demo/status.md create mode 100644 components/time-picker/demo/status.ts 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); + } + }); + } }