feat: update icon

pull/1845/head
tangjinzhou 2020-02-17 17:59:18 +08:00
parent 1fffe0d632
commit 4efc5099c6
13 changed files with 155 additions and 254 deletions

View File

@ -1,5 +1,5 @@
module.exports = { module.exports = {
dev: { dev: {
componentName: 'grid', // dev components componentName: 'icon', // dev components
}, },
}; };

View File

@ -2,8 +2,12 @@
exports[`Icon \`component\` prop can access to svg defs if has children 1`] = ` exports[`Icon \`component\` prop can access to svg defs if has children 1`] = `
<i class="my-home-icon anticon"><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""> <i class="my-home-icon anticon"><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
<title>Cool Home</title> <defs>
<path d="'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'"></path> <linearGradient id="gradient">
<stop offset="20%" stopColor="#39F"></stop>
<stop offset="90%" stopColor="#F3F"></stop>
</linearGradient>
</defs>
</svg></i> </svg></i>
`; `;
@ -58,9 +62,9 @@ exports[`Icon should support pass svg paths as children 1`] = `
`; `;
exports[`Icon should support svg vue component 1`] = ` exports[`Icon should support svg vue component 1`] = `
<i class="my-home-icon anticon"><svg width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class=""> <i class="my-home-icon anticon"><svg viewBox="0 0 24 24" width="1em" height="1em" fill="currentColor" aria-hidden="true" focusable="false" class="">
<title>Cool Home</title> <title>Cool Home</title>
<path d="'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'"></path> <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z"></path>
</svg></i> </svg></i>
`; `;

View File

@ -3,8 +3,11 @@ import Icon from '..';
import VueIcon from '@ant-design/icons-vue'; import VueIcon from '@ant-design/icons-vue';
import { getThemeFromTypeName, withThemeSuffix } from '../utils'; import { getThemeFromTypeName, withThemeSuffix } from '../utils';
import { cloneElement } from '../../_util/vnode'; import { cloneElement } from '../../_util/vnode';
import mountTest from '../../../tests/shared/mountTest';
describe('Icon', () => { describe('Icon', () => {
mountTest(Icon);
it('should render to a <i class="xxx"><svg>...</svg></i>', () => { it('should render to a <i class="xxx"><svg>...</svg></i>', () => {
const wrapper = mount({ const wrapper = mount({
render() { render() {
@ -119,7 +122,7 @@ describe('Icon', () => {
return <Icon type="clock-circle-o" theme="outlined" />; return <Icon type="clock-circle-o" theme="outlined" />;
}, },
}); });
expect(errorSpy).not.toBeCalled(); expect(errorSpy).not.toHaveBeenCalled();
}); });
it('warns', () => { it('warns', () => {
@ -129,7 +132,7 @@ describe('Icon', () => {
}, },
}); });
expect(errorSpy).toBeCalledWith( expect(errorSpy).toBeCalledWith(
"Warning: The icon name 'clock-circle-o' already specify a theme 'outlined', the 'theme' prop 'filled' will be ignored.", "Warning: [antdv: Icon] The icon name 'clock-circle-o' already specify a theme 'outlined', the 'theme' prop 'filled' will be ignored.",
); );
}); });
}); });

View File

@ -13,14 +13,10 @@ const md = {
## 设计师专属 ## 设计师专属
安装 [Kitchen Sketch 插件 <EFBFBD>](https://kitchen.alipay.com)使 Ant Design Iconfont 安装 [Kitchen Sketch 插件 <EFBFBD>](https://kitchen.alipay.com)使 Ant Design Iconfont
## 图标列表 ## 图标列表
> 点击图标即可复制代码
新版图标可能略有缺失我们还在持续补充中
`, `,
us: `# Icon us: `# Icon
Semantic vector graphics. Semantic vector graphics.
## List of icons ## List of icons
> Click the icon and copy the code.
We are still adding two-tone icons right now.
`, `,
}; };
export default { export default {

View File

@ -5,7 +5,7 @@
<us> <us>
#### Two-tone icon and colorful icon #### Two-tone icon and colorful icon
Specific them property `theme` to `twoTone` to render two-tone icons. You can also set the primary color. Specify the property `theme` to `twoTone` to render two-tone icons. You can also set the primary color.
</us> </us>
```tpl ```tpl

View File

@ -4,26 +4,30 @@
| --- | --- | --- | --- | | --- | --- | --- | --- |
| type | Type of the ant design icon | string | - | | type | Type of the ant design icon | string | - |
| style | Style properties of icon, like `fontSize` and `color` | CSSProperties | - | | style | Style properties of icon, like `fontSize` and `color` | CSSProperties | - |
| theme | Theme of the ant design icon | 'filled' \| 'outlined' \| 'twoTone' | 'outlined' | | theme | Theme variant of the icon | 'filled' \| 'outlined' \| 'twoTone' | 'outlined' |
| spin | Rotate icon with animation | boolean | false | | spin | Rotate icon with animation | boolean | false |
| rotate | Rotate degrees (added in 1.4.0, not working in IE9) | number | - | | rotate | Rotate degrees (added in 1.4.0, not working in IE9) | number | - |
| component | The component used for the root node. This will override the **`type`** property. | ComponentType<CustomIconComponentProps\> | - | | component | The component used for the root node. This will override the **`type`** property. | ComponentType<CustomIconComponentProps\> | - |
| twoToneColor | Only support the two-tone icon. Specific the primary color. | string (hex color) | - | | twoToneColor | Only support the two-tone icon. Specific the primary color. | string (hex color) | - |
> Note: icon rendering priority of the Icon component is component > children > type. When props is passed, the higher priority item will work, and the lower priority item will be invalid.
### SVG icons ### SVG icons
We introduced SVG icons in `1.2.0` version replacing font icons which brings benefits below: We introduced SVG icons in version `1.2.0`, replacing font icons. This has the following benefits:
- Complete offline usage of icon, no dependency of CDN font icon file and no more empty square during downloading than no need to deploy icon font files locally either. - Complete offline usage of icons, without dependency on a CDN-hosted font icon file (No more empty square during downloading and no need to deploy icon font files locally either!)
- Much more display accuracy in lower-level screens. - Much more display accuracy on lower-resolution screens
- Support multiple colors for icon. - The ability to choose icon color
- No need to change built-in icons with overriding styles by providing more props in component. - No need to change built-in icons with overriding styles by providing more props in component
More discussion of SVG icon reference to [#10353](https://github.com/ant-design/ant-design/issues/10353). More discussion of SVG icon reference at [#10353](https://github.com/ant-design/ant-design/issues/10353).
> ⚠️ About the extra bundle size brought by all SVG icons we imported in 1.2.0, we will provide new API to allow developers importing icons as your need, you can trace [#12011](https://github.com/ant-design/ant-design/issues/12011) for further progress. > ⚠️ Given the extra bundle size caused by all SVG icons imported in 1.2.0, we will provide a new API to allow developers to import icons as needed, you can track [#12011](https://github.com/ant-design/ant-design/issues/12011) for updates.
>
> While you wait, you can use [webpack plugin](https://github.com/Beven91/webpack-ant-icon-loader) from the community to chunk the icon file.
The properties `theme`, `component` and `twoToneColor` are added in `1.2.0`. The best practice is to pass the property `theme` to every `<Icon />` components. The properties `theme`, `component` and `twoToneColor` were added in `1.2.0`. The best practice is to pass the property `theme` to every `<Icon />` component.
```html ```html
<a-icon type="star" theme="filled" /> <a-icon type="star" theme="filled" />

View File

@ -41,6 +41,7 @@ function renderIcon(h, locale, context) {
children = children.length === 0 ? undefined : children; children = children.length === 0 ? undefined : children;
warning( warning(
Boolean(type || Component || children), Boolean(type || Component || children),
'Icon',
'Icon should have `type` prop or `component` prop or `children`.', 'Icon should have `type` prop or `component` prop or `children`.',
); );
@ -61,68 +62,71 @@ function renderIcon(h, locale, context) {
} }
: undefined; : undefined;
let innerNode; const innerSvgProps = {
attrs: {
...svgBaseProps,
viewBox,
},
class: svgClassString,
style: svgStyle,
};
if (!viewBox) {
delete innerSvgProps.attrs.viewBox;
}
// component > children > type const renderInnerNode = () => {
if (Component) { // component > children > type
const innerSvgProps = { if (Component) {
attrs: { return <Component {...innerSvgProps}>{children}</Component>;
...svgBaseProps,
viewBox,
},
class: svgClassString,
style: svgStyle,
};
if (!viewBox) {
delete innerSvgProps.attrs.viewBox;
} }
if (children) {
innerNode = <Component {...innerSvgProps}>{children}</Component>;
}
if (children) {
warning(
Boolean(viewBox) || (children.length === 1 && children[0].tag === 'use'),
'Make sure that you provide correct `viewBox`' +
' prop (default `0 0 1024 1024`) to the icon.',
);
const innerSvgProps = {
attrs: {
...svgBaseProps,
},
class: svgClassString,
style: svgStyle,
};
innerNode = (
<svg {...innerSvgProps} viewBox={viewBox}>
{children}
</svg>
);
}
if (typeof type === 'string') {
let computedType = type;
if (theme) {
const themeInName = getThemeFromTypeName(type);
warning( warning(
!themeInName || theme === themeInName, Boolean(viewBox) || (children.length === 1 && children[0].tag === 'use'),
`The icon name '${type}' already specify a theme '${themeInName}',` + 'Icon',
` the 'theme' prop '${theme}' will be ignored.`, 'Make sure that you provide correct `viewBox`' +
' prop (default `0 0 1024 1024`) to the icon.',
);
const innerSvgProps = {
attrs: {
...svgBaseProps,
},
class: svgClassString,
style: svgStyle,
};
return (
<svg {...innerSvgProps} viewBox={viewBox}>
{children}
</svg>
); );
} }
computedType = withThemeSuffix(
removeTypeTheme(alias(computedType)), if (typeof type === 'string') {
dangerousTheme || theme || defaultTheme, let computedType = type;
); if (theme) {
innerNode = ( const themeInName = getThemeFromTypeName(type);
<VueIcon warning(
focusable="false" !themeInName || theme === themeInName,
class={svgClassString} 'Icon',
type={computedType} `The icon name '${type}' already specify a theme '${themeInName}',` +
primaryColor={twoToneColor} ` the 'theme' prop '${theme}' will be ignored.`,
style={svgStyle} );
/> }
); computedType = withThemeSuffix(
} removeTypeTheme(alias(computedType)),
dangerousTheme || theme || defaultTheme,
);
return (
<VueIcon
focusable="false"
class={svgClassString}
type={computedType}
primaryColor={twoToneColor}
style={svgStyle}
/>
);
}
};
let iconTabIndex = tabIndex; let iconTabIndex = tabIndex;
if (iconTabIndex === undefined && 'click' in listeners) { if (iconTabIndex === undefined && 'click' in listeners) {
iconTabIndex = -1; iconTabIndex = -1;
@ -140,7 +144,7 @@ function renderIcon(h, locale, context) {
class: classString, class: classString,
staticClass: '', staticClass: '',
}; };
return <i {...iProps}>{innerNode}</i>; return <i {...iProps}>{renderInnerNode()}</i>;
} }
const Icon = { const Icon = {

View File

@ -10,6 +10,8 @@
| component | 控制如何渲染图标,通常是一个渲染根标签为 `<svg>``Vue` 组件,**会使 `type` 属性失效** | ComponentType<CustomIconComponentProps\> | - | | component | 控制如何渲染图标,通常是一个渲染根标签为 `<svg>``Vue` 组件,**会使 `type` 属性失效** | ComponentType<CustomIconComponentProps\> | - |
| twoToneColor | 仅适用双色图标。设置双色图标的主要颜色 | string (十六进制颜色) | - | | twoToneColor | 仅适用双色图标。设置双色图标的主要颜色 | string (十六进制颜色) | - |
> 注意Icon 组件中图标渲染的优先级为 component > children > type, 传入 props 时,优先级高的直接生效,优先级低的则失效。
### SVG 图标 ### SVG 图标
`1.2.0` 之后,我们使用了 SVG 图标替换了原先的 font 图标,从而带来了以下优势: `1.2.0` 之后,我们使用了 SVG 图标替换了原先的 font 图标,从而带来了以下优势:
@ -21,7 +23,7 @@
更多讨论可参考:[#10353](https://github.com/ant-design/ant-design/issues/10353)。 更多讨论可参考:[#10353](https://github.com/ant-design/ant-design/issues/10353)。
> ⚠️ 1.2.0 之后我们全量引入了所有图标,导致 antd 默认的包体积有一定增加,我们会在不远的未来增加新的 API 来实现图标的按需使用,更多相关讨论可关注:[#12011](https://github.com/ant-design/ant-design/issues/12011)。 > ⚠️ 1.2.0 之后我们全量引入了所有图标,导致 antd 默认的包体积有一定增加,我们会在不远的未来增加新的 API 来实现图标的按需使用,更多相关讨论可关注:[#12011](https://github.com/ant-design/ant-design/issues/12011)。在此之前,你可以通过来自社区同学的 [webpack 插件](https://github.com/Beven91/webpack-ant-icon-loader)将图标文件拆分。
其中 `theme`, `component`, `twoToneColor``1.2.x` 版本新增加的属性。最佳实践是给使用的 `<Icon />` 组件传入属性 `theme` 以明确图标的主题风格。例如: 其中 `theme`, `component`, `twoToneColor``1.2.x` 版本新增加的属性。最佳实践是给使用的 `<Icon />` 组件传入属性 `theme` 以明确图标的主题风格。例如:

View File

@ -42,17 +42,36 @@ export function withThemeSuffix(type, theme) {
} else if (theme === 'twoTone') { } else if (theme === 'twoTone') {
result += '-twotone'; result += '-twotone';
} else { } else {
warning(false, `This icon '${type}' has unknown theme '${theme}'`); warning(false, 'Icon', `This icon '${type}' has unknown theme '${theme}'`);
} }
return result; return result;
} }
// For alias or compatibility // For alias or compatibility
export function alias(type) { export function alias(type) {
let newType = type;
switch (type) { switch (type) {
case 'cross': case 'cross':
return 'close'; newType = 'close';
break;
// https://github.com/ant-design/ant-design/issues/13007
case 'interation':
newType = 'interaction';
break;
// https://github.com/ant-design/ant-design/issues/16810
case 'canlendar':
newType = 'calendar';
break;
// https://github.com/ant-design/ant-design/issues/17448
case 'colum-height':
newType = 'column-height';
break;
default: default:
} }
return type; warning(
newType === type,
'Icon',
`Icon '${type}' was a typo and is now deprecated, please use '${newType}' instead.`,
);
return newType;
} }

View File

@ -13,7 +13,12 @@
</li> </li>
</template> </template>
<script> <script>
import Badge from '@/components/badge';
import '@/components/badge/style';
export default { export default {
components: {
'a-badge': Badge,
},
props: ['type', 'isNew', 'theme', 'justCopied'], props: ['type', 'isNew', 'theme', 'justCopied'],
data() { data() {
const { type, theme } = this; const { type, theme } = this;

View File

@ -1,4 +1,15 @@
export const categories = { import manifest from '@ant-design/icons/lib/manifest';
let allIcons = [];
Object.keys(manifest).forEach(theme => {
allIcons = [...allIcons, ...manifest[theme]];
});
// Hide typo-name icons
allIcons = allIcons.filter(name => !['interation', 'canlendar', 'colum-height'].includes(name));
const categories = {
all: [...new Set(allIcons)],
direction: [ direction: [
'step-backward', 'step-backward',
'step-forward', 'step-forward',
@ -22,6 +33,9 @@ export const categories = {
'double-left', 'double-left',
'vertical-left', 'vertical-left',
'vertical-right', 'vertical-right',
'vertical-align-top',
'vertical-align-middle',
'vertical-align-bottom',
'forward', 'forward',
'backward', 'backward',
'rollback', 'rollback',
@ -46,7 +60,7 @@ export const categories = {
'border-bottom', 'border-bottom',
'border-horizontal', 'border-horizontal',
'border-inner', 'border-inner',
'border-outter', 'border-outer',
'border-left', 'border-left',
'border-right', 'border-right',
'border-top', 'border-top',
@ -57,6 +71,7 @@ export const categories = {
'radius-bottomleft', 'radius-bottomleft',
'radius-bottomright', 'radius-bottomright',
'radius-upleft', 'radius-upleft',
'radius-upright',
'fullscreen', 'fullscreen',
'fullscreen-exit', 'fullscreen-exit',
], ],
@ -86,7 +101,7 @@ export const categories = {
'issues-close', 'issues-close',
'stop', 'stop',
], ],
edit: [ editor: [
'edit', 'edit',
'form', 'form',
'copy', 'copy',
@ -110,15 +125,16 @@ export const categories = {
'font-colors', 'font-colors',
'font-size', 'font-size',
'line-height', 'line-height',
'colum-height',
'colum-width',
'dash', 'dash',
'small-dash', 'small-dash',
'sort-ascending', 'sort-ascending',
'sort-descending', 'sort-descending',
'drag', 'drag',
'ordered-list', 'ordered-list',
'unordered-list',
'radius-setting', 'radius-setting',
'column-width',
'column-height',
], ],
data: [ data: [
'area-chart', 'area-chart',
@ -135,170 +151,6 @@ export const categories = {
'fund', 'fund',
'sliders', 'sliders',
], ],
other: [
'lock',
'unlock',
'bars',
'book',
'calendar',
'cloud',
'cloud-download',
'code',
'copy',
'credit-card',
'delete',
'desktop',
'download',
'ellipsis',
'file',
'file-text',
'file-unknown',
'file-pdf',
'file-word',
'file-excel',
'file-jpg',
'file-ppt',
'file-markdown',
'file-add',
'folder',
'folder-open',
'folder-add',
'hdd',
'frown',
'meh',
'smile',
'inbox',
'laptop',
'appstore',
'link',
'mail',
'mobile',
'notification',
'paper-clip',
'picture',
'poweroff',
'reload',
'search',
'setting',
'share-alt',
'shopping-cart',
'tablet',
'tag',
'tags',
'to-top',
'upload',
'user',
'video-camera',
'home',
'loading',
'loading-3-quarters',
'cloud-upload',
'star',
'heart',
'environment',
'eye',
'eye-invisible',
'camera',
'save',
'team',
'solution',
'phone',
'filter',
'exception',
'export',
'customer-service',
'qrcode',
'scan',
'like',
'dislike',
'message',
'pay-circle',
'calculator',
'pushpin',
'bulb',
'select',
'switcher',
'rocket',
'bell',
'disconnect',
'database',
'compass',
'barcode',
'hourglass',
'key',
'flag',
'layout',
'printer',
'sound',
'usb',
'skin',
'tool',
'sync',
'wifi',
'car',
'schedule',
'user-add',
'user-delete',
'usergroup-add',
'usergroup-delete',
'man',
'woman',
'shop',
'gift',
'idcard',
'medicine-box',
'red-envelope',
'coffee',
'copyright',
'trademark',
'safety',
'wallet',
'bank',
'trophy',
'contacts',
'global',
'shake',
'api',
'fork',
'dashboard',
'table',
'profile',
'alert',
'audit',
'batch-folding',
'branches',
'build',
'border',
'crown',
'experiment',
'fire',
'money-collect',
'property-safety',
'read',
'reconciliation',
'rest',
'security-scan',
'insurance',
'interation',
'safety-certificate',
'project',
'thunderbolt',
'block',
'cluster',
'deployment-unit',
'dollar',
'euro',
'pound',
'file-done',
'file-exclamation',
'file-protect',
'file-search',
'file-sync',
'gateway',
'gold',
'robot',
'shopping',
],
logo: [ logo: [
'android', 'android',
'apple', 'apple',
@ -335,6 +187,7 @@ export const categories = {
'codepen-circle', 'codepen-circle',
'alipay', 'alipay',
'ant-design', 'ant-design',
'ant-cloud',
'aliyun', 'aliyun',
'zhihu', 'zhihu',
'slack', 'slack',
@ -347,5 +200,9 @@ export const categories = {
'yuque', 'yuque',
'alibaba', 'alibaba',
'yahoo', 'yahoo',
'reddit',
'sketch',
], ],
}; };
export default categories;

View File

@ -1,7 +1,9 @@
import manifest from '@ant-design/icons/lib/manifest'; import manifest from '@ant-design/icons/lib/manifest';
import Category from './Category'; import Category from './Category';
import { FilledIcon, OutlinedIcon, TwoToneIcon } from './themeIcons'; import { FilledIcon, OutlinedIcon, TwoToneIcon } from './themeIcons';
import { categories } from './fields'; import categories from './fields';
import Radio from '@/components/radio';
import '@/components/radio/style';
const IconDisplay = { const IconDisplay = {
cagetories: categories, cagetories: categories,
@ -115,6 +117,11 @@ const IconDisplay = {
outlined: 'outline', outlined: 'outline',
twoTone: 'twotone', twoTone: 'twotone',
}, },
components: {
ARadio: Radio,
ARadioGroup: Radio.Group,
ARadioButton: Radio.Button,
},
data() { data() {
return { return {
theme: 'outlined', theme: 'outlined',

View File

@ -5,7 +5,7 @@ export default function mountTest(Component) {
it(`component could be updated and unmounted without errors`, () => { it(`component could be updated and unmounted without errors`, () => {
const wrapper = mount(Component); const wrapper = mount(Component);
expect(() => { expect(() => {
wrapper.setProps({}); wrapper.vm.$forceUpdate();
wrapper.destroy(); wrapper.destroy();
}).not.toThrow(); }).not.toThrow();
}); });