diff --git a/components/button/demo/basic.ts b/components/button/demo/basic.ts
index 71347a31618..00d9a4f743d 100644
--- a/components/button/demo/basic.ts
+++ b/components/button/demo/basic.ts
@@ -7,6 +7,7 @@ import { Component } from '@angular/core';
+
`,
styles: [
`
diff --git a/components/button/demo/block.ts b/components/button/demo/block.ts
index edc33da7993..e185dae8c75 100644
--- a/components/button/demo/block.ts
+++ b/components/button/demo/block.ts
@@ -7,6 +7,7 @@ import { Component } from '@angular/core';
+
`,
styles: [
`
diff --git a/components/button/demo/disabled.ts b/components/button/demo/disabled.ts
index 35751830d5a..5c9f45b0f8f 100644
--- a/components/button/demo/disabled.ts
+++ b/components/button/demo/disabled.ts
@@ -11,6 +11,9 @@ import { Component } from '@angular/core';
+
+
+
diff --git a/components/button/demo/ghost.ts b/components/button/demo/ghost.ts
index cccaa5120f8..8a804a748c0 100644
--- a/components/button/demo/ghost.ts
+++ b/components/button/demo/ghost.ts
@@ -8,6 +8,7 @@ import { Component } from '@angular/core';
+
`,
styles: [
diff --git a/components/button/demo/size.ts b/components/button/demo/size.ts
index 6fc47ee6867..c685095542e 100644
--- a/components/button/demo/size.ts
+++ b/components/button/demo/size.ts
@@ -14,6 +14,7 @@ import { Component } from '@angular/core';
+
diff --git a/components/button/doc/index.en-US.md b/components/button/doc/index.en-US.md
index e816e47475b..1cac8365add 100644
--- a/components/button/doc/index.en-US.md
+++ b/components/button/doc/index.en-US.md
@@ -30,5 +30,5 @@ To get a customized button, just set `nzType`/`nzShape`/`nzSize`/`nzLoading`/`di
| `[nzLoading]` | set the loading status of button | `boolean` | `false` |
| `[nzShape]` | can be set to `circle` `round` or omitted | `'circle'|'round'` | - |
| `[nzSize]` | can be set to `small` `large` or omitted | `'large'|'small'|'default'` | `'default'` |
-| `[nzType]` | can be set to `primary` `dashed` `danger` or omitted (meaning `default`) | `'primary'|'dashed'|'danger'|'default'` | `'default'` |
+| `[nzType]` | can be set to `primary` `dashed` `danger` or omitted (meaning `default`) | `'primary'|'dashed'|'danger'|'default'|'link'` | `'default'` |
| `[nzBlock]` | option to fit button width to its parent width | `boolean` | `false` |
diff --git a/components/button/doc/index.zh-CN.md b/components/button/doc/index.zh-CN.md
index fedf532f9b9..8fade534be5 100644
--- a/components/button/doc/index.zh-CN.md
+++ b/components/button/doc/index.zh-CN.md
@@ -34,5 +34,5 @@ import { NzButtonModule } from 'ng-zorro-antd';
| `[nzLoading]` | 设置按钮载入状态 | `boolean` | `false` |
| `[nzShape]` | 设置按钮形状,可选值为 `circle` `round` 或者不设 | `'circle'|'round'` | - |
| `[nzSize]` | 设置按钮大小,可选值为 `small` `large` 或者不设 | `'large'|'small'|'default'` | `'default'` |
-| `[nzType]` | 设置按钮类型,可选值为 `primary` `dashed` `danger` 或者不设 | `'primary'|'dashed'|'danger'|'default'` | `'default'` |
+| `[nzType]` | 设置按钮类型,可选值为 `primary` `dashed` `danger` 或者不设 | `'primary'|'dashed'|'danger'|'default'|'link'` | `'default'` |
| `[nzBlock]` | 将按钮宽度调整为其父宽度的选项 | `boolean` | `false` |
diff --git a/components/button/nz-button.component.ts b/components/button/nz-button.component.ts
index a1d113c07db..62ede32067f 100644
--- a/components/button/nz-button.component.ts
+++ b/components/button/nz-button.component.ts
@@ -43,7 +43,7 @@ import {
} from 'ng-zorro-antd/core';
import { NzIconDirective } from 'ng-zorro-antd/icon';
-export type NzButtonType = 'primary' | 'dashed' | 'danger' | 'default';
+export type NzButtonType = 'primary' | 'dashed' | 'danger' | 'default' | 'link';
export type NzButtonShape = 'circle' | 'round' | null;
@Component({
diff --git a/components/button/nz-button.spec.ts b/components/button/nz-button.spec.ts
index ea185ad8efa..b04b0de0e37 100644
--- a/components/button/nz-button.spec.ts
+++ b/components/button/nz-button.spec.ts
@@ -40,6 +40,7 @@ describe('button', () => {
expect(buttons[1].nativeElement.classList.contains('ant-btn-default')).toBe(true);
expect(buttons[2].nativeElement.classList.contains('ant-btn-dashed')).toBe(true);
expect(buttons[3].nativeElement.classList.contains('ant-btn-danger')).toBe(true);
+ expect(buttons[4].nativeElement.classList.contains('ant-btn-link')).toBe(true);
});
});
@@ -115,10 +116,7 @@ describe('button', () => {
it('should have correct style', () => {
fixture.detectChanges();
- expect(buttons[0].nativeElement.classList.contains('ant-btn-background-ghost')).toBe(true);
- expect(buttons[1].nativeElement.classList.contains('ant-btn-background-ghost')).toBe(true);
- expect(buttons[2].nativeElement.classList.contains('ant-btn-background-ghost')).toBe(true);
- expect(buttons[3].nativeElement.classList.contains('ant-btn-background-ghost')).toBe(true);
+ expect(buttons.every(button => button.nativeElement.classList.contains('ant-btn-background-ghost'))).toBe(true);
});
});
@@ -299,11 +297,9 @@ describe('button', () => {
expect(buttons[1].nativeElement.classList.contains('ant-btn-default')).toBe(true);
expect(buttons[2].nativeElement.classList.contains('ant-btn-dashed')).toBe(true);
expect(buttons[3].nativeElement.classList.contains('ant-btn-danger')).toBe(true);
+ expect(buttons[4].nativeElement.classList.contains('ant-btn-link')).toBe(true);
- expect(buttons[0].nativeElement.classList.contains('ant-btn-block')).toBe(true);
- expect(buttons[1].nativeElement.classList.contains('ant-btn-block')).toBe(true);
- expect(buttons[2].nativeElement.classList.contains('ant-btn-block')).toBe(true);
- expect(buttons[3].nativeElement.classList.contains('ant-btn-block')).toBe(true);
+ expect(buttons.every(button => button.nativeElement.classList.contains('ant-btn-block'))).toBe(true);
});
});
diff --git a/components/button/style/index.less b/components/button/style/index.less
index ef371977504..8692cf86d9c 100644
--- a/components/button/style/index.less
+++ b/components/button/style/index.less
@@ -69,6 +69,10 @@
.btn-danger;
}
+ &-link {
+ .btn-link;
+ }
+
&-round {
.btn-round(@btn-prefix-cls);
}
@@ -90,8 +94,8 @@
border-radius: inherit;
opacity: 0.35;
transition: opacity 0.2s;
- pointer-events: none;
content: '';
+ pointer-events: none;
}
.@{iconfont-css-prefix} {
@@ -107,14 +111,17 @@
}
}
+ &&-loading {
+ position: relative;
+ pointer-events: none;
+ }
+
&&-loading::before {
display: block;
}
&&-loading:not(&-circle):not(&-circle-outline):not(&-icon-only) {
- position: relative;
padding-left: 29px;
- pointer-events: none;
.@{iconfont-css-prefix}:not(:last-child) {
margin-left: -14px;
}
@@ -162,6 +169,12 @@
.button-variant-ghost(@btn-danger-color);
}
+ &-background-ghost&-link {
+ .button-variant-ghost(@link-color; transparent);
+
+ color: @component-background;
+ }
+
&-two-chinese-chars::first-letter {
letter-spacing: 0.34em;
}
@@ -189,4 +202,4 @@ a.@{btn-prefix-cls} {
&-sm {
line-height: @btn-height-sm - 2px;
}
-}
+}
\ No newline at end of file
diff --git a/components/button/style/mixin.less b/components/button/style/mixin.less
index 58b0f6fd0f1..19a83b6e3ae 100644
--- a/components/button/style/mixin.less
+++ b/components/button/style/mixin.less
@@ -7,7 +7,7 @@
border-radius: @border-radius;
}
-.button-disabled() {
+.button-disabled(@color: @btn-disable-color; @background: @btn-disable-bg; @border: @btn-disable-border) {
&-disabled,
&.disabled,
&[disabled] {
@@ -16,7 +16,8 @@
&:focus,
&:active,
&.active {
- .button-color(@btn-disable-color; @btn-disable-bg; @btn-disable-border);
+ .button-color(@color; @background; @border);
+
text-shadow: none;
box-shadow: none;
}
@@ -25,6 +26,7 @@
.button-variant-primary(@color; @background) {
.button-color(@color; @background; @background);
+
text-shadow: @btn-text-shadow;
box-shadow: @btn-primary-shadow;
@@ -84,16 +86,26 @@
}
.button-disabled();
}
-.button-variant-ghost(@color) {
- .button-color(@color; transparent; @color);
+.button-variant-ghost(@color; @border: @color) {
+ .button-color(@color; transparent; @border);
text-shadow: none;
&:hover,
&:focus {
- .button-color(~`colorPalette('@{color}', 5) `; transparent; ~`colorPalette('@{color}', 5) `);
+ & when (@border = transparent) {
+ .button-color(~`colorPalette('@{color}', 5) `; transparent; transparent);
+ }
+ & when not(@border = transparent) {
+ .button-color(~`colorPalette('@{color}', 5) `; transparent; ~`colorPalette('@{color}', 5) `);
+ }
}
&:active,
&.active {
- .button-color(~`colorPalette('@{color}', 7) `; transparent; ~`colorPalette('@{color}', 7) `);
+ & when (@border = transparent) {
+ .button-color(~`colorPalette('@{color}', 7) `; transparent; transparent);
+ }
+ & when not(@border = transparent) {
+ .button-color(~`colorPalette('@{color}', 7) `; transparent; ~`colorPalette('@{color}', 7) `);
+ }
}
.button-disabled();
}
@@ -220,6 +232,17 @@
.btn-danger() {
.button-variant-danger(@btn-danger-color, @btn-danger-bg, @btn-danger-border);
}
+// link button style
+.btn-link() {
+ .button-variant-other(@link-color, transparent, transparent);
+ box-shadow: none;
+ &:hover,
+ &:focus,
+ &:active {
+ border-color: transparent;
+ }
+ .button-disabled(@disabled-color; transparent; transparent);
+}
// round button
.btn-round(@btnClassName: btn) {
.button-size(@btn-circle-size; 0 @btn-circle-size / 2; @font-size-base + 2px; @btn-circle-size);
@@ -247,7 +270,7 @@
.button-size(@btn-circle-size-sm; 0; @font-size-base; 50%);
}
}
-// Horizontal button groups styl
+// Horizontal button groups style
// --------------------------------------------------
.btn-group(@btnClassName: btn) {
.button-group-base(@btnClassName);
@@ -322,4 +345,4 @@
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
-}
+}
\ No newline at end of file
diff --git a/components/core/wave/nz-wave-renderer.ts b/components/core/wave/nz-wave-renderer.ts
index 88dc486b166..08bf5020ef8 100644
--- a/components/core/wave/nz-wave-renderer.ts
+++ b/components/core/wave/nz-wave-renderer.ts
@@ -14,16 +14,13 @@ export class NzWaveRenderer {
private styleForPseudo: HTMLStyleElement | null;
private extraNode: HTMLDivElement | null;
private lastTime = 0;
-
+ private platform = new Platform();
get waveAttributeName(): string {
return this.insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
}
constructor(private triggerElement: HTMLElement, private ngZone: NgZone, private insertExtraNode: boolean) {
- const platform = new Platform();
- if (platform.isBrowser) {
- this.bindTriggerEvent();
- }
+ this.bindTriggerEvent();
}
onClick = (event: MouseEvent) => {
@@ -40,11 +37,13 @@ export class NzWaveRenderer {
};
bindTriggerEvent(): void {
- this.ngZone.runOutsideAngular(() => {
- if (this.triggerElement) {
- this.triggerElement.addEventListener('click', this.onClick, true);
- }
- });
+ if (this.platform.isBrowser) {
+ this.ngZone.runOutsideAngular(() => {
+ if (this.triggerElement) {
+ this.triggerElement.addEventListener('click', this.onClick, true);
+ }
+ });
+ }
}
removeTriggerEvent(): void {
diff --git a/components/core/wave/nz-wave.directive.ts b/components/core/wave/nz-wave.directive.ts
index 2a30546a765..35817cedc16 100644
--- a/components/core/wave/nz-wave.directive.ts
+++ b/components/core/wave/nz-wave.directive.ts
@@ -47,6 +47,14 @@ export class NzWaveDirective implements OnInit, OnDestroy {
private waveRenderer: NzWaveRenderer;
private waveDisabled: boolean = false;
+ get disabled(): boolean {
+ return this.waveDisabled;
+ }
+
+ get rendererRef(): NzWaveRenderer {
+ return this.waveRenderer;
+ }
+
constructor(
private ngZone: NgZone,
private elementRef: ElementRef,
@@ -76,4 +84,21 @@ export class NzWaveDirective implements OnInit, OnDestroy {
this.waveRenderer = new NzWaveRenderer(this.elementRef.nativeElement, this.ngZone, this.nzWaveExtraNode);
}
}
+
+ disable(): void {
+ this.waveDisabled = true;
+ if (this.waveRenderer) {
+ this.waveRenderer.removeTriggerEvent();
+ this.waveRenderer.removeStyleAndExtraNode();
+ }
+ }
+
+ enable(): void {
+ this.waveDisabled = false;
+ if (this.waveRenderer) {
+ this.waveRenderer.bindTriggerEvent();
+ } else {
+ this.renderWaveIfEnabled();
+ }
+ }
}
diff --git a/components/core/wave/nz-wave.spec.ts b/components/core/wave/nz-wave.spec.ts
index 86ac40a77fc..ae6f01281ea 100644
--- a/components/core/wave/nz-wave.spec.ts
+++ b/components/core/wave/nz-wave.spec.ts
@@ -1,5 +1,6 @@
import { Component, ElementRef, ViewChild } from '@angular/core';
import { fakeAsync, tick, ComponentFixture, TestBed } from '@angular/core/testing';
+import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { dispatchMouseEvent } from '../testing';
import { NzWaveDirective } from './nz-wave.directive';
import { NzWaveModule } from './nz-wave.module';
@@ -8,14 +9,14 @@ const WAVE_ATTRIBUTE_NAME = 'ant-click-animating-without-extra-node';
const WAVE_ATTRIBUTE_NAME_EXTRA_NODE = 'ant-click-animating';
const EXTRA_NODE_CLASS_NAME = '.ant-click-animating-node';
-describe('nz-wave', () => {
- let fixture: ComponentFixture;
+describe('nz-wave base', () => {
+ let fixture: ComponentFixture;
let waveTarget: HTMLElement;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [NzWaveModule],
- declarations: [WaveContainerWithButtonComponent, WaveContainerWithExtraNodeComponent]
+ declarations: [WaveContainerWithButtonComponent]
});
});
@@ -52,7 +53,7 @@ describe('nz-wave', () => {
});
it('should not create wave on click when disabled', () => {
- (fixture.componentInstance as WaveContainerWithButtonComponent).disabled = true;
+ fixture.componentInstance.disabled = true;
fixture.detectChanges();
dispatchMouseEvent(waveTarget, 'click');
expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(false);
@@ -101,6 +102,18 @@ describe('nz-wave', () => {
expect(document.body.querySelector('style') !== null).toBe(false);
});
});
+});
+
+describe('nz-wave extra', () => {
+ let fixture: ComponentFixture;
+ let waveTarget: HTMLElement;
+
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [NzWaveModule],
+ declarations: [WaveContainerWithExtraNodeComponent]
+ });
+ });
describe('extra node wave', () => {
beforeEach(() => {
@@ -172,6 +185,58 @@ describe('nz-wave', () => {
});
});
+describe('nz-wave disable/enable', () => {
+ let fixture: ComponentFixture;
+ let waveTarget: HTMLElement;
+ let waveRef: NzWaveDirective;
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ imports: [NzWaveModule, NoopAnimationsModule],
+ declarations: [WaveContainerWithButtonComponent]
+ });
+ });
+
+ describe('disable/enable', () => {
+ beforeEach(() => {
+ fixture = TestBed.createComponent(WaveContainerWithButtonComponent);
+ fixture.detectChanges();
+ waveTarget = fixture.componentInstance.trigger.nativeElement;
+ waveRef = fixture.componentInstance.wave;
+ });
+
+ it('should disable by NoopAnimationsModule ', () => {
+ expect(waveRef.disabled).toBe(true);
+ expect(waveRef.rendererRef).toBeFalsy();
+ waveRef.disable();
+ expect(waveRef.rendererRef).toBeFalsy();
+ });
+
+ it('should create waveRenderer when called enable', () => {
+ waveRef.enable();
+ expect(waveRef.disabled).toBe(false);
+ expect(waveRef.rendererRef).toBeTruthy();
+ });
+
+ it('should enable work', () => {
+ waveRef.enable();
+ expect(waveRef.disabled).toBe(false);
+ expect(waveRef.rendererRef).toBeTruthy();
+ dispatchMouseEvent(waveTarget, 'click');
+ expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(true);
+ expect(document.body.querySelector('style') !== null).toBe(true);
+ });
+
+ it('should disable work', () => {
+ waveRef.disable();
+ expect(waveRef.disabled).toBe(true);
+ expect(waveRef.rendererRef).toBeFalsy();
+ dispatchMouseEvent(waveTarget, 'click');
+ expect(waveTarget.hasAttribute(WAVE_ATTRIBUTE_NAME)).toBe(false);
+ expect(document.body.querySelector('style') === null).toBe(true);
+ });
+ });
+});
+
@Component({
template: `