diff --git a/components/icon/demo/basic.ts b/components/icon/demo/basic.ts
index 027cacea88c..c52c30135ee 100644
--- a/components/icon/demo/basic.ts
+++ b/components/icon/demo/basic.ts
@@ -7,10 +7,16 @@ import { Component } from '@angular/core';
-
+
- `
+ `,
+ styles: [ `
+ .icons-list > .anticon {
+ margin-right: 6px;
+ font-size: 24px;
+ }
+ `]
})
export class NzDemoIconBasicComponent {
}
diff --git a/components/icon/demo/custom.md b/components/icon/demo/custom.md
new file mode 100644
index 00000000000..7da95a9736e
--- /dev/null
+++ b/components/icon/demo/custom.md
@@ -0,0 +1,14 @@
+---
+order: 2
+title:
+ zh-CN: 自定义图标
+ en-US: Custom Icon
+---
+
+## zh-CN
+
+你可以直接将 `svg` 标签放在 `nz-icon` 中来渲染自定义内容。
+
+## en-US
+
+You can just put a `svg` element inside of a `nz-icon` to render custom content.
diff --git a/components/icon/demo/custom.ts b/components/icon/demo/custom.ts
new file mode 100644
index 00000000000..e9d28b2602b
--- /dev/null
+++ b/components/icon/demo/custom.ts
@@ -0,0 +1,34 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'nz-demo-icon-custom',
+ template: `
+
+
+
+
+
+
+
+
+ `,
+ styles : [ `
+ .icons-list > .anticon {
+ margin-right: 6px;
+ font-size: 24px;
+ }
+ ` ]
+})
+export class NzDemoIconCustomComponent {
+}
\ No newline at end of file
diff --git a/components/icon/demo/iconfont.md b/components/icon/demo/iconfont.md
new file mode 100644
index 00000000000..99b1246af8c
--- /dev/null
+++ b/components/icon/demo/iconfont.md
@@ -0,0 +1,14 @@
+---
+order: 3
+title:
+ zh-CN: 使用 Iconfont.cn
+ en-US: Use iconfont.cn
+---
+
+## zh-CN
+
+对于使用 [iconfont.cn](http://iconfont.cn/) 的用户,通过设置 `createFromIconfontCN` 方法参数对象中的 `scriptUrl` 字段, 即可轻松地使用已有项目中的图标。
+
+## en-US
+
+If you are using [iconfont.cn](http://iconfont.cn/), you can use the icons in your project gracefully.
diff --git a/components/icon/demo/iconfont.ts b/components/icon/demo/iconfont.ts
new file mode 100644
index 00000000000..8b76585a186
--- /dev/null
+++ b/components/icon/demo/iconfont.ts
@@ -0,0 +1,26 @@
+import { Component } from '@angular/core';
+import { NzIconService } from 'ng-zorro-antd';
+
+@Component({
+ selector: 'nz-demo-icon-iconfont',
+ template: `
+
+
+
+
+
+ `,
+ styles : [ `
+ .icons-list > .anticon {
+ margin-right: 6px;
+ font-size: 24px;
+ }
+ ` ]
+})
+export class NzDemoIconIconfontComponent {
+ constructor(private _iconService: NzIconService) {
+ this._iconService.fetchFromIconfont({
+ scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js'
+ });
+ }
+}
diff --git a/components/icon/demo/twotone.md b/components/icon/demo/twotone.md
new file mode 100644
index 00000000000..0d7861195a1
--- /dev/null
+++ b/components/icon/demo/twotone.md
@@ -0,0 +1,15 @@
+---
+order: 1
+title:
+ zh-CN: 多色图标
+ en-US: Two-tone icon and colorful icon
+---
+
+## zh-CN
+
+可以通过设置 `theme` 属性为 `twotone` 来渲染双色图标,并且可以设置主题色。
+
+## en-US
+
+
+Specify property `theme` to `twotone` to render two-tone icons. You can also the primary color.` prop to show spinning animation and the theme property to switch different themes. Old API ``
diff --git a/components/icon/demo/twotone.ts b/components/icon/demo/twotone.ts
new file mode 100644
index 00000000000..964074203fb
--- /dev/null
+++ b/components/icon/demo/twotone.ts
@@ -0,0 +1,20 @@
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'nz-demo-icon-twotone',
+ template: `
+
+
+
+
+
+ `,
+ styles : [ `
+ .icons-list > .anticon {
+ margin-right: 6px;
+ font-size: 24px;
+ }
+ ` ]
+})
+export class NzDemoIconTwotoneComponent {
+}
diff --git a/components/icon/doc/index.en-US.md b/components/icon/doc/index.en-US.md
index 56cdcacdda6..5725b1a565a 100755
--- a/components/icon/doc/index.en-US.md
+++ b/components/icon/doc/index.en-US.md
@@ -19,3 +19,28 @@ We provide semantic name for every icon, and naming rules are as follows:
## API
+
+### [nz-input]
+
+All props of input supported by [w3c standards](https://www.w3schools.com/tags/tag_input.asp) and Angular can used in `nz-input`.
+
+| Property | Description | Type | Default |
+| -------- | ----------- | ---- | ------- |
+| `[nzSize]` | The size of the input box. Note: in the context of a form, the `large` size is used. Available: `large` `default` `small` | string | `default` |
+| `[nzAutosize]` | Only used for `textarea`, height autosize feature, can be set to `boolean` or an object `{ minRows: 2, maxRows: 6 }` | boolean丨`{ minRows: number, maxRows: number }` | false |
+
+
+### nz-input-group
+
+| Property | Description | Type | Default |
+| -------- | ----------- | ---- | ------- |
+| `[nzAddonAfter]` | The label text displayed after (on the right side of) the input field. | string 丨 `TemplateRef` | |
+| `[nzAddonAfterIcon]` | The label icon's ngClass displayed after. | `string 丨 string[] 丨 Set 丨 { [klass: string]: any; }` | |
+| `[nzAddonBefore]` | The label text displayed before (on the left side of) the input field. | string 丨 `TemplateRef` | |
+| `[nzAddonBeforeIcon]` | The label icon's ngClass displayed before. | `string 丨 string[] 丨 Set 丨 { [klass: string]: any; }` | |
+| `[nzPrefix]` | The prefix icon for the Input. | string 丨 `TemplateRef` | |
+| `[nzPrefixIcon]` | The prefix icon's ngClass for the Input. | `string 丨 string[] 丨 Set 丨 { [klass: string]: any; }` | |
+| `[nzSuffix]` | The suffix icon for the Input. | string 丨 `TemplateRef` | |
+| `[nzSuffixIcon]` | The suffix icon's ngClass for the Input. | `string 丨 string[] 丨 Set 丨 { [klass: string]: any; }` | |
+| `[nzCompact]` | Whether use compact style | boolean | false |
+| `[nzSize]` | The size of `nz-input-group` specifies the size of the included `nz-input` fields. Available: `large` `default` `small` | string | `default` |
diff --git a/components/icon/doc/index.zh-CN.md b/components/icon/doc/index.zh-CN.md
index d22f4e18d37..447ea26c366 100755
--- a/components/icon/doc/index.zh-CN.md
+++ b/components/icon/doc/index.zh-CN.md
@@ -15,3 +15,28 @@ hasPageDemo: true
新版图标可能略有缺失,我们还在持续补充中。
## API
+
+### [nz-input]
+
+All props of input supported by [w3c standards](https://www.w3schools.com/tags/tag_input.asp) and Angular can used in `nz-input`.
+
+| Property | Description | Type | Default |
+| -------- | ----------- | ---- | ------- |
+| `[nzSize]` | The size of the input box. Note: in the context of a form, the `large` size is used. Available: `large` `default` `small` | string | `default` |
+| `[nzAutosize]` | Only used for `textarea`, height autosize feature, can be set to `boolean` or an object `{ minRows: 2, maxRows: 6 }` | boolean丨`{ minRows: number, maxRows: number }` | false |
+
+
+### nz-input-group
+
+| Property | Description | Type | Default |
+| -------- | ----------- | ---- | ------- |
+| `[nzAddonAfter]` | The label text displayed after (on the right side of) the input field. | string 丨 `TemplateRef` | |
+| `[nzAddonAfterIcon]` | The label icon's ngClass displayed after. | `string 丨 string[] 丨 Set 丨 { [klass: string]: any; }` | |
+| `[nzAddonBefore]` | The label text displayed before (on the left side of) the input field. | string 丨 `TemplateRef` | |
+| `[nzAddonBeforeIcon]` | The label icon's ngClass displayed before. | `string 丨 string[] 丨 Set 丨 { [klass: string]: any; }` | |
+| `[nzPrefix]` | The prefix icon for the Input. | string 丨 `TemplateRef` | |
+| `[nzPrefixIcon]` | The prefix icon's ngClass for the Input. | `string 丨 string[] 丨 Set 丨 { [klass: string]: any; }` | |
+| `[nzSuffix]` | The suffix icon for the Input. | string 丨 `TemplateRef` | |
+| `[nzSuffixIcon]` | The suffix icon's ngClass for the Input. | `string 丨 string[] 丨 Set 丨 { [klass: string]: any; }` | |
+| `[nzCompact]` | Whether use compact style | boolean | false |
+| `[nzSize]` | The size of `nz-input-group` specifies the size of the included `nz-input` fields. Available: `large` `default` `small` | string | `default` |
diff --git a/components/icon/nz-icon.directive.ts b/components/icon/nz-icon.directive.ts
index f874d267e46..ba43a105432 100644
--- a/components/icon/nz-icon.directive.ts
+++ b/components/icon/nz-icon.directive.ts
@@ -1,4 +1,14 @@
-import { isDevMode, Directive, ElementRef, Input, OnChanges, OnDestroy, OnInit } from '@angular/core';
+import {
+ isDevMode,
+ AfterContentChecked,
+ Directive,
+ ElementRef,
+ Input,
+ OnChanges,
+ OnDestroy,
+ OnInit,
+ Renderer2
+} from '@angular/core';
import { IconDirective } from 'ant-icons-angular';
import { NzIconService } from './nz-icon.service';
@@ -12,18 +22,16 @@ import { NzIconService } from './nz-icon.service';
@Directive({
selector: 'i.anticon, [nz-icon]'
})
-export class NzIconDirective extends IconDirective implements OnInit, OnChanges, OnDestroy {
- @Input() spin: boolean;
+export class NzIconDirective extends IconDirective implements OnInit, OnChanges, OnDestroy, AfterContentChecked {
+ @Input() spin = false;
+ @Input() iconfont: string;
+ // private _renderer: Renderer2;
private _classObserver: MutationObserver;
- protected _iconService: NzIconService;
/**
* In order to make this directive compatible to old API, we had do some ugly stuff here.
* Should be removed in next major version.
- *
- * @param className className property of a DOM element
- * @private
*/
private _classChangeHandler(className: string): void {
const getTypeName = function (): string {
@@ -31,7 +39,6 @@ export class NzIconDirective extends IconDirective implements OnInit, OnChanges,
return iconClass.length ? iconClass[ 0 ].replace('anticon-', '') : '';
};
- // TODO: deal with spin here.
let newType = getTypeName();
if (!newType) {
return;
@@ -46,7 +53,9 @@ export class NzIconDirective extends IconDirective implements OnInit, OnChanges,
}
if (this.type !== newType) {
this.type = newType;
- this._changeIcon();
+ this._changeIcon().then(svg => {
+ this._addExtraModifications(svg);
+ });
}
}
@@ -57,14 +66,29 @@ export class NzIconDirective extends IconDirective implements OnInit, OnChanges,
this._iconService.warnedAboutAPI = true;
}
- constructor(_iconSrv: NzIconService, _elementRef: ElementRef) {
- super(_iconSrv, _elementRef);
- // Convert type. We know NzIconService would be injected but TypeScript don't.
- this._iconService = _iconSrv as NzIconService;
+ private _addExtraModifications(svg: SVGElement): void {
+ if (this.spin || this.type === 'loading') {
+ this._renderer.addClass(svg, 'anticon-spin');
+ } else {
+ this._renderer.removeClass(svg, 'anticon-spin');
+ }
+ }
+
+ constructor(public _iconService: NzIconService, public _elementRef: ElementRef, public _renderer: Renderer2) {
+ super(_iconService, _elementRef); // NzIconService extends IconService so IconDirective won't complain.
}
+ /**
+ * Override this method to check if the icon need to be spin.
+ */
ngOnChanges(): void {
- this._changeIcon();
+ if (!this.iconfont) {
+ this._changeIcon().then(svg => {
+ this._addExtraModifications(svg);
+ });
+ } else {
+ this._setSVGElement(this._iconService.createIconfontIcon(`#${this.iconfont}`));
+ }
}
/**
@@ -82,6 +106,9 @@ export class NzIconDirective extends IconDirective implements OnInit, OnChanges,
});
this._classObserver.observe(this._elementRef.nativeElement, { attributes: true });
}
+
+ // this._renderer = this._rendererFactory.createRenderer(null, null);
+ this._renderer.addClass(this._elementRef.nativeElement, 'anticon');
}
ngOnDestroy(): void {
@@ -89,4 +116,12 @@ export class NzIconDirective extends IconDirective implements OnInit, OnChanges,
this._classObserver.disconnect();
}
}
+
+ ngAfterContentChecked(): void {
+ const children = (this._elementRef.nativeElement as HTMLElement).children;
+ if (children && children.length && !this.type) {
+ const child = children[0];
+ this._iconService.normalizeSvgElement(child as SVGElement);
+ }
+ }
}
diff --git a/components/icon/nz-icon.service.ts b/components/icon/nz-icon.service.ts
index f7e62e844bd..f3268c298a9 100644
--- a/components/icon/nz-icon.service.ts
+++ b/components/icon/nz-icon.service.ts
@@ -1,6 +1,12 @@
-import { Injectable } from '@angular/core';
+import { DOCUMENT } from '@angular/common';
+import { HttpClient } from '@angular/common/http';
+import { Inject, Injectable, Optional, RendererFactory2 } from '@angular/core';
import { IconService } from 'ant-icons-angular';
+export interface NzIconfontOption {
+ scriptUrl: string;
+}
+
/**
* It should be a global singleton, otherwise registered icons could not be found.
*/
@@ -8,5 +14,45 @@ import { IconService } from 'ant-icons-angular';
providedIn: 'root'
})
export class NzIconService extends IconService {
+ private _iconfontCache = new Set();
+
warnedAboutAPI = false;
+
+ normalizeSvgElement(svg: SVGElement): void {
+ if (!svg.getAttribute('viewBox')) {
+ this._renderer.setAttribute(svg, 'viewBox', '0 0 1024 1024');
+ }
+ if (!svg.getAttribute('width') || !svg.getAttribute('height')) {
+ this._renderer.setAttribute(svg, 'width', '1em');
+ this._renderer.setAttribute(svg, 'height', '1em');
+ }
+ if (!svg.getAttribute('fill')) {
+ this._renderer.setAttribute(svg, 'fill', 'currentColor');
+ }
+ }
+
+ fetchFromIconfont(opt: NzIconfontOption): void {
+ const { scriptUrl } = opt;
+ if (this._document && !this._iconfontCache.has(scriptUrl)) {
+ const script = this._renderer.createElement('script');
+ this._renderer.setAttribute(script, 'src', `https:${ scriptUrl }`);
+ this._renderer.setAttribute(script, 'data-namespace', scriptUrl);
+ this._iconfontCache.add(scriptUrl);
+ this._renderer.appendChild(this._document.body, script);
+ }
+ }
+
+ createIconfontIcon(type: string): SVGElement {
+ const svgString = ``;
+ return this._createSVGElementFromString(svgString);
+ }
+
+ constructor(
+ protected _rendererFactory: RendererFactory2,
+ @Optional() protected _http: HttpClient,
+ // tslint:disable:no-any
+ @Optional() @Inject(DOCUMENT) protected _document: any
+ ) {
+ super(_rendererFactory, _http, _document);
+ }
}
diff --git a/components/ng-zorro-antd.module.ts b/components/ng-zorro-antd.module.ts
index 8df3ac2c52b..96e5580083e 100644
--- a/components/ng-zorro-antd.module.ts
+++ b/components/ng-zorro-antd.module.ts
@@ -75,6 +75,7 @@ export * from './drawer';
export * from './form';
export * from './grid';
export * from './i18n';
+export * from './icon';
export * from './input';
export * from './input-number';
export * from './layout';
diff --git a/site_scripts/_site/src/app/app.component.ts b/site_scripts/_site/src/app/app.component.ts
index 878f417c474..a1508b3a358 100644
--- a/site_scripts/_site/src/app/app.component.ts
+++ b/site_scripts/_site/src/app/app.component.ts
@@ -1,9 +1,9 @@
import { AfterViewInit, Component, ElementRef, HostListener, OnInit, ViewChild } from '@angular/core';
import { Title } from '@angular/platform-browser';
import { NavigationEnd, Router } from '@angular/router';
-import { IconService, IconDefinition } from 'ant-icons-angular';
+import { IconDefinition } from 'ant-icons-angular';
import * as AllIcons from 'ant-icons-angular/icons';
-import { en_US, zh_CN, NzI18nService, NzMessageService } from 'ng-zorro-antd';
+import { en_US, zh_CN, NzI18nService, NzIconService, NzMessageService } from 'ng-zorro-antd';
import { environment } from '../environments/environment';
import { ROUTER_LIST } from './router';
@@ -44,7 +44,7 @@ export class AppComponent implements OnInit, AfterViewInit {
this.hide = !this.hide;
}
- constructor(private router: Router, private title: Title, private nzI18nService: NzI18nService, private msg: NzMessageService, private iconService: IconService) {
+ constructor(private router: Router, private title: Title, private nzI18nService: NzI18nService, private msg: NzMessageService, private iconService: NzIconService) {
const antDesignIcons = AllIcons as {
[key: string]: IconDefinition;
};