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; };