diff --git a/components/button/button-group.component.ts b/components/button/button-group.component.ts index 3684b34cc5d..7bd61a9d3d0 100644 --- a/components/button/button-group.component.ts +++ b/components/button/button-group.component.ts @@ -7,6 +7,7 @@ */ import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit, ViewEncapsulation } from '@angular/core'; +import { IndexableObject } from 'ng-zorro-antd/core'; export type NzButtonGroupSize = 'large' | 'default' | 'small'; @@ -23,7 +24,7 @@ export type NzButtonGroupSize = 'large' | 'default' | 'small'; }) export class NzButtonGroupComponent implements OnInit, OnChanges { @Input() nzSize: NzButtonGroupSize = 'default'; - hostClassMap = {}; + hostClassMap: IndexableObject = {}; updateHostClassMap(): void { this.hostClassMap = { ['ant-btn-group']: true, diff --git a/components/button/button.component.ts b/components/button/button.component.ts index c8cde6ca454..cf3d1777f72 100644 --- a/components/button/button.component.ts +++ b/components/button/button.component.ts @@ -14,21 +14,16 @@ import { Component, ContentChild, ElementRef, - HostBinding, - Inject, Input, - NgZone, OnChanges, OnDestroy, OnInit, - Optional, Renderer2, SimpleChanges, ViewEncapsulation } from '@angular/core'; -import { ANIMATION_MODULE_TYPE } from '@angular/platform-browser/animations'; -import { InputBoolean, NZ_WAVE_GLOBAL_CONFIG, NzConfigService, NzWaveConfig, NzWaveDirective, WithConfig } from 'ng-zorro-antd/core'; +import { IndexableObject, InputBoolean, NzConfigService, WithConfig } from 'ng-zorro-antd/core'; import { NzIconDirective } from 'ng-zorro-antd/icon'; import { Subject } from 'rxjs'; import { filter, startWith, takeUntil } from 'rxjs/operators'; @@ -53,7 +48,6 @@ const NZ_CONFIG_COMPONENT_NAME = 'button'; }) export class NzButtonComponent implements OnInit, OnDestroy, OnChanges, AfterViewInit, AfterContentInit { @ContentChild(NzIconDirective, { read: ElementRef }) nzIconDirectiveElement: ElementRef; - @HostBinding('attr.nz-wave') nzWave = new NzWaveDirective(this.ngZone, this.elementRef, this.waveConfig, this.animationType); @Input() @InputBoolean() nzBlock: boolean = false; @Input() @InputBoolean() nzGhost: boolean = false; @Input() @InputBoolean() nzSearch: boolean = false; @@ -62,10 +56,9 @@ export class NzButtonComponent implements OnInit, OnDestroy, OnChanges, AfterVie @Input() nzType: NzButtonType = null; @Input() nzShape: NzButtonShape = null; @Input() @WithConfig(NZ_CONFIG_COMPONENT_NAME, 'default') nzSize: NzButtonSize; - readonly nativeElement: HTMLElement = this.elementRef.nativeElement; private destroy$ = new Subject(); private loading$ = new Subject(); - hostClassMap = {}; + hostClassMap: IndexableObject = {}; updateHostClassMap(): void { this.hostClassMap = { @@ -102,10 +95,7 @@ export class NzButtonComponent implements OnInit, OnDestroy, OnChanges, AfterVie private elementRef: ElementRef, private cdr: ChangeDetectorRef, private renderer: Renderer2, - private ngZone: NgZone, - public nzConfigService: NzConfigService, - @Optional() @Inject(NZ_WAVE_GLOBAL_CONFIG) private waveConfig: NzWaveConfig, - @Optional() @Inject(ANIMATION_MODULE_TYPE) private animationType: string + public nzConfigService: NzConfigService ) { this.nzConfigService .getConfigChangeEventForComponent(NZ_CONFIG_COMPONENT_NAME) @@ -117,30 +107,18 @@ export class NzButtonComponent implements OnInit, OnDestroy, OnChanges, AfterVie ngOnInit(): void { this.updateHostClassMap(); - this.nzWave.ngOnInit(); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - this.nzWave.ngOnDestroy(); } ngOnChanges(changes: SimpleChanges): void { this.updateHostClassMap(); - const { nzType, nzLoading } = changes; + const { nzLoading } = changes; if (nzLoading) { this.loading$.next(this.nzLoading); } - if (nzType && nzType.currentValue === 'link') { - this.nzWave.disable(); - } else { - this.nzWave.enable(); - } } ngAfterViewInit(): void { - this.insertSpan(this.nativeElement.childNodes, this.renderer); + this.insertSpan(this.elementRef.nativeElement.childNodes, this.renderer); } ngAfterContentInit(): void { @@ -159,4 +137,9 @@ export class NzButtonComponent implements OnInit, OnDestroy, OnChanges, AfterVie } }); } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } } diff --git a/components/button/button.module.ts b/components/button/button.module.ts index 701032b09d2..370d0f4cd67 100644 --- a/components/button/button.module.ts +++ b/components/button/button.module.ts @@ -11,13 +11,12 @@ import { NgModule } from '@angular/core'; import { NzWaveModule, ɵNzTransitionPatchModule as NzTransitionPatchModule } from 'ng-zorro-antd/core'; import { NzIconModule } from 'ng-zorro-antd/icon'; - import { NzButtonGroupComponent } from './button-group.component'; import { NzButtonComponent } from './button.component'; @NgModule({ declarations: [NzButtonComponent, NzButtonGroupComponent], - exports: [NzButtonComponent, NzButtonGroupComponent, NzTransitionPatchModule], + exports: [NzButtonComponent, NzButtonGroupComponent, NzTransitionPatchModule, NzWaveModule], imports: [CommonModule, NzWaveModule, NzIconModule, NzTransitionPatchModule] }) export class NzButtonModule {} diff --git a/components/core/config/config.ts b/components/core/config/config.ts index 96371be5e03..e4dc17e15ad 100644 --- a/components/core/config/config.ts +++ b/components/core/config/config.ts @@ -8,10 +8,10 @@ import { InjectionToken, TemplateRef, Type } from '@angular/core'; -import { NzAlignType, NzShapeSCType, NzSizeDSType, NzSizeLDSType, NzSizeMDSType } from '../types'; - import { SafeUrl } from '@angular/platform-browser'; -import { BreakpointMap, NzBreakpoint } from '../responsive/public-api'; +import { NzBreakpointEnum } from '../responsive/public-api'; + +import { NzShapeSCType, NzSizeDSType, NzSizeLDSType, NzSizeMDSType } from '../types'; export interface NzConfig { affix?: AffixConfig; @@ -31,7 +31,6 @@ export interface NzConfig { drawer?: DrawerConfig; empty?: EmptyConfig; form?: FormConfig; - grid?: GridConfig; icon?: IconConfig; message?: MessageConfig; modal?: ModalConfig; @@ -125,7 +124,7 @@ export interface CollapsePanelConfig { export interface DescriptionsConfig { nzBorder?: boolean; - nzColumn?: { [key in NzBreakpoint]?: number } | number; + nzColumn?: { [key in NzBreakpointEnum]?: number } | number; nzSize?: 'default' | 'middle' | 'small'; nzColon?: boolean; } @@ -144,13 +143,6 @@ export interface FormConfig { nzNoColon?: boolean; } -export interface GridConfig { - nzAlign?: NzAlignType; - nzGutter?: number | BreakpointMap; - nzJustify?: 'start' | 'end' | 'center' | 'space-around' | 'space-between'; - nzType?: 'flex'; -} - export interface IconConfig { nzTheme?: 'fill' | 'outline' | 'twotone'; nzTwotoneColor?: string; diff --git a/components/core/responsive/nz-breakpoint.ts b/components/core/responsive/nz-breakpoint.ts index 0371b41dba6..f0a79b15d2a 100644 --- a/components/core/responsive/nz-breakpoint.ts +++ b/components/core/responsive/nz-breakpoint.ts @@ -6,7 +6,7 @@ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE */ -export enum NzBreakpoint { +export enum NzBreakpointEnum { xxl = 'xxl', xl = 'xl', lg = 'lg', @@ -15,9 +15,8 @@ export enum NzBreakpoint { xs = 'xs' } -export type NzBreakPoint = 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'xxl'; - -export type BreakpointMap = { [key in NzBreakpoint]: string }; +export type BreakpointMap = { [key in NzBreakpointEnum]: string }; +export type NzBreakpointKey = keyof typeof NzBreakpointEnum; export const responsiveMap: BreakpointMap = { xs: '(max-width: 575px)', diff --git a/components/core/transition-patch/transition-patch.spec.ts b/components/core/transition-patch/transition-patch.spec.ts index e9a26316dac..3da4bdfa53c 100644 --- a/components/core/transition-patch/transition-patch.spec.ts +++ b/components/core/transition-patch/transition-patch.spec.ts @@ -31,21 +31,21 @@ describe('transition-patch', () => { @Component({ template: ` - + ` }) export class TestTransitionPatchComponent {} @Component({ template: ` - + ` }) export class TestTransitionPatchHiddenComponent {} @Component({ template: ` - + ` }) export class TestTransitionPatchRestoreComponent {} diff --git a/components/core/types/direction.ts b/components/core/types/direction.ts index 86753c3211b..f4d426086c7 100644 --- a/components/core/types/direction.ts +++ b/components/core/types/direction.ts @@ -9,5 +9,3 @@ export type NzDirectionVHIType = 'vertical' | 'horizontal' | 'inline'; export type NzDirectionVHType = 'vertical' | 'horizontal'; export type NzFourDirectionType = 'top' | 'bottom' | 'left' | 'right'; - -export type NzAlignType = 'top' | 'middle' | 'bottom'; diff --git a/components/core/wave/nz-wave.directive.ts b/components/core/wave/nz-wave.directive.ts index 655de9718d9..21aa24f3263 100644 --- a/components/core/wave/nz-wave.directive.ts +++ b/components/core/wave/nz-wave.directive.ts @@ -28,7 +28,7 @@ export function NZ_WAVE_GLOBAL_CONFIG_FACTORY(): NzWaveConfig { } @Directive({ - selector: '[nz-wave]', + selector: '[nz-wave],button[nz-button]', exportAs: 'nzWave' }) export class NzWaveDirective implements OnInit, OnDestroy { diff --git a/components/descriptions/nz-descriptions.component.ts b/components/descriptions/nz-descriptions.component.ts index b2974fd1185..bba2b0fa5f3 100644 --- a/components/descriptions/nz-descriptions.component.ts +++ b/components/descriptions/nz-descriptions.component.ts @@ -22,15 +22,15 @@ import { TemplateRef, ViewEncapsulation } from '@angular/core'; + +import { InputBoolean, NzBreakpointEnum, NzConfigService, NzDomEventService, responsiveMap, warn, WithConfig } from 'ng-zorro-antd/core'; import { merge, Subject } from 'rxjs'; import { auditTime, finalize, startWith, switchMap, takeUntil } from 'rxjs/operators'; - -import { InputBoolean, NzBreakpoint, NzConfigService, NzDomEventService, responsiveMap, warn, WithConfig } from 'ng-zorro-antd/core'; import { NzDescriptionsItemRenderProps, NzDescriptionsLayout, NzDescriptionsSize } from './nz-descriptions-definitions'; import { NzDescriptionsItemComponent } from './nz-descriptions-item.component'; const NZ_CONFIG_COMPONENT_NAME = 'descriptions'; -const defaultColumnMap: { [key in NzBreakpoint]: number } = { +const defaultColumnMap: { [key in NzBreakpointEnum]: number } = { xxl: 3, xl: 3, lg: 3, @@ -65,7 +65,7 @@ export class NzDescriptionsComponent implements OnChanges, OnDestroy, AfterConte @Input() @InputBoolean() @WithConfig(NZ_CONFIG_COMPONENT_NAME, false) nzBordered: boolean; @Input() nzLayout: NzDescriptionsLayout = 'horizontal'; - @Input() @WithConfig(NZ_CONFIG_COMPONENT_NAME, defaultColumnMap) nzColumn: number | { [key in NzBreakpoint]: number }; + @Input() @WithConfig(NZ_CONFIG_COMPONENT_NAME, defaultColumnMap) nzColumn: number | { [key in NzBreakpointEnum]: number }; @Input() @WithConfig(NZ_CONFIG_COMPONENT_NAME, 'default') nzSize: NzDescriptionsSize; @Input() nzTitle: string | TemplateRef = ''; @Input() @WithConfig(NZ_CONFIG_COMPONENT_NAME, true) @InputBoolean() nzColon: boolean; @@ -165,11 +165,11 @@ export class NzDescriptionsComponent implements OnChanges, OnDestroy, AfterConte this.itemMatrix = matrix; } - private matchMedia(): NzBreakpoint { - let bp: NzBreakpoint = NzBreakpoint.md; + private matchMedia(): NzBreakpointEnum { + let bp: NzBreakpointEnum = NzBreakpointEnum.md; Object.keys(responsiveMap).map((breakpoint: string) => { - const castBP = breakpoint as NzBreakpoint; + const castBP = breakpoint as NzBreakpointEnum; const matchBelow = this.mediaMatcher.matchMedia(responsiveMap[castBP]).matches; if (matchBelow) { bp = castBP; diff --git a/components/form/nz-form-control.component.ts b/components/form/nz-form-control.component.ts index 0d1beba5964..4561022ac24 100644 --- a/components/form/nz-form-control.component.ts +++ b/components/form/nz-form-control.component.ts @@ -8,7 +8,6 @@ import { AfterContentInit, - AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, @@ -24,11 +23,10 @@ import { ViewEncapsulation } from '@angular/core'; import { FormControl, FormControlDirective, FormControlName, NgControl, NgModel } from '@angular/forms'; + +import { helpMotion, NgClassType, toBoolean } from 'ng-zorro-antd/core'; import { Subscription } from 'rxjs'; import { startWith } from 'rxjs/operators'; - -import { helpMotion, NgClassType, NzUpdateHostClassService, toBoolean } from 'ng-zorro-antd/core'; -import { NzColDirective, NzRowDirective } from 'ng-zorro-antd/grid'; import { NzFormItemComponent } from './nz-form-item.component'; export type NzFormControlStatusType = 'warning' | 'validating' | 'error' | 'success' | null; @@ -40,7 +38,6 @@ export type NzFormControlStatusType = 'warning' | 'validating' | 'error' | 'succ animations: [helpMotion], encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, - providers: [NzUpdateHostClassService], templateUrl: './nz-form-control.component.html', styles: [ ` @@ -53,7 +50,7 @@ export type NzFormControlStatusType = 'warning' | 'validating' | 'error' | 'succ ` ] }) -export class NzFormControlComponent extends NzColDirective implements OnDestroy, OnInit, AfterContentInit, AfterViewInit, OnDestroy { +export class NzFormControlComponent implements OnDestroy, OnInit, AfterContentInit, OnDestroy { private _hasFeedback = false; private validateChanges: Subscription = Subscription.EMPTY; private validateString: string | null; @@ -170,25 +167,20 @@ export class NzFormControlComponent extends NzColDirective implements OnDestroy, } constructor( - nzUpdateHostClassService: NzUpdateHostClassService, elementRef: ElementRef, @Optional() @Host() private nzFormItemComponent: NzFormItemComponent, - @Optional() @Host() nzRowDirective: NzRowDirective, private cdr: ChangeDetectorRef, renderer: Renderer2 ) { - super(nzUpdateHostClassService, elementRef, nzFormItemComponent || nzRowDirective, renderer); renderer.addClass(elementRef.nativeElement, 'ant-form-item-control-wrapper'); } ngOnInit(): void { - super.ngOnInit(); this.setControlClassMap(); } ngOnDestroy(): void { this.removeSubscribe(); - super.ngOnDestroy(); } ngAfterContentInit(): void { @@ -200,8 +192,4 @@ export class NzFormControlComponent extends NzColDirective implements OnDestroy, } } } - - ngAfterViewInit(): void { - super.ngAfterViewInit(); - } } diff --git a/components/form/nz-form-item.component.ts b/components/form/nz-form-item.component.ts index 25565f32edd..ad7c97ad7ce 100644 --- a/components/form/nz-form-item.component.ts +++ b/components/form/nz-form-item.component.ts @@ -6,8 +6,6 @@ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE */ -import { MediaMatcher } from '@angular/cdk/layout'; -import { Platform } from '@angular/cdk/platform'; import { AfterContentInit, ChangeDetectionStrategy, @@ -16,19 +14,17 @@ import { ContentChildren, ElementRef, Input, - NgZone, OnChanges, OnDestroy, - OnInit, QueryList, Renderer2, SimpleChanges, ViewEncapsulation } from '@angular/core'; -import { startWith, takeUntil } from 'rxjs/operators'; -import { InputBoolean, NzDomEventService, NzUpdateHostClassService } from 'ng-zorro-antd/core'; -import { NzRowDirective } from 'ng-zorro-antd/grid'; +import { InputBoolean } from 'ng-zorro-antd/core'; +import { Subject } from 'rxjs'; +import { startWith, takeUntil } from 'rxjs/operators'; import { NzFormExplainComponent } from './nz-form-explain.component'; @@ -39,7 +35,6 @@ import { NzFormExplainComponent } from './nz-form-explain.component'; preserveWhitespaces: false, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, - providers: [NzUpdateHostClassService], templateUrl: './nz-form-item.component.html', host: { '[class.ant-form-item-with-help]': 'withHelpClass' @@ -52,12 +47,13 @@ import { NzFormExplainComponent } from './nz-form-explain.component'; ` ] }) -export class NzFormItemComponent extends NzRowDirective implements AfterContentInit, OnDestroy, OnChanges, OnInit, OnDestroy { +export class NzFormItemComponent implements AfterContentInit, OnDestroy, OnChanges, OnDestroy { @Input() @InputBoolean() nzFlex: boolean = false; @ContentChildren(NzFormExplainComponent, { descendants: true }) listOfNzFormExplainComponent: QueryList; withHelpClass = false; tipsMode = false; + private destroy$ = new Subject(); updateFlexStyle(): void { if (this.nzFlex) { @@ -73,17 +69,7 @@ export class NzFormItemComponent extends NzRowDirective implements AfterContentI this.cdr.markForCheck(); } - constructor( - elementRef: ElementRef, - renderer: Renderer2, - nzUpdateHostClassService: NzUpdateHostClassService, - mediaMatcher: MediaMatcher, - ngZone: NgZone, - platform: Platform, - nzDomEventService: NzDomEventService, - private cdr: ChangeDetectorRef - ) { - super(elementRef, renderer, nzUpdateHostClassService, mediaMatcher, ngZone, platform, nzDomEventService); + constructor(private elementRef: ElementRef, private renderer: Renderer2, private cdr: ChangeDetectorRef) { renderer.addClass(elementRef.nativeElement, 'ant-form-item'); } @@ -96,20 +82,14 @@ export class NzFormItemComponent extends NzRowDirective implements AfterContentI } } - ngOnInit(): void { - super.ngOnInit(); - - this.updateFlexStyle(); - } - - ngOnDestroy(): void { - super.ngOnDestroy(); - } - ngOnChanges(changes: SimpleChanges): void { - super.ngOnChanges(changes); if (changes.hasOwnProperty('nzFlex')) { this.updateFlexStyle(); } } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } } diff --git a/components/form/nz-form-label.component.ts b/components/form/nz-form-label.component.ts index 985f0d59bc3..0b4228a5bd1 100644 --- a/components/form/nz-form-label.component.ts +++ b/components/form/nz-form-label.component.ts @@ -6,35 +6,19 @@ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE */ -import { - AfterViewInit, - ChangeDetectionStrategy, - ChangeDetectorRef, - Component, - ElementRef, - Host, - Input, - OnDestroy, - Optional, - Renderer2, - ViewEncapsulation -} from '@angular/core'; +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Input, Renderer2, ViewEncapsulation } from '@angular/core'; -import { InputBoolean, NzUpdateHostClassService, toBoolean } from 'ng-zorro-antd/core'; -import { NzColDirective, NzRowDirective } from 'ng-zorro-antd/grid'; - -import { NzFormItemComponent } from './nz-form-item.component'; +import { InputBoolean, toBoolean } from 'ng-zorro-antd/core'; @Component({ selector: 'nz-form-label', exportAs: 'nzFormLabel', - providers: [NzUpdateHostClassService], preserveWhitespaces: false, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, templateUrl: './nz-form-label.component.html' }) -export class NzFormLabelComponent extends NzColDirective implements OnDestroy, AfterViewInit { +export class NzFormLabelComponent { @Input() nzFor: string; @Input() @InputBoolean() nzRequired = false; @Input() @@ -48,15 +32,7 @@ export class NzFormLabelComponent extends NzColDirective implements OnDestroy, A defaultNoColon: boolean = false; noColon: boolean | string = 'default'; - constructor( - nzUpdateHostClassService: NzUpdateHostClassService, - elementRef: ElementRef, - @Optional() @Host() nzFormItemComponent: NzFormItemComponent, - @Optional() @Host() nzRowDirective: NzRowDirective, - renderer: Renderer2, - private cdr: ChangeDetectorRef - ) { - super(nzUpdateHostClassService, elementRef, nzFormItemComponent || nzRowDirective, renderer); + constructor(elementRef: ElementRef, renderer: Renderer2, private cdr: ChangeDetectorRef) { renderer.addClass(elementRef.nativeElement, 'ant-form-item-label'); } @@ -64,12 +40,4 @@ export class NzFormLabelComponent extends NzColDirective implements OnDestroy, A this.defaultNoColon = toBoolean(value); this.cdr.markForCheck(); } - - ngOnDestroy(): void { - super.ngOnDestroy(); - } - - ngAfterViewInit(): void { - super.ngAfterViewInit(); - } } diff --git a/components/form/nz-form.directive.ts b/components/form/nz-form.directive.ts index c6a0a04194a..e4455d927f5 100644 --- a/components/form/nz-form.directive.ts +++ b/components/form/nz-form.directive.ts @@ -19,11 +19,11 @@ import { Renderer2, SimpleChanges } from '@angular/core'; + +import { InputBoolean, NzConfigService, WithConfig } from 'ng-zorro-antd/core'; import { Subject } from 'rxjs'; import { startWith, takeUntil } from 'rxjs/operators'; -import { InputBoolean, NzConfigService, NzUpdateHostClassService, WithConfig } from 'ng-zorro-antd/core'; - import { NzFormLabelComponent } from './nz-form-label.component'; const NZ_CONFIG_COMPONENT_NAME = 'form'; @@ -31,20 +31,21 @@ const NZ_CONFIG_COMPONENT_NAME = 'form'; @Directive({ selector: '[nz-form]', exportAs: 'nzForm', - providers: [NzUpdateHostClassService] + host: { '[class]': 'hostClassMap' } }) export class NzFormDirective implements OnInit, OnChanges, AfterContentInit, OnDestroy { @Input() nzLayout = 'horizontal'; @Input() @WithConfig(NZ_CONFIG_COMPONENT_NAME, false) @InputBoolean() nzNoColon: boolean; + hostClassMap = {}; @ContentChildren(NzFormLabelComponent, { descendants: true }) nzFormLabelComponent: QueryList; destroy$ = new Subject(); setClassMap(): void { - this.nzUpdateHostClassService.updateHostClass(this.elementRef.nativeElement, { + this.hostClassMap = { [`ant-form-${this.nzLayout}`]: this.nzLayout - }); + }; } updateItemsDefaultColon(): void { @@ -53,12 +54,7 @@ export class NzFormDirective implements OnInit, OnChanges, AfterContentInit, OnD } } - constructor( - public nzConfigService: NzConfigService, - private elementRef: ElementRef, - private renderer: Renderer2, - private nzUpdateHostClassService: NzUpdateHostClassService - ) { + constructor(public nzConfigService: NzConfigService, elementRef: ElementRef, private renderer: Renderer2) { this.renderer.addClass(elementRef.nativeElement, 'ant-form'); } diff --git a/components/form/nz-form.module.ts b/components/form/nz-form.module.ts index eb733b14caf..5a3b944d3cf 100644 --- a/components/form/nz-form.module.ts +++ b/components/form/nz-form.module.ts @@ -11,10 +11,10 @@ import { PlatformModule } from '@angular/cdk/platform'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; +import { NzAddOnModule } from 'ng-zorro-antd/core'; + import { NzGridModule } from 'ng-zorro-antd/grid'; import { NzIconModule } from 'ng-zorro-antd/icon'; - -import { NzAddOnModule } from 'ng-zorro-antd/core'; import { NzFormControlComponent } from './nz-form-control.component'; import { NzFormExplainComponent } from './nz-form-explain.component'; import { NzFormExtraComponent } from './nz-form-extra.component'; @@ -43,7 +43,8 @@ import { NzFormDirective } from './nz-form.directive'; NzFormControlComponent, NzFormExplainComponent, NzFormTextComponent, - NzFormSplitComponent + NzFormSplitComponent, + NzGridModule ], imports: [CommonModule, NzGridModule, NzIconModule, LayoutModule, PlatformModule, NzAddOnModule] }) diff --git a/components/grid/col.directive.ts b/components/grid/col.directive.ts new file mode 100644 index 00000000000..fe4e5ce9867 --- /dev/null +++ b/components/grid/col.directive.ts @@ -0,0 +1,146 @@ +/** + * @license + * Copyright Alibaba.com All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE + */ + +import { + AfterViewInit, + Directive, + ElementRef, + Host, + Input, + OnChanges, + OnDestroy, + OnInit, + Optional, + Renderer2, + SimpleChanges +} from '@angular/core'; +import { IndexableObject, isNotNil, NgClassInterface } from 'ng-zorro-antd/core'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { NzRowDirective } from './row.directive'; + +export interface EmbeddedProperty { + span?: number; + pull?: number; + push?: number; + offset?: number; + order?: number; +} + +@Directive({ + selector: '[nz-col],nz-col,nz-form-control,nz-form-label', + exportAs: 'nzCol', + host: { + '[class]': 'hostClassMap', + '[style.flex]': 'hostFlexStyle' + } +}) +export class NzColDirective implements OnInit, OnChanges, AfterViewInit, OnDestroy { + private destroy$ = new Subject(); + hostClassMap: IndexableObject = {}; + hostFlexStyle: string | null = null; + @Input() nzFlex: string | number | null = null; + @Input() nzSpan: number | null = null; + @Input() nzOrder: number | null = null; + @Input() nzOffset: number | null = null; + @Input() nzPush: number | null = null; + @Input() nzPull: number | null = null; + @Input() nzXs: number | EmbeddedProperty | null = null; + @Input() nzSm: number | EmbeddedProperty | null = null; + @Input() nzMd: number | EmbeddedProperty | null = null; + @Input() nzLg: number | EmbeddedProperty | null = null; + @Input() nzXl: number | EmbeddedProperty | null = null; + @Input() nzXXl: number | EmbeddedProperty | null = null; + + setHostClassMap(): void { + this.hostClassMap = { + ['ant-col']: true, + [`ant-col-${this.nzSpan}`]: isNotNil(this.nzSpan), + [`ant-col-order-${this.nzOrder}`]: isNotNil(this.nzOrder), + [`ant-col-offset-${this.nzOffset}`]: isNotNil(this.nzOffset), + [`ant-col-pull-${this.nzPull}`]: isNotNil(this.nzPull), + [`ant-col-push-${this.nzPush}`]: isNotNil(this.nzPush), + ...this.generateClass() + }; + } + + setHostFlexStyle(): void { + this.hostFlexStyle = this.parseFlex(this.nzFlex); + } + + parseFlex(flex: number | string | null): string | null { + if (typeof flex === 'number') { + return `${flex} ${flex} auto`; + } else if (typeof flex === 'string') { + if (/^\d+(\.\d+)?(px|em|rem|%)$/.test(flex)) { + return `0 0 ${flex}`; + } + } + return flex; + } + + generateClass(): object { + const listOfSizeInputName: Array = ['nzXs', 'nzSm', 'nzMd', 'nzLg', 'nzXl', 'nzXXl']; + const listClassMap: NgClassInterface = {}; + listOfSizeInputName.forEach(name => { + const sizeName = name.replace('nz', '').toLowerCase(); + if (isNotNil(this[name])) { + if (typeof this[name] === 'number' || typeof this[name] === 'string') { + listClassMap[`ant-col-${sizeName}-${this[name]}`] = true; + } else { + const embedded = this[name] as EmbeddedProperty; + const prefixArray: Array = ['span', 'pull', 'push', 'offset', 'order']; + prefixArray.forEach(prefix => { + const prefixClass = prefix === 'span' ? '-' : `-${prefix}-`; + listClassMap[`ant-col-${sizeName}${prefixClass}${embedded[prefix]}`] = embedded && isNotNil(embedded[prefix]); + }); + } + } + }); + return listClassMap; + } + + constructor(private elementRef: ElementRef, @Optional() @Host() public nzRowDirective: NzRowDirective, public renderer: Renderer2) {} + + ngOnInit(): void { + this.setHostClassMap(); + this.setHostFlexStyle(); + } + + ngOnChanges(changes: SimpleChanges): void { + this.setHostClassMap(); + const { nzFlex } = changes; + if (nzFlex) { + this.setHostFlexStyle(); + } + } + + ngAfterViewInit(): void { + if (this.nzRowDirective) { + this.nzRowDirective.actualGutter$.pipe(takeUntil(this.destroy$)).subscribe(([horizontalGutter, verticalGutter]) => { + const renderGutter = (name: string, gutter: number) => { + const nativeElement = this.elementRef.nativeElement; + this.renderer.setStyle(nativeElement, name, `${gutter / 2}px`); + }; + if (horizontalGutter > 0) { + renderGutter('padding-left', horizontalGutter); + renderGutter('padding-right', horizontalGutter); + } + if (verticalGutter > 0) { + renderGutter('padding-top', verticalGutter); + renderGutter('padding-bottom', verticalGutter); + } + }); + } + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/components/grid/demo/flex-align.md b/components/grid/demo/flex-align.md index 62591430862..2dd27203d66 100755 --- a/components/grid/demo/flex-align.md +++ b/components/grid/demo/flex-align.md @@ -1,15 +1,15 @@ --- order: 5 title: - zh-CN: Flex 对齐 - en-US: Flex Alignment + zh-CN: 对齐 + en-US: Alignment --- ## zh-CN -Flex 子元素垂直对齐。 +子元素垂直对齐。 ## en-US -Flex child elements vertically aligned. +Child elements vertically aligned. diff --git a/components/grid/demo/flex-align.ts b/components/grid/demo/flex-align.ts index 98e4f3ee084..a8f83bb42ba 100755 --- a/components/grid/demo/flex-align.ts +++ b/components/grid/demo/flex-align.ts @@ -5,27 +5,34 @@ import { Component } from '@angular/core'; template: `

Align Top

-
+

col-4

col-4

col-4

col-4

Align Center

-
+

col-4

col-4

col-4

col-4

Align Bottom

-
+

col-4

col-4

col-4

col-4

- ` + `, + styles: [ + ` + [nz-row] { + background-color: rgba(128, 128, 128, 0.08); + } + ` + ] }) export class NzDemoGridFlexAlignComponent {} diff --git a/components/grid/demo/flex-order.md b/components/grid/demo/flex-order.md index b1f28ab6bbf..c9f42eb0dfa 100755 --- a/components/grid/demo/flex-order.md +++ b/components/grid/demo/flex-order.md @@ -1,14 +1,14 @@ --- order: 6 title: - zh-CN: Flex 排序 - en-US: Flex Order + zh-CN: 排序 + en-US: Order --- ## zh-CN -通过 Flex 布局的 `nzOrder` 来改变元素的排序。 +通过 `nzOrder` 来改变元素的排序。 ## en-US -To change the element sort by Flex layout `nzOrder`. +To change the element sort by `nzOrder`. diff --git a/components/grid/demo/flex-order.ts b/components/grid/demo/flex-order.ts index 58c88b531c4..69bfb7e9261 100755 --- a/components/grid/demo/flex-order.ts +++ b/components/grid/demo/flex-order.ts @@ -1,19 +1,31 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'nz-demo-grid-flex-order', template: ` -
-
{{ i + 1 }} col-order-{{ order }}
+
+
+
+ 1 col-order-4 +
+
+ 2 col-order-3 +
+
+ 3 col-order-2 +
+
+ 4 col-order-1 +
+
- ` + `, + styles: [ + ` + [nz-row] { + background-color: rgba(128, 128, 128, 0.08); + } + ` + ] }) -export class NzDemoGridFlexOrderComponent implements OnInit { - orderList = [1, 2, 3, 4]; - - ngOnInit(): void { - setTimeout(() => { - this.orderList = [...this.orderList.reverse()]; - }, 10000); - } -} +export class NzDemoGridFlexOrderComponent {} diff --git a/components/grid/demo/flex-stretch.md b/components/grid/demo/flex-stretch.md new file mode 100644 index 00000000000..60cc97e34cd --- /dev/null +++ b/components/grid/demo/flex-stretch.md @@ -0,0 +1,14 @@ +--- +order: 7 +title: + zh-CN: Flex 填充 + en-US: Flex Stretch +--- + +## zh-CN + +`nz-col` 提供 `nzFlex` 属性以支持填充。 + +## en-US + +`nz-col` provides `nzFlex` prop to support fill rest. diff --git a/components/grid/demo/flex-stretch.ts b/components/grid/demo/flex-stretch.ts new file mode 100755 index 00000000000..73b796f706d --- /dev/null +++ b/components/grid/demo/flex-stretch.ts @@ -0,0 +1,32 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'nz-demo-grid-flex-stretch', + template: ` +
+

Percentage columns

+
+
2 / 5
+
3 / 5
+
+

Fill rest

+
+
100px
+
Fill Rest
+
+

Raw flex style

+
+
1 1 200px
+
0 1 300px
+
+
+ `, + styles: [ + ` + [nz-row] { + background-color: rgba(128, 128, 128, 0.08); + } + ` + ] +}) +export class NzDemoGridFlexStretchComponent {} diff --git a/components/grid/demo/flex.md b/components/grid/demo/flex.md index fbb4bb8e205..55831492f95 100755 --- a/components/grid/demo/flex.md +++ b/components/grid/demo/flex.md @@ -1,17 +1,17 @@ --- order: 4 title: - zh-CN: Flex 布局 - en-US: Flex Layout + zh-CN: 排版 + en-US: Layout --- ## zh-CN -Flex 布局基础。 +布局基础。 -使用 `nzType` 定义 `flex` 布局,其子元素根据不同的值 `start`,`center`,`end`,`space-between`,`space-around`,分别定义其在父节点里面的排版方式。 +子元素根据不同的值 `start`,`center`,`end`,`space-between`,`space-around`,分别定义其在父节点里面的排版方式。 ## en-US -Use `nzType` define` flex` layout, its child elements depending on the value of the `start`,` center`, `end`,` space-between`, `space-around`, which are defined in its parent node layout mode. +Child elements depending on the value of the `start`,` center`, `end`,` space-between`, `space-around`, which are defined in its parent node layout mode. diff --git a/components/grid/demo/flex.ts b/components/grid/demo/flex.ts index 78648b80fbc..7ebe910a1ab 100755 --- a/components/grid/demo/flex.ts +++ b/components/grid/demo/flex.ts @@ -5,41 +5,48 @@ import { Component } from '@angular/core'; template: `

sub-element align left

-
+
col-4
col-4
col-4
col-4

sub-element align center

-
+
col-4
col-4
col-4
col-4

sub-element align right

-
+
col-4
col-4
col-4
col-4

sub-element monospaced arrangement

-
+
col-4
col-4
col-4
col-4

sub-element align full

-
+
col-4
col-4
col-4
col-4
- ` + `, + styles: [ + ` + [nz-row] { + background-color: rgba(128, 128, 128, 0.08); + } + ` + ] }) export class NzDemoGridFlexComponent {} diff --git a/components/grid/demo/playground.ts b/components/grid/demo/playground.ts index 83384dd706a..390b7846060 100755 --- a/components/grid/demo/playground.ts +++ b/components/grid/demo/playground.ts @@ -3,20 +3,34 @@ import { Component } from '@angular/core'; @Component({ selector: 'nz-demo-grid-playground', template: ` -
- Gutter (px): -
- +
+ Horizontal Gutter (px): +
+
- Column Count: -
- + Vertical Gutter (px): +
+ +
+ Column Count: +
+
-
-
+
+
+
Column
+
+
Column
@@ -24,6 +38,12 @@ import { Component } from '@angular/core'; `, styles: [ ` + .slider { + width: 50%; + } + .slider-container { + margin-bottom: 16px; + } .grid-config { background: #00a0e9; height: 120px; @@ -34,9 +54,19 @@ import { Component } from '@angular/core'; ] }) export class NzDemoGridPlaygroundComponent { - gutter = 16; + hGutter = 16; + vGutter = 16; count = 4; - marksGutter = { + array = new Array(this.count); + marksHGutter = { + 8: 8, + 16: 16, + 24: 24, + 32: 32, + 40: 40, + 48: 48 + }; + marksVGutter = { 8: 8, 16: 16, 24: 24, @@ -52,8 +82,7 @@ export class NzDemoGridPlaygroundComponent { 8: 8, 12: 12 }; - - generateArray(value: number): number[] { - return new Array(value); + reGenerateArray(count: number): void { + this.array = new Array(count); } } diff --git a/components/grid/doc/index.en-US.md b/components/grid/doc/index.en-US.md index 36840ab72dc..7a7a9f06a17 100755 --- a/components/grid/doc/index.en-US.md +++ b/components/grid/doc/index.en-US.md @@ -58,7 +58,7 @@ title: Grid
-In most business situations, Ant Design needs to solve a lot of information storage problems within the design area, so based on 12 Grids System, we divided the design area into 24 aliquots. +In most business situations, Ant Design needs to solve a lot of information storage problems within the design area, so based on 12 Grids System, we divided the design area into 24 sections. We name the divided area 'box'. We suggest four boxes for horizontal arrangement at most, one at least. Boxes are proportional to the entire screen as shown in the picture above. To ensure a high level of visual comfort, we customize the typography inside of the box based on the box unit. @@ -70,14 +70,12 @@ Following is a brief look at how it works: - Establish a set of `column` in the horizontal space defined by `row` (abbreviated col) - Your content elements should be placed directly in the `col`, and only `col` should be placed directly in `row` -- The column grid system is a value of 1-24 to represent its range spans. For example, three columns of equal width can be created by `.col-8` (`span=8`). +- The column grid system is a value of 1-24 to represent its range spans. For example, three columns of equal width can be created by `
`. - If the sum of `col` spans in a `row` are more than 24, then the overflowing `col` as a whole will start a new line arrangement. -## Flex layout +Our grid systems base on Flex layout to allow the elements within the parent to be aligned horizontally - left, center, right, wide arrangement, and decentralized arrangement. The Grid system also supports vertical alignment - top aligned, vertically centered, bottom-aligned. You can also define the order of elements by using `order`. -Our grid systems support Flex layout to allow the elements within the parent to be aligned horizontally - left, center, right, wide arrangement, and decentralized arrangement. The Grid system also supports vertical alignment - top aligned, vertically centered, bottom-aligned. You can also define the order of elements by using `order`. - -Flex layout uses a 24 grid layout to define the width of each "box", but does not rigidly adhere to the grid layout. +Layout uses a 24 grid layout to define the width of each "box", but does not rigidly adhere to the grid layout. ```ts import { NzGridModule } from 'ng-zorro-antd/grid'; @@ -87,19 +85,19 @@ import { NzGridModule } from 'ng-zorro-antd/grid'; ### [nz-row] -| Property | Description | Type | Default | Global Config | -| -------- | ----------- | ---- | ------- | ------------- | -| `[nzAlign]` | the vertical alignment of the flex layout | `'top'\|'middle'\|'bottom'` | `'top'` | ✅ | -| `[nzGutter]` | spacing between grids, could be a number or a object like `{ xs: 8, sm: 16, md: 24, lg: 32, xl: 32, xxl: 32 }` | `number\|object` | `0` | ✅ | -| `[nzJustify]` | horizontal arrangement of the flex layout | `'start'\|'end'\|'center'\|'space-around'\|'space-between'` | `'start'` | ✅ | -| `[nzType]` | layout mode, optional `flex`, [browser support](http://caniuse.com/#search=flex) | `'flex'` | - | ✅ | +| Property | Description | Type | Default | +| -------- | ----------- | ---- | ------- | +| `[nzAlign]` | the vertical alignment | `'top'\|'middle'\|'bottom'` | - | +| `[nzGutter]` | spacing between grids, could be a number or a object like `{ xs: 8, sm: 16, md: 24}`. or you can use array to make horizontal and vertical spacing work at the same time `[horizontal, vertical]` | `number\|object\|[number, number]\|[object, object]` | `0` | +| `[nzJustify]` | horizontal arrangement | `'start'\|'end'\|'center'\|'space-around'\|'space-between'` | - | ### [nz-col] | Property | Description | Type | Default | | -------- | ----------- | ---- | ------- | +| `[nzFlex]` | flex layout style | `string \| number` | - | | `[nzOffset]` | the number of cells to offset Col from the left | `number` | `0` | -| `[nzOrder]` | raster order, used in `flex` layout mode | `number` | `0` | +| `[nzOrder]` | raster order | `number` | `0` | | `[nzPull]` | the number of cells that raster is moved to the left | `number` | `0` | | `[nzPush]` | the number of cells that raster is moved to the right | `number` | `0` | | `[nzSpan]` | raster number of cells to occupy, 0 corresponds to `display: none` | `number` | - | diff --git a/components/grid/doc/index.zh-CN.md b/components/grid/doc/index.zh-CN.md index 2548b015275..c208b60f649 100755 --- a/components/grid/doc/index.zh-CN.md +++ b/components/grid/doc/index.zh-CN.md @@ -59,7 +59,7 @@ title: Grid
-在多数业务情况下,Ant Design需要在设计区域内解决大量信息收纳的问题,因此在 12 栅格系统的基础上,我们将整个设计建议区域按照 24 等分的原则进行划分。 +在多数业务情况下,Ant Design 需要在设计区域内解决大量信息收纳的问题,因此在 12 栅格系统的基础上,我们将整个设计建议区域按照 24 等分的原则进行划分。 划分之后的信息区块我们称之为『盒子』。建议横向排列的盒子数量最多四个,最少一个。『盒子』在整个屏幕上占比见上图。设计部分基于盒子的单位定制盒子内部的排版规则,以保证视觉层面的舒适感。 @@ -67,16 +67,14 @@ title: Grid 布局的栅格化系统,我们是基于行(row)和列(col)来定义信息区块的外部框架,以保证页面的每个区域能够稳健地排布起来。下面简单介绍一下它的工作原理: -- 通过`row`在水平方向建立一组`column`(简写col) -- 你的内容应当放置于`col`内,并且,只有`col`可以作为`row`的直接元素 -- 栅格系统中的列是指1到24的值来表示其跨越的范围。例如,三个等宽的列可以使用`.col-8`来创建 -- 如果一个`row`中的`col`总和超过 24,那么多余的`col`会作为一个整体另起一行排列 +- 通过 `row` 在水平方向建立一组 `column`(简写 col) +- 你的内容应当放置于 `col` 内,并且,只有 `col` 可以作为 `row` 的直接元素 +- 栅格系统中的列是指 1 到 24 的值来表示其跨越的范围。例如,三个等宽的列可以使用 `
` 来创建 +- 如果一个 `row` 中的 `col` 总和超过 24,那么多余的 `col` 会作为一个整体另起一行排列 -## Flex 布局 +我们的栅格化系统基于 Flex 布局,允许子元素在父节点内的水平对齐方式 - 居左、居中、居右、等宽排列、分散排列。子元素与子元素之间,支持顶部对齐、垂直居中对齐、底部对齐的方式。同时,支持使用 order 来定义元素的排列顺序。 -我们的栅格化系统支持 Flex 布局,允许子元素在父节点内的水平对齐方式 - 居左、居中、居右、等宽排列、分散排列。子元素与子元素之间,支持顶部对齐、垂直居中对齐、底部对齐的方式。同时,支持使用 order 来定义元素的排列顺序。 - -Flex 布局是基于 24 栅格来定义每一个『盒子』的宽度,但排版则不拘泥于栅格。 +布局是基于 24 栅格来定义每一个『盒子』的宽度,但不拘泥于栅格。 ```ts import { NzGridModule } from 'ng-zorro-antd/grid'; @@ -86,21 +84,21 @@ import { NzGridModule } from 'ng-zorro-antd/grid'; ### [nz-row] -| 成员 | 说明 | 类型 | 默认值 | 全局配置 | -| --- | --- | --- | --- | --- | -| `[nzAlign]` | flex 布局下的垂直对齐方式 | `'top' \| 'middle' \| 'bottom'` | `'top'` | ✅ | -| `[nzGutter]` | 栅格间隔,可以写成像素值或支持响应式的对象写法 `{ xs: 8, sm: 16, md: 24, lg: 32, xl: 32, xxl: 32 }` | `number \| object` | `0` | ✅ | -| `[nzJustify]` | flex 布局下的水平排列方式 | `'start' \| 'end' \| 'center' \| 'space-around' \| 'space-between'` | `'start'` | ✅ | -| `[nzType]` | 布局模式,可选 `flex`,[现代浏览器](http://caniuse.com/#search=flex) 下有效 | `'flex'` | - | ✅ | +| 成员 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| `[nzAlign]` | 垂直对齐方式 | `'top' \| 'middle' \| 'bottom'` | - | +| `[nzGutter]` | 栅格间隔,可以写成像素值或支持响应式的对象写法来设置水平间隔 `{ xs: 8, sm: 16, md: 24}`。或者使用数组形式同时设置 `[水平间距, 垂直间距]`。 | `number\|object\|[number, number]\|[object, object]` | - | +| `[nzJustify]` | 水平排列方式 | `'start' \| 'end' \| 'center' \| 'space-around' \| 'space-between'` | - | ### [nz-col] | 成员 | 说明 | 类型 | 默认值 | | --- | --- | --- | --- | -| `[nzOffset]` | 栅格左侧的间隔格数,间隔内不可以有栅格 | `number` | `0` | -| `[nzOrder]` | 栅格顺序,`flex` 布局模式下有效 | `number` | `0` | -| `[nzPull]` | 栅格向左移动格数 | `number` | `0` | -| `[nzPush]` | 栅格向右移动格数 | `number` | `0` | +| `[nzFlex]` | flex 布局属性 | `string \| number` | - | +| `[nzOffset]` | 栅格左侧的间隔格数,间隔内不可以有栅格 | `number` | - | +| `[nzOrder]` | 栅格顺序 | `number` | - | +| `[nzPull]` | 栅格向左移动格数 | `number` | - | +| `[nzPush]` | 栅格向右移动格数 | `number` | - | | `[nzSpan]` | 栅格占位格数,为 0 时相当于 `display: none` | `number` | - | | `[nzXs]` | `<576px` 响应式栅格,可为栅格数或一个包含其他属性的对象 | `number \| object` | - | | `[nzSm]` | `≥576px` 响应式栅格,可为栅格数或一个包含其他属性的对象 | `number \| object` | - | diff --git a/components/grid/nz-grid.module.ts b/components/grid/grid.module.ts similarity index 85% rename from components/grid/nz-grid.module.ts rename to components/grid/grid.module.ts index b0182a0d4e6..52ce772a19c 100644 --- a/components/grid/nz-grid.module.ts +++ b/components/grid/grid.module.ts @@ -11,8 +11,8 @@ import { PlatformModule } from '@angular/cdk/platform'; import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { NzColDirective } from './nz-col.directive'; -import { NzRowDirective } from './nz-row.directive'; +import { NzColDirective } from './col.directive'; +import { NzRowDirective } from './row.directive'; @NgModule({ declarations: [NzColDirective, NzRowDirective], diff --git a/components/grid/grid.spec.ts b/components/grid/grid.spec.ts new file mode 100644 index 00000000000..4a1789ee937 --- /dev/null +++ b/components/grid/grid.spec.ts @@ -0,0 +1,214 @@ +import { Component } from '@angular/core'; +import { fakeAsync, tick } from '@angular/core/testing'; +import { By } from '@angular/platform-browser'; +import { ɵComponentBed as ComponentBed, ɵcreateComponentBed as createComponentBed } from 'ng-zorro-antd/core'; +import { NzColDirective } from './col.directive'; +import { NzGridModule } from './grid.module'; +import { NzRowDirective } from './row.directive'; + +const setWindowWidth = (width: number) => { + viewport.set(width); + window.dispatchEvent(new Event('resize')); + tick(100); +}; + +describe('grid', () => { + describe('row', () => { + let rowElement: HTMLElement; + let colElement: HTMLElement; + let testBed: ComponentBed; + beforeEach(() => { + testBed = createComponentBed(TestGridComponent, { imports: [NzGridModule] }); + rowElement = testBed.debugElement.query(By.directive(NzRowDirective)).nativeElement; + colElement = testBed.debugElement.query(By.directive(NzColDirective)).nativeElement; + }); + it('should apply className', () => { + expect(rowElement.className).toBe('ant-row'); + }); + it('should apply className according to align', () => { + const listOfAlign = ['top', 'middle', 'bottom']; + listOfAlign.forEach(align => { + testBed.component.align = align; + testBed.fixture.detectChanges(); + expect(rowElement.classList).toContain(`ant-row-${align}`); + }); + }); + it('should apply className according to justify', () => { + const listOfJustify = ['start', 'end', 'center', 'space-around', 'space-between']; + listOfJustify.forEach(justify => { + testBed.component.justify = justify; + testBed.fixture.detectChanges(); + expect(rowElement.classList).toContain(`ant-row-${justify}`); + }); + }); + it('should gutter number work', () => { + expect(rowElement.style.cssText).toBe(''); + expect(colElement.style.cssText).toBe(''); + testBed.component.gutter = 16; + testBed.fixture.detectChanges(); + expect(rowElement.style.cssText).toBe('margin-left: -8px; margin-right: -8px;'); + expect(colElement.style.cssText).toBe('padding-left: 8px; padding-right: 8px;'); + }); + it('should gutter number array work', () => { + testBed.component.gutter = [16, 16]; + testBed.fixture.detectChanges(); + expect(rowElement.style.cssText).toBe('margin: -8px;'); + expect(colElement.style.cssText).toBe('padding: 8px;'); + }); + it('should gutter responsive work', fakeAsync(() => { + testBed.component.gutter = { xs: 8, sm: 16, md: 24 }; + setWindowWidth(480); + testBed.fixture.detectChanges(); + expect(rowElement.style.cssText).toBe('margin-left: -4px; margin-right: -4px;'); + expect(colElement.style.cssText).toBe('padding-left: 4px; padding-right: 4px;'); + setWindowWidth(600); + testBed.fixture.detectChanges(); + expect(rowElement.style.cssText).toBe('margin-left: -8px; margin-right: -8px;'); + expect(colElement.style.cssText).toBe('padding-left: 8px; padding-right: 8px;'); + setWindowWidth(800); + testBed.fixture.detectChanges(); + expect(rowElement.style.cssText).toBe('margin-left: -12px; margin-right: -12px;'); + expect(colElement.style.cssText).toBe('padding-left: 12px; padding-right: 12px;'); + })); + it('should gutter responsive array work', fakeAsync(() => { + testBed.component.gutter = [ + { xs: 8, sm: 16, md: 24 }, + { xs: 4, sm: 8, md: 12 } + ]; + setWindowWidth(480); + testBed.fixture.detectChanges(); + expect(rowElement.style.cssText).toBe('margin: -2px -4px;'); + expect(colElement.style.cssText).toBe('padding: 2px 4px;'); + setWindowWidth(600); + testBed.fixture.detectChanges(); + expect(rowElement.style.cssText).toBe('margin: -4px -8px;'); + expect(colElement.style.cssText).toBe('padding: 4px 8px;'); + setWindowWidth(800); + testBed.fixture.detectChanges(); + expect(rowElement.style.cssText).toBe('margin: -6px -12px;'); + expect(colElement.style.cssText).toBe('padding: 6px 12px;'); + })); + }); + describe('col', () => { + let colElement: HTMLElement; + let testBed: ComponentBed; + const sizeMatch = (name: string, count: number, size?: string): boolean => { + const middle = size ? `-${size}-` : '-'; + if (name === 'span') { + return colElement.classList.contains(`ant-col${middle}${count}`); + } else { + return colElement.classList.contains(`ant-col${middle}${name}-${count}`); + } + }; + beforeEach(() => { + testBed = createComponentBed(TestColComponent, { imports: [NzGridModule] }); + colElement = testBed.debugElement.query(By.directive(NzColDirective)).nativeElement; + }); + it('should apply className', () => { + expect(colElement.className).toBe('ant-col'); + }); + it('should apply style according to flex', () => { + testBed.component.flex = 1; + testBed.fixture.detectChanges(); + expect(colElement.style.cssText).toBe('flex: 1 1 auto;'); + testBed.component.flex = '100px'; + testBed.fixture.detectChanges(); + expect(colElement.style.cssText).toBe('flex: 0 0 100px;'); + }); + it('should apply className according to property', () => { + const propertySizeMatch = (name: keyof TestColComponent, count: number): boolean => { + testBed.component[name] = count; + testBed.fixture.detectChanges(); + return sizeMatch(name, count); + }; + expect(propertySizeMatch('span', 8)).toBe(true); + expect(propertySizeMatch('offset', 8)).toBe(true); + expect(propertySizeMatch('order', 8)).toBe(true); + expect(propertySizeMatch('pull', 8)).toBe(true); + expect(propertySizeMatch('push', 8)).toBe(true); + expect(propertySizeMatch('xs', 8)).toBe(true); + expect(propertySizeMatch('sm', 8)).toBe(true); + expect(propertySizeMatch('md', 8)).toBe(true); + expect(propertySizeMatch('lg', 8)).toBe(true); + expect(propertySizeMatch('xl', 8)).toBe(true); + expect(propertySizeMatch('xxl', 8)).toBe(true); + }); + it('should apply className according to responsive size object', () => { + const batchSizeMatch = (count: number, size: string): boolean => { + return ( + sizeMatch('span', count, size) && + sizeMatch('offset', count, size) && + sizeMatch('order', count, size) && + sizeMatch('pull', count, size) && + sizeMatch('push', count, size) + ); + }; + testBed.component.xs = { span: 1, offset: 1, order: 1, pull: 1, push: 1 }; + testBed.component.sm = { span: 2, offset: 2, order: 2, pull: 2, push: 2 }; + testBed.component.md = { span: 3, offset: 3, order: 3, pull: 3, push: 3 }; + testBed.component.lg = { span: 4, offset: 4, order: 4, pull: 4, push: 4 }; + testBed.component.xl = { span: 5, offset: 5, order: 5, pull: 5, push: 5 }; + testBed.component.xxl = { span: 6, offset: 6, order: 6, pull: 6, push: 6 }; + testBed.fixture.detectChanges(); + expect(batchSizeMatch(1, 'xs')).toBe(true); + expect(batchSizeMatch(2, 'sm')).toBe(true); + expect(batchSizeMatch(3, 'md')).toBe(true); + expect(batchSizeMatch(4, 'lg')).toBe(true); + expect(batchSizeMatch(5, 'xl')).toBe(true); + expect(batchSizeMatch(6, 'xxl')).toBe(true); + testBed.component.xs = { span: 2, offset: 2, order: 2, pull: 2, push: 2 }; + testBed.fixture.detectChanges(); + expect(batchSizeMatch(1, 'xs')).toBe(false); + }); + }); +}); + +@Component({ + template: ` +
+
+
+ ` +}) +export class TestGridComponent { + gutter: number | null | [number, number] | { [key: string]: number } | [{ [key: string]: number }, { [key: string]: number }] = null; + flex: string | null = null; + justify: string | null = null; + align: string | null = null; +} + +@Component({ + template: ` +
+
+
+ ` +}) +export class TestColComponent { + span: number | null = null; + flex: string | null | number = null; + offset: number | null = null; + order: number | null = null; + pull: number | null = null; + push: number | null = null; + xs: number | null | { [key: string]: number } = null; + sm: number | null | { [key: string]: number } = null; + md: number | null | { [key: string]: number } = null; + lg: number | null | { [key: string]: number } = null; + xl: number | null | { [key: string]: number } = null; + xxl: number | null | { [key: string]: number } = null; +} diff --git a/components/grid/nz-col.directive.ts b/components/grid/nz-col.directive.ts deleted file mode 100644 index 9909449b438..00000000000 --- a/components/grid/nz-col.directive.ts +++ /dev/null @@ -1,110 +0,0 @@ -/** - * @license - * Copyright Alibaba.com All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE - */ - -import { AfterViewInit, Directive, ElementRef, Host, Input, OnChanges, OnDestroy, OnInit, Optional, Renderer2 } from '@angular/core'; -import { isNotNil, NgClassInterface, NzUpdateHostClassService } from 'ng-zorro-antd/core'; -import { Subject } from 'rxjs'; -import { startWith, takeUntil } from 'rxjs/operators'; -import { NzRowDirective } from './nz-row.directive'; - -export interface EmbeddedProperty { - span?: number; - pull?: number; - push?: number; - offset?: number; - order?: number; -} - -@Directive({ - selector: '[nz-col],nz-col', - exportAs: 'nzCol', - providers: [NzUpdateHostClassService] -}) -export class NzColDirective implements OnInit, OnChanges, AfterViewInit, OnDestroy { - private el: HTMLElement = this.elementRef.nativeElement; - private prefixCls = 'ant-col'; - protected destroy$ = new Subject(); - - @Input() nzSpan: number; - @Input() nzOrder: number; - @Input() nzOffset: number; - @Input() nzPush: number; - @Input() nzPull: number; - @Input() nzXs: number | EmbeddedProperty; - @Input() nzSm: number | EmbeddedProperty; - @Input() nzMd: number | EmbeddedProperty; - @Input() nzLg: number | EmbeddedProperty; - @Input() nzXl: number | EmbeddedProperty; - @Input() nzXXl: number | EmbeddedProperty; - - /** temp solution since no method add classMap to host https://github.com/angular/angular/issues/7289*/ - setClassMap(): void { - const classMap = { - [`${this.prefixCls}`]: true, - [`${this.prefixCls}-${this.nzSpan}`]: isNotNil(this.nzSpan), - [`${this.prefixCls}-order-${this.nzOrder}`]: isNotNil(this.nzOrder), - [`${this.prefixCls}-offset-${this.nzOffset}`]: isNotNil(this.nzOffset), - [`${this.prefixCls}-pull-${this.nzPull}`]: isNotNil(this.nzPull), - [`${this.prefixCls}-push-${this.nzPush}`]: isNotNil(this.nzPush), - ...this.generateClass() - }; - this.nzUpdateHostClassService.updateHostClass(this.el, classMap); - } - - generateClass(): object { - const listOfSizeInputName: Array = ['nzXs', 'nzSm', 'nzMd', 'nzLg', 'nzXl', 'nzXXl']; - const listClassMap: NgClassInterface = {}; - listOfSizeInputName.forEach(name => { - const sizeName = name.replace('nz', '').toLowerCase(); - if (isNotNil(this[name])) { - if (typeof this[name] === 'number' || typeof this[name] === 'string') { - listClassMap[`${this.prefixCls}-${sizeName}-${this[name]}`] = true; - } else { - const embedded = this[name] as EmbeddedProperty; - const prefixArray: Array = ['span', 'pull', 'push', 'offset', 'order']; - prefixArray.forEach(prefix => { - const prefixClass = prefix === 'span' ? '-' : `-${prefix}-`; - listClassMap[`${this.prefixCls}-${sizeName}${prefixClass}${embedded[prefix]}`] = embedded && isNotNil(embedded[prefix]); - }); - } - } - }); - return listClassMap; - } - - constructor( - private nzUpdateHostClassService: NzUpdateHostClassService, - private elementRef: ElementRef, - @Optional() @Host() public nzRowDirective: NzRowDirective, - public renderer: Renderer2 - ) {} - - ngOnChanges(): void { - this.setClassMap(); - } - - ngAfterViewInit(): void { - if (this.nzRowDirective) { - this.nzRowDirective.actualGutter$ - .pipe(startWith(this.nzRowDirective.actualGutter), takeUntil(this.destroy$)) - .subscribe(actualGutter => { - this.renderer.setStyle(this.el, 'padding-left', `${actualGutter / 2}px`); - this.renderer.setStyle(this.el, 'padding-right', `${actualGutter / 2}px`); - }); - } - } - - ngOnInit(): void { - this.setClassMap(); - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } -} diff --git a/components/grid/nz-grid.spec.ts b/components/grid/nz-grid.spec.ts deleted file mode 100644 index 5c7f7be8cc8..00000000000 --- a/components/grid/nz-grid.spec.ts +++ /dev/null @@ -1,335 +0,0 @@ -import { DebugElement, NO_ERRORS_SCHEMA } from '@angular/core'; -import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; - -import { NzDemoGridBasicComponent } from './demo/basic'; -import { NzDemoGridFlexComponent } from './demo/flex'; -import { NzDemoGridFlexAlignComponent } from './demo/flex-align'; -import { NzDemoGridFlexOrderComponent } from './demo/flex-order'; -import { NzDemoGridGutterComponent } from './demo/gutter'; -import { NzDemoGridOffsetComponent } from './demo/offset'; -import { NzDemoGridPlaygroundComponent } from './demo/playground'; -import { NzDemoGridResponsiveComponent } from './demo/responsive'; -import { NzDemoGridResponsiveMoreComponent } from './demo/responsive-more'; -import { NzDemoGridSortComponent } from './demo/sort'; -import { NzColDirective } from './nz-col.directive'; -import { NzGridModule } from './nz-grid.module'; -import { NzRowDirective } from './nz-row.directive'; - -// tslint:disable-next-line no-any -declare const viewport: any; - -describe('grid', () => { - describe('basic', () => { - let fixture: ComponentFixture; - let rows: DebugElement[]; - let cols: DebugElement[]; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NzGridModule], - declarations: [NzDemoGridBasicComponent], - providers: [] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoGridBasicComponent); - rows = fixture.debugElement.queryAll(By.directive(NzRowDirective)); - cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - }); - - it('should have correct style', () => { - fixture.detectChanges(); - expect(rows.every(row => row.nativeElement.classList.contains('ant-row'))).toBe(true); - expect(cols[0].nativeElement.classList.contains('ant-col-12')).toBe(true); - expect(cols[1].nativeElement.classList.contains('ant-col-12')).toBe(true); - expect(cols[2].nativeElement.classList.contains('ant-col-8')).toBe(true); - expect(cols[3].nativeElement.classList.contains('ant-col-8')).toBe(true); - expect(cols[4].nativeElement.classList.contains('ant-col-8')).toBe(true); - expect(cols[5].nativeElement.classList.contains('ant-col-6')).toBe(true); - expect(cols[6].nativeElement.classList.contains('ant-col-6')).toBe(true); - expect(cols[7].nativeElement.classList.contains('ant-col-6')).toBe(true); - expect(cols[8].nativeElement.classList.contains('ant-col-6')).toBe(true); - }); - }); - describe('flex', () => { - let fixture: ComponentFixture; - let rows: DebugElement[]; - let cols: DebugElement[]; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NzGridModule], - declarations: [NzDemoGridFlexComponent], - providers: [] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoGridFlexComponent); - rows = fixture.debugElement.queryAll(By.directive(NzRowDirective)); - cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - }); - - it('should have correct style', () => { - fixture.detectChanges(); - expect(rows[0].nativeElement.className).toBe('ant-row-flex ant-row-flex-top ant-row-flex-start'); - expect(rows[1].nativeElement.className).toBe('ant-row-flex ant-row-flex-top ant-row-flex-center'); - expect(rows[2].nativeElement.className).toBe('ant-row-flex ant-row-flex-top ant-row-flex-end'); - expect(rows[3].nativeElement.className).toBe('ant-row-flex ant-row-flex-top ant-row-flex-space-between'); - expect(rows[4].nativeElement.className).toBe('ant-row-flex ant-row-flex-top ant-row-flex-space-around'); - expect(cols.every(col => col.nativeElement.classList.contains('ant-col-4'))).toBe(true); - }); - }); - - describe('flex-align', () => { - let fixture: ComponentFixture; - let rows: DebugElement[]; - let cols: DebugElement[]; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NzGridModule], - declarations: [NzDemoGridFlexAlignComponent], - providers: [] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoGridFlexAlignComponent); - rows = fixture.debugElement.queryAll(By.directive(NzRowDirective)); - cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - }); - - it('should have correct style', () => { - fixture.detectChanges(); - expect(rows[0].nativeElement.className).toBe('ant-row-flex ant-row-flex-top ant-row-flex-center'); - expect(rows[1].nativeElement.className).toBe('ant-row-flex ant-row-flex-middle ant-row-flex-space-around'); - expect(rows[2].nativeElement.className).toBe('ant-row-flex ant-row-flex-bottom ant-row-flex-space-between'); - expect(cols.every(col => col.nativeElement.classList.contains('ant-col-4'))).toBe(true); - }); - }); - - describe('flex-order', () => { - let fixture: ComponentFixture; - let row: DebugElement; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NzGridModule], - declarations: [NzDemoGridFlexOrderComponent], - providers: [] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoGridFlexOrderComponent); - row = fixture.debugElement.query(By.directive(NzRowDirective)); - }); - - it('should have update order correctly', fakeAsync(() => { - fixture.detectChanges(); - let cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - expect(row.nativeElement.className).toBe('ant-row-flex ant-row-flex-top ant-row-flex-start'); - expect(cols[0].nativeElement.classList.contains('ant-col-order-1')).toBe(true); - expect(cols[1].nativeElement.classList.contains('ant-col-order-2')).toBe(true); - expect(cols[2].nativeElement.classList.contains('ant-col-order-3')).toBe(true); - expect(cols[3].nativeElement.classList.contains('ant-col-order-4')).toBe(true); - tick(10000); - fixture.detectChanges(); - cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - expect(row.nativeElement.className).toBe('ant-row-flex ant-row-flex-top ant-row-flex-start'); - expect(cols[0].nativeElement.classList.contains('ant-col-order-4')).toBe(true); - expect(cols[1].nativeElement.classList.contains('ant-col-order-3')).toBe(true); - expect(cols[2].nativeElement.classList.contains('ant-col-order-2')).toBe(true); - expect(cols[3].nativeElement.classList.contains('ant-col-order-1')).toBe(true); - })); - }); - - describe('gutter', () => { - let fixture: ComponentFixture; - let rows: DebugElement[]; - let cols: DebugElement[]; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NzGridModule], - declarations: [NzDemoGridGutterComponent], - providers: [] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoGridGutterComponent); - rows = fixture.debugElement.queryAll(By.directive(NzRowDirective)); - cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - }); - - it('should number work', () => { - fixture.detectChanges(); - expect(rows[0].nativeElement.style.cssText).toBe('margin-left: -8px; margin-right: -8px;'); - expect(cols.slice(0, 4).every(col => col.nativeElement.style.cssText === 'padding-left: 8px; padding-right: 8px;')).toBe(true); - expect(cols.slice(0, 4).every(col => col.nativeElement.classList.contains('gutter-row'))).toBe(true); - }); - - it('should responsive work', fakeAsync(() => { - viewport.set(1000, 1000); - window.dispatchEvent(new Event('resize')); - fixture.detectChanges(); - tick(100); - fixture.detectChanges(); - - expect(rows[1].nativeElement.style.cssText).toBe('margin-left: -16px; margin-right: -16px;'); - expect(cols.slice(4, 8).every(col => col.nativeElement.style.cssText === 'padding-left: 16px; padding-right: 16px;')).toBe(true); - expect(cols.slice(4, 8).every(col => col.nativeElement.classList.contains('gutter-row'))).toBe(true); - - viewport.set(480, 480); - window.dispatchEvent(new Event('resize')); - fixture.detectChanges(); - tick(100); - fixture.detectChanges(); - expect(rows[1].nativeElement.style.cssText).toBe('margin-left: -4px; margin-right: -4px;'); - expect(cols.slice(4, 8).every(col => col.nativeElement.style.cssText === 'padding-left: 4px; padding-right: 4px;')).toBe(true); - expect(cols.slice(4, 8).every(col => col.nativeElement.classList.contains('gutter-row'))).toBe(true); - - viewport.reset(); - })); - }); - - describe('offset', () => { - let fixture: ComponentFixture; - let rows: DebugElement[]; - let cols: DebugElement[]; - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NzGridModule], - declarations: [NzDemoGridOffsetComponent], - providers: [] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoGridOffsetComponent); - rows = fixture.debugElement.queryAll(By.directive(NzRowDirective)); - cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - }); - it('should have correct style', () => { - fixture.detectChanges(); - expect(rows.every(row => row.nativeElement.classList.contains('ant-row'))).toBe(true); - expect(cols[0].nativeElement.className).toBe('ant-col ant-col-8'); - expect(cols[1].nativeElement.className).toBe('ant-col ant-col-8 ant-col-offset-8'); - expect(cols[2].nativeElement.className).toBe('ant-col ant-col-6 ant-col-offset-6'); - expect(cols[3].nativeElement.className).toBe('ant-col ant-col-6 ant-col-offset-6'); - expect(cols[4].nativeElement.className).toBe('ant-col ant-col-12 ant-col-offset-6'); - }); - }); - - describe('responsive', () => { - let fixture: ComponentFixture; - let cols: DebugElement[]; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NzGridModule], - declarations: [NzDemoGridResponsiveComponent], - providers: [] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoGridResponsiveComponent); - cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - }); - - it('should have correct style', () => { - fixture.detectChanges(); - expect(cols[0].nativeElement.className).toBe('ant-col ant-col-xs-2 ant-col-sm-4 ant-col-md-6 ant-col-lg-8 ant-col-xl-10'); - expect(cols[1].nativeElement.className).toBe('ant-col ant-col-xs-20 ant-col-sm-16 ant-col-md-12 ant-col-lg-8 ant-col-xl-4'); - expect(cols[2].nativeElement.className).toBe('ant-col ant-col-xs-2 ant-col-sm-4 ant-col-md-6 ant-col-lg-8 ant-col-xl-10'); - }); - }); - - describe('responsive-more', () => { - let fixture: ComponentFixture; - let cols: DebugElement[]; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NzGridModule], - declarations: [NzDemoGridResponsiveMoreComponent], - providers: [] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoGridResponsiveMoreComponent); - cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - }); - it('should have correct style', () => { - fixture.detectChanges(); - expect(cols[0].nativeElement.className).toBe('ant-col ant-col-xs-5 ant-col-xs-offset-1 ant-col-lg-6 ant-col-lg-offset-2'); - expect(cols[1].nativeElement.className).toBe('ant-col ant-col-xs-11 ant-col-xs-offset-1 ant-col-lg-6 ant-col-lg-offset-2'); - expect(cols[2].nativeElement.className).toBe('ant-col ant-col-xs-5 ant-col-xs-offset-1 ant-col-lg-6 ant-col-lg-offset-2'); - }); - }); - - describe('sort', () => { - let fixture: ComponentFixture; - let cols: DebugElement[]; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NzGridModule], - declarations: [NzDemoGridSortComponent], - providers: [] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoGridSortComponent); - cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - }); - - it('should have correct style', () => { - fixture.detectChanges(); - expect(cols[0].nativeElement.className).toBe('ant-col ant-col-18 ant-col-push-6'); - expect(cols[1].nativeElement.className).toBe('ant-col ant-col-6 ant-col-pull-18'); - }); - }); - - describe('playground', () => { - let fixture: ComponentFixture; - let testComponent: NzDemoGridPlaygroundComponent; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [NzGridModule], - declarations: [NzDemoGridPlaygroundComponent], - providers: [], - schemas: [NO_ERRORS_SCHEMA] - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(NzDemoGridPlaygroundComponent); - testComponent = fixture.debugElement.componentInstance; - }); - - it('should update gutter and count correctly', () => { - fixture.detectChanges(); - const row = fixture.debugElement.query(By.directive(NzRowDirective)); - let cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - expect(cols.length).toBe(4); - expect(cols.every(col => col.nativeElement.style.cssText === 'padding-left: 8px; padding-right: 8px;')).toBe(true); - expect(row.nativeElement.style.cssText).toBe('margin-left: -8px; margin-right: -8px;'); - testComponent.gutter = 24; - testComponent.count = 12; - fixture.detectChanges(); - cols = fixture.debugElement.queryAll(By.directive(NzColDirective)); - expect(cols.length).toBe(12); - expect(cols.every(col => col.nativeElement.style.cssText === 'padding-left: 12px; padding-right: 12px;')).toBe(true); - expect(row.nativeElement.style.cssText).toBe('margin-left: -12px; margin-right: -12px;'); - }); - }); -}); diff --git a/components/grid/nz-row.directive.ts b/components/grid/nz-row.directive.ts deleted file mode 100644 index 0d41b031d9e..00000000000 --- a/components/grid/nz-row.directive.ts +++ /dev/null @@ -1,119 +0,0 @@ -/** - * @license - * Copyright Alibaba.com All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE - */ - -import { AfterViewInit, Directive, ElementRef, Input, NgZone, OnChanges, OnDestroy, OnInit, Renderer2, SimpleChanges } from '@angular/core'; - -import { MediaMatcher } from '@angular/cdk/layout'; -import { Platform } from '@angular/cdk/platform'; -import { IndexableObject, NzAlignType, NzBreakPoint, NzDomEventService, NzUpdateHostClassService, responsiveMap } from 'ng-zorro-antd/core'; -import { Subject } from 'rxjs'; -import { finalize, takeUntil } from 'rxjs/operators'; - -export type NzJustify = 'start' | 'end' | 'center' | 'space-around' | 'space-between'; -export type NzGridType = 'flex' | null; - -@Directive({ - selector: '[nz-row],nz-row', - exportAs: 'nzRow', - providers: [NzUpdateHostClassService] -}) -export class NzRowDirective implements OnInit, OnChanges, AfterViewInit, OnDestroy { - @Input() nzType: NzGridType; - @Input() nzAlign: NzAlignType = 'top'; - @Input() nzJustify: NzJustify = 'start'; - @Input() nzGutter: number | IndexableObject; - private el: HTMLElement = this.elementRef.nativeElement; - private prefixCls = 'ant-row'; - private breakPoint: NzBreakPoint; - actualGutter: number; - actualGutter$ = new Subject(); - destroy$ = new Subject(); - - calculateGutter(): number { - if (typeof this.nzGutter !== 'object') { - return this.nzGutter; - } else if (this.breakPoint && this.nzGutter[this.breakPoint]) { - return this.nzGutter[this.breakPoint]; - } else { - return 0; - } - } - - updateGutter(): void { - const actualGutter = this.calculateGutter(); - if (this.actualGutter !== actualGutter) { - this.actualGutter = actualGutter; - this.actualGutter$.next(this.actualGutter); - this.renderer.setStyle(this.el, 'margin-left', `-${this.actualGutter / 2}px`); - this.renderer.setStyle(this.el, 'margin-right', `-${this.actualGutter / 2}px`); - } - } - - watchMedia(): void { - Object.keys(responsiveMap).map((screen: string) => { - const castBP = screen as NzBreakPoint; - const matchBelow = this.mediaMatcher.matchMedia(responsiveMap[castBP]).matches; - if (matchBelow) { - this.breakPoint = castBP; - } - }); - this.updateGutter(); - } - - /** temp solution since no method add classMap to host https://github.com/angular/angular/issues/7289*/ - setClassMap(): void { - const classMap = { - [`${this.prefixCls}`]: !this.nzType, - [`${this.prefixCls}-${this.nzType}`]: this.nzType, - [`${this.prefixCls}-${this.nzType}-${this.nzAlign}`]: this.nzType && this.nzAlign, - [`${this.prefixCls}-${this.nzType}-${this.nzJustify}`]: this.nzType && this.nzJustify - }; - this.nzUpdateHostClassService.updateHostClass(this.el, classMap); - } - - constructor( - public elementRef: ElementRef, - public renderer: Renderer2, - public nzUpdateHostClassService: NzUpdateHostClassService, - public mediaMatcher: MediaMatcher, - public ngZone: NgZone, - public platform: Platform, - private nzDomEventService: NzDomEventService - ) {} - - ngOnInit(): void { - this.setClassMap(); - this.watchMedia(); - } - - ngOnChanges(changes: SimpleChanges): void { - if (changes.nzType || changes.nzAlign || changes.nzJustify) { - this.setClassMap(); - } - if (changes.nzGutter) { - this.updateGutter(); - } - } - - ngAfterViewInit(): void { - if (this.platform.isBrowser) { - this.nzDomEventService - .registerResizeListener() - .pipe( - takeUntil(this.destroy$), - finalize(() => this.nzDomEventService.unregisterResizeListener()) - ) - .subscribe(() => this.watchMedia()); - } - } - - ngOnDestroy(): void { - this.destroy$.next(); - this.destroy$.complete(); - } -} diff --git a/components/grid/public-api.ts b/components/grid/public-api.ts index be5015a7616..e54adcff003 100644 --- a/components/grid/public-api.ts +++ b/components/grid/public-api.ts @@ -6,6 +6,6 @@ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE */ -export * from './nz-row.directive'; -export * from './nz-col.directive'; -export * from './nz-grid.module'; +export * from './row.directive'; +export * from './col.directive'; +export * from './grid.module'; diff --git a/components/grid/row.directive.ts b/components/grid/row.directive.ts new file mode 100644 index 00000000000..5e25faee330 --- /dev/null +++ b/components/grid/row.directive.ts @@ -0,0 +1,127 @@ +/** + * @license + * Copyright Alibaba.com All Rights Reserved. + * + * Use of this source code is governed by an MIT-style license that can be + * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE + */ + +import { MediaMatcher } from '@angular/cdk/layout'; +import { Platform } from '@angular/cdk/platform'; +import { AfterViewInit, Directive, ElementRef, Input, NgZone, OnChanges, OnDestroy, OnInit, Renderer2, SimpleChanges } from '@angular/core'; +import { IndexableObject, NzBreakpointKey, NzDomEventService, responsiveMap } from 'ng-zorro-antd/core'; +import { ReplaySubject, Subject } from 'rxjs'; +import { finalize, takeUntil } from 'rxjs/operators'; + +export type NzJustify = 'start' | 'end' | 'center' | 'space-around' | 'space-between'; +export type NzAlign = 'top' | 'middle' | 'bottom'; + +@Directive({ + selector: '[nz-row],nz-row,nz-form-item', + exportAs: 'nzRow', + host: { '[class]': 'hostClassMap' } +}) +export class NzRowDirective implements OnInit, OnChanges, AfterViewInit, OnDestroy { + /** + * @deprecated don't need nzType="flex" after 9.0 + */ + @Input() nzType: 'flex' | null; + @Input() nzAlign: NzAlign | null = null; + @Input() nzJustify: NzJustify | null = null; + @Input() nzGutter: number | IndexableObject | [number, number] | [IndexableObject, IndexableObject] | null = null; + actualGutter$ = new ReplaySubject<[number, number]>(1); + destroy$ = new Subject(); + hostClassMap: IndexableObject = {}; + + getGutter(breakPoint: NzBreakpointKey): [number, number] { + const results: [number, number] = [0, 0]; + const gutter = this.nzGutter || 0; + const normalizedGutter = Array.isArray(gutter) ? gutter : [gutter, 0]; + normalizedGutter.forEach((g, index) => { + if (typeof g === 'object') { + results[index] = (g![breakPoint] as number) || 0; + } else { + results[index] = g || 0; + } + }); + return results; + } + + setGutterStyle(): void { + let breakPoint: NzBreakpointKey | null = null; + Object.keys(responsiveMap).map((screen: string) => { + const bp = screen as NzBreakpointKey; + if (this.mediaMatcher.matchMedia(responsiveMap[bp]).matches) { + breakPoint = bp; + } + }); + const [horizontalGutter, verticalGutter] = this.getGutter(breakPoint!); + this.actualGutter$.next([horizontalGutter, verticalGutter]); + const renderGutter = (name: string, gutter: number) => { + const nativeElement = this.elementRef.nativeElement; + this.renderer.setStyle(nativeElement, name, `-${gutter / 2}px`); + }; + if (horizontalGutter > 0) { + renderGutter('margin-left', horizontalGutter); + renderGutter('margin-right', horizontalGutter); + } + if (verticalGutter > 0) { + renderGutter('margin-top', verticalGutter); + renderGutter('margin-bottom', verticalGutter); + } + } + + setHostClassMap(): void { + this.hostClassMap = { + ['ant-row']: true, + ['ant-row-top']: this.nzAlign === 'top', + ['ant-row-middle']: this.nzAlign === 'middle', + ['ant-row-bottom']: this.nzAlign === 'bottom', + ['ant-row-start']: this.nzJustify === 'start', + ['ant-row-end']: this.nzJustify === 'end', + ['ant-row-center']: this.nzJustify === 'center', + ['ant-row-space-around']: this.nzJustify === 'space-around', + ['ant-row-space-between']: this.nzJustify === 'space-between' + }; + } + + constructor( + public elementRef: ElementRef, + public renderer: Renderer2, + public mediaMatcher: MediaMatcher, + public ngZone: NgZone, + public platform: Platform, + private nzDomEventService: NzDomEventService + ) {} + + ngOnInit(): void { + this.setHostClassMap(); + this.setGutterStyle(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.nzType || changes.nzAlign || changes.nzJustify) { + this.setHostClassMap(); + } + if (changes.nzGutter) { + this.setGutterStyle(); + } + } + + ngAfterViewInit(): void { + if (this.platform.isBrowser) { + this.nzDomEventService + .registerResizeListener() + .pipe( + takeUntil(this.destroy$), + finalize(() => this.nzDomEventService.unregisterResizeListener()) + ) + .subscribe(() => this.setGutterStyle()); + } + } + + ngOnDestroy(): void { + this.destroy$.next(); + this.destroy$.complete(); + } +} diff --git a/components/layout/nz-sider.component.ts b/components/layout/nz-sider.component.ts index a2f03157bab..576ac432220 100644 --- a/components/layout/nz-sider.component.ts +++ b/components/layout/nz-sider.component.ts @@ -6,6 +6,8 @@ * found in the LICENSE file at https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/LICENSE */ +import { MediaMatcher } from '@angular/cdk/layout'; +import { Platform } from '@angular/cdk/platform'; import { AfterViewInit, ChangeDetectionStrategy, @@ -26,13 +28,10 @@ import { ViewEncapsulation } from '@angular/core'; -import { MediaMatcher } from '@angular/cdk/layout'; -import { Platform } from '@angular/cdk/platform'; +import { InputBoolean, NzBreakpointKey, NzDomEventService, toCssPixel } from 'ng-zorro-antd/core'; import { Subject } from 'rxjs'; import { finalize, takeUntil } from 'rxjs/operators'; -import { InputBoolean, NzBreakPoint, NzDomEventService, toCssPixel } from 'ng-zorro-antd/core'; - import { NzLayoutComponent } from './nz-layout.component'; @Component({ @@ -69,7 +68,7 @@ export class NzSiderComponent implements OnInit, AfterViewInit, OnDestroy { @Input() nzWidth: string | number = 200; @Input() nzTheme: 'light' | 'dark' = 'dark'; @Input() nzCollapsedWidth = 80; - @Input() nzBreakpoint: NzBreakPoint; + @Input() nzBreakpoint: NzBreakpointKey; @Input() nzZeroTrigger: TemplateRef; @Input() @InputBoolean() nzReverseArrow = false; @Input() @InputBoolean() nzCollapsible = false; diff --git a/components/tsconfig.spec.json b/components/tsconfig.spec.json index a123693049a..3b827070c9c 100644 --- a/components/tsconfig.spec.json +++ b/components/tsconfig.spec.json @@ -13,6 +13,7 @@ "include": [ "**/*.spec.ts", "**/*.d.ts", - "../node_modules/@types/jasmine/index.d.ts" + "../node_modules/@types/jasmine/index.d.ts", + "../node_modules/karma-viewport/dist/index.d.ts" ] }