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

View File

@ -3,8 +3,11 @@ import Icon from '..';
import VueIcon from '@ant-design/icons-vue';
import { getThemeFromTypeName, withThemeSuffix } from '../utils';
import { cloneElement } from '../../_util/vnode';
import mountTest from '../../../tests/shared/mountTest';
describe('Icon', () => {
mountTest(Icon);
it('should render to a <i class="xxx"><svg>...</svg></i>', () => {
const wrapper = mount({
render() {
@ -119,7 +122,7 @@ describe('Icon', () => {
return <Icon type="clock-circle-o" theme="outlined" />;
},
});
expect(errorSpy).not.toBeCalled();
expect(errorSpy).not.toHaveBeenCalled();
});
it('warns', () => {
@ -129,7 +132,7 @@ describe('Icon', () => {
},
});
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
## 图标列表
> 点击图标即可复制代码
新版图标可能略有缺失我们还在持续补充中
`,
us: `# Icon
Semantic vector graphics.
## List of icons
> Click the icon and copy the code.
We are still adding two-tone icons right now.
`,
};
export default {

View File

@ -5,7 +5,7 @@
<us>
#### 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>
```tpl

View File

@ -4,26 +4,30 @@
| --- | --- | --- | --- |
| type | Type of the ant design icon | string | - |
| 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 |
| 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\> | - |
| 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
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.
- Much more display accuracy in lower-level screens.
- Support multiple colors for icon.
- No need to change built-in icons with overriding styles by providing more props in component.
- 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 on lower-resolution screens
- The ability to choose icon color
- 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
<a-icon type="star" theme="filled" />

View File

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

View File

@ -10,6 +10,8 @@
| component | 控制如何渲染图标,通常是一个渲染根标签为 `<svg>``Vue` 组件,**会使 `type` 属性失效** | ComponentType<CustomIconComponentProps\> | - |
| twoToneColor | 仅适用双色图标。设置双色图标的主要颜色 | string (十六进制颜色) | - |
> 注意Icon 组件中图标渲染的优先级为 component > children > type, 传入 props 时,优先级高的直接生效,优先级低的则失效。
### SVG 图标
`1.2.0` 之后,我们使用了 SVG 图标替换了原先的 font 图标,从而带来了以下优势:
@ -21,7 +23,7 @@
更多讨论可参考:[#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` 以明确图标的主题风格。例如:

View File

@ -42,17 +42,36 @@ export function withThemeSuffix(type, theme) {
} else if (theme === 'twoTone') {
result += '-twotone';
} else {
warning(false, `This icon '${type}' has unknown theme '${theme}'`);
warning(false, 'Icon', `This icon '${type}' has unknown theme '${theme}'`);
}
return result;
}
// For alias or compatibility
export function alias(type) {
let newType = type;
switch (type) {
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:
}
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>
</template>
<script>
import Badge from '@/components/badge';
import '@/components/badge/style';
export default {
components: {
'a-badge': Badge,
},
props: ['type', 'isNew', 'theme', 'justCopied'],
data() {
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: [
'step-backward',
'step-forward',
@ -22,6 +33,9 @@ export const categories = {
'double-left',
'vertical-left',
'vertical-right',
'vertical-align-top',
'vertical-align-middle',
'vertical-align-bottom',
'forward',
'backward',
'rollback',
@ -46,7 +60,7 @@ export const categories = {
'border-bottom',
'border-horizontal',
'border-inner',
'border-outter',
'border-outer',
'border-left',
'border-right',
'border-top',
@ -57,6 +71,7 @@ export const categories = {
'radius-bottomleft',
'radius-bottomright',
'radius-upleft',
'radius-upright',
'fullscreen',
'fullscreen-exit',
],
@ -86,7 +101,7 @@ export const categories = {
'issues-close',
'stop',
],
edit: [
editor: [
'edit',
'form',
'copy',
@ -110,15 +125,16 @@ export const categories = {
'font-colors',
'font-size',
'line-height',
'colum-height',
'colum-width',
'dash',
'small-dash',
'sort-ascending',
'sort-descending',
'drag',
'ordered-list',
'unordered-list',
'radius-setting',
'column-width',
'column-height',
],
data: [
'area-chart',
@ -135,170 +151,6 @@ export const categories = {
'fund',
'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: [
'android',
'apple',
@ -335,6 +187,7 @@ export const categories = {
'codepen-circle',
'alipay',
'ant-design',
'ant-cloud',
'aliyun',
'zhihu',
'slack',
@ -347,5 +200,9 @@ export const categories = {
'yuque',
'alibaba',
'yahoo',
'reddit',
'sketch',
],
};
export default categories;

View File

@ -1,7 +1,9 @@
import manifest from '@ant-design/icons/lib/manifest';
import Category from './Category';
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 = {
cagetories: categories,
@ -115,6 +117,11 @@ const IconDisplay = {
outlined: 'outline',
twoTone: 'twotone',
},
components: {
ARadio: Radio,
ARadioGroup: Radio.Group,
ARadioButton: Radio.Button,
},
data() {
return {
theme: 'outlined',

View File

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