feat: update icon

pull/309/head
tangjinzhou 2018-11-17 15:57:38 +08:00
parent 02a0012dcb
commit 6da26a9bc4
11 changed files with 777 additions and 2 deletions

View File

@ -0,0 +1,53 @@
import Icon from './index'
const customCache = new Set()
export default function create (options) {
const { scriptUrl } = options
/**
* DOM API required.
* Make sure in browser environment.
* The Custom Icon will create a <script/>
* that loads SVG symbols and insert the SVG Element into the document body.
*/
if (typeof document !== 'undefined' && typeof window !== 'undefined' &&
typeof document.createElement === 'function' &&
typeof scriptUrl === 'string' && scriptUrl.length &&
!customCache.has(scriptUrl)
) {
const script = document.createElement('script')
script.setAttribute('src', scriptUrl)
script.setAttribute('data-namespace', scriptUrl)
customCache.add(scriptUrl)
document.body.appendChild(script)
}
const Iconfont = {
functional: true,
name: 'AIconfont',
render (h, context) {
const { props, slots, listeners } = context
const { type, ...restProps } = props
const slotsMap = slots()
const children = slotsMap.default
// component > children > type
let content = null
if (type) {
content = <use {...{ attrs: { 'xlink:href': `#${type}` }}} />
}
if (children) {
content = children
}
return (
<Icon
{...{ props: restProps, on: listeners }}
>
{content}
</Icon>
)
},
}
return Iconfont
}

View File

@ -0,0 +1,29 @@
<cn>
#### 基本用法
使用 `<Icon />` 标签声明组件,指定图标对应的 `type` 属性。可以通过 `theme` 属性来设置不同的主题风格的图标,也可以通过设置 `spin` 属性来实现动画旋转效果。
</cn>
<us>
#### Basic
Use tag `<Icon />` to create an icon and set its type in the `type` prop. Specific the `spin` property to show spinning animation and the `theme` property to switch different themes.
</us>
```html
<template>
<div class="icons-list">
<a-icon type="home" />
<a-icon type="setting" theme="filled" />
<a-icon type="smile" theme="outlined" />
<a-icon type="sync" spin />
<a-icon type="loading" />
</div>
</template>
<style scoped>
.icons-list >>> .anticon {
margin-right: 6px;
font-size: 24px;
}
</style>
```

View File

@ -0,0 +1,76 @@
<cn>
#### 自定义图标
利用 `Icon` 组件封装一个可复用的自定义图标。可以通过 `component` 属性传入一个组件来渲染最终的图标,以满足特定的需求。
</cn>
<us>
#### Basic
Create a reusable Vue component by using `<Icon component={...} />`. The property `component` takes a Vue component that renders to `svg` element.
</us>
```html
<template>
<div class="custom-icons-list">
<HeartIcon :style="{ color: 'hotpink' }" />
<PandaIcon :style="{ fontSize: '32px' }" />
</div>
<script>
const HeartSvg = {
template: `
<svg width="1em" height="1em" fill="currentColor" viewBox="0 0 1024 1024">
<path d="M923 283.6c-13.4-31.1-32.6-58.9-56.9-82.8-24.3-23.8-52.5-42.4-84-55.5-32.5-13.5-66.9-20.3-102.4-20.3-49.3 0-97.4 13.5-139.2 39-10 6.1-19.5 12.8-28.5 20.1-9-7.3-18.5-14-28.5-20.1-41.8-25.5-89.9-39-139.2-39-35.5 0-69.9 6.8-102.4 20.3-31.4 13-59.7 31.7-84 55.5-24.4 23.9-43.5 51.7-56.9 82.8-13.9 32.3-21 66.6-21 101.9 0 33.3 6.8 68 20.3 103.3 11.3 29.5 27.5 60.1 48.2 91 32.8 48.9 77.9 99.9 133.9 151.6 92.8 85.7 184.7 144.9 188.6 147.3l23.7 15.2c10.5 6.7 24 6.7 34.5 0l23.7-15.2c3.9-2.5 95.7-61.6 188.6-147.3 56-51.7 101.1-102.7 133.9-151.6 20.7-30.9 37-61.5 48.2-91 13.5-35.3 20.3-70 20.3-103.3 0.1-35.3-7-69.6-20.9-101.9z" />
</svg>
`
}
const PandaSvg = {
template: `
<svg viewBox="0 0 1024 1024" width="1em" height="1em" fill="currentColor">
<path d="M99.096 315.634s-82.58-64.032-82.58-132.13c0-66.064 33.032-165.162 148.646-148.646 83.37 11.91 99.096 165.162 99.096 165.162l-165.162 115.614zM924.906 315.634s82.58-64.032 82.58-132.13c0-66.064-33.032-165.162-148.646-148.646-83.37 11.91-99.096 165.162-99.096 165.162l165.162 115.614z" fill="#6B676E" p-id="1143" />
<path d="M1024 561.548c0 264.526-229.23 429.42-512.002 429.42S0 826.076 0 561.548 283.96 66.064 512.002 66.064 1024 297.022 1024 561.548z" fill="#FFEBD2" p-id="1144" />
<path d="M330.324 842.126c0 82.096 81.34 148.646 181.678 148.646s181.678-66.55 181.678-148.646H330.324z" fill="#E9D7C3" p-id="1145" />
<path d="M644.13 611.098C594.582 528.516 561.55 512 512.002 512c-49.548 0-82.58 16.516-132.13 99.096-42.488 70.814-78.73 211.264-49.548 247.742 66.064 82.58 165.162 33.032 181.678 33.032 16.516 0 115.614 49.548 181.678-33.032 29.18-36.476-7.064-176.93-49.55-247.74z" fill="#FFFFFF" p-id="1146" />
<path d="M611.098 495.484c0-45.608 36.974-82.58 82.58-82.58 49.548 0 198.194 99.098 198.194 165.162s-79.934 144.904-148.646 99.096c-49.548-33.032-132.128-148.646-132.128-181.678zM412.904 495.484c0-45.608-36.974-82.58-82.58-82.58-49.548 0-198.194 99.098-198.194 165.162s79.934 144.904 148.646 99.096c49.548-33.032 132.128-148.646 132.128-181.678z" fill="#6B676E" p-id="1147" />
<path d="M512.002 726.622c-30.06 0-115.614 5.668-115.614 33.032 0 49.638 105.484 85.24 115.614 82.58 10.128 2.66 115.614-32.944 115.614-82.58-0.002-27.366-85.556-33.032-115.614-33.032z" fill="#464655" p-id="1148" />
<path d="M330.324 495.484m-33.032 0a33.032 33.032 0 1 0 66.064 0 33.032 33.032 0 1 0-66.064 0Z" fill="#464655" p-id="1149" />
<path d="M693.678 495.484m-33.032 0a33.032 33.032 0 1 0 66.064 0 33.032 33.032 0 1 0-66.064 0Z" fill="#464655" p-id="1150" />
</svg>
`
}
const HeartIcon = {
template: `
<a-icon :component="HeartSvg" />
`,
data() {
return {
HeartSvg
}
}
}
const PandaIcon = {
template: `
<a-icon :component="PandaSvg" />
`,
data() {
return {
PandaSvg
}
}
}
export default {
components: {
HeartIcon,
PandaIcon,
}
}
</script>
<style scoped>
.custom-icons-list >>> .anticon {
margin-right: 6px;
}
</style>
```

View File

@ -0,0 +1,39 @@
<cn>
#### 使用 iconfont.cn
对于使用 [iconfont.cn](http://iconfont.cn/) 的用户,通过设置 `createFromIconfontCN` 方法参数对象中的 `scriptUrl` 字段, 即可轻松地使用已有项目中的图标。
</cn>
<us>
#### Use iconfont.cn
If you are using [iconfont.cn](http://iconfont.cn/), you can use the icons in your project gracefully.
</us>
```html
<template>
<div class="icons-list">
<IconFont type="icon-tuichu" />
<IconFont type="icon-facebook" />
<IconFont type="icon-twitter" />
</div>
</template>
<script>
import { Icon } from 'antd';
const IconFont = Icon.createFromIconfontCN({
scriptUrl: '//at.alicdn.com/t/font_8d5l8fzk5b87iudi.js',
})
export default {
components: {
IconFont,
}
}
</script>
<style scoped>
.icons-list >>> .anticon {
margin-right: 6px;
font-size: 24px;
}
</style>
```

View File

@ -42,6 +42,7 @@ const md = {
export default {
category: 'Components',
type: 'General',
zhType: '通用',
title: 'Icon',
subtitle: '图标',
render () {

View File

@ -0,0 +1,318 @@
<cn>
#### 老版图标
测试 1.2.0 之前的老图标。
</cn>
<us>
#### Test old icons
Test old icons before `1.2.0`.
</us>
```html
<template>
<div>
<a-icon v-for="icon in icons" :key="icon" :type="icon" />
</div>
</template>
<script>
const icons = [
'step-backward',
'step-forward',
'fast-backward',
'fast-forward',
'shrink',
'arrows-alt',
'down',
'up',
'left',
'right',
'caret-up',
'caret-down',
'caret-left',
'caret-right',
'up-circle',
'down-circle',
'left-circle',
'right-circle',
'up-circle-o',
'down-circle-o',
'right-circle-o',
'left-circle-o',
'double-right',
'double-left',
'verticle-left',
'verticle-right',
'forward',
'backward',
'rollback',
'enter',
'retweet',
'swap',
'swap-left',
'swap-right',
'arrow-up',
'arrow-down',
'arrow-left',
'arrow-right',
'play-circle',
'play-circle-o',
'up-square',
'down-square',
'left-square',
'right-square',
'up-square-o',
'down-square-o',
'left-square-o',
'right-square-o',
'login',
'logout',
'menu-fold',
'menu-unfold',
'question',
'question-circle-o',
'question-circle',
'plus',
'plus-circle-o',
'plus-circle',
'pause',
'pause-circle-o',
'pause-circle',
'minus',
'minus-circle-o',
'minus-circle',
'plus-square',
'plus-square-o',
'minus-square',
'minus-square-o',
'info',
'info-circle-o',
'info-circle',
'exclamation',
'exclamation-circle-o',
'exclamation-circle',
'close',
'cross',
'close-circle',
'close-circle-o',
'close-square',
'close-square-o',
'check',
'check-circle',
'check-circle-o',
'check-square',
'check-square-o',
'clock-circle-o',
'clock-circle',
'warning',
'lock',
'unlock',
'area-chart',
'pie-chart',
'bar-chart',
'dot-chart',
'bars',
'book',
'calendar',
'cloud',
'cloud-download',
'code',
'code-o',
'copy',
'credit-card',
'delete',
'desktop',
'download',
'edit',
'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',
'frown-o',
'meh',
'meh-o',
'smile',
'smile-o',
'inbox',
'laptop',
'appstore-o',
'appstore',
'line-chart',
'link',
'mail',
'mobile',
'notification',
'paper-clip',
'picture',
'poweroff',
'reload',
'search',
'setting',
'share-alt',
'shopping-cart',
'tablet',
'tag',
'tag-o',
'tags',
'tags-o',
'to-top',
'upload',
'user',
'video-camera',
'home',
'loading',
'loading-3-quarters',
'cloud-upload-o',
'cloud-download-o',
'cloud-upload',
'cloud-o',
'star-o',
'star',
'heart-o',
'heart',
'environment',
'environment-o',
'eye',
'eye-o',
'camera',
'camera-o',
'save',
'team',
'solution',
'phone',
'filter',
'exception',
'export',
'customer-service',
'qrcode',
'scan',
'like',
'like-o',
'dislike',
'dislike-o',
'message',
'pay-circle',
'pay-circle-o',
'calculator',
'pushpin',
'pushpin-o',
'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',
'form',
'table',
'profile',
'android',
'android-o',
'apple',
'apple-o',
'windows',
'windows-o',
'ie',
'chrome',
'github',
'aliwangwang',
'aliwangwang-o',
'dingding',
'dingding-o',
'weibo-square',
'weibo-circle',
'taobao-circle',
'html5',
'weibo',
'twitter',
'wechat',
'youtube',
'alipay-circle',
'taobao',
'skype',
'qq',
'medium-workmark',
'gitlab',
'medium',
'linkedin',
'google-plus',
'dropbox',
'facebook',
'codepen',
'amazon',
'google',
'codepen-circle',
'alipay',
'ant-design',
'aliyun',
'zhihu',
'slack',
'slack-square',
'behance',
'behance-square',
'dribbble',
'dribbble-square',
'instagram',
'yuque',
]
export default {
data() {
return {
icons,
}
}
}
</script>
```

View File

@ -0,0 +1,27 @@
<cn>
#### 多色图标
可以通过设置 `theme` 属性为 `twoTone` 来渲染双色图标,并且可以设置主题色。
</cn>
<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.
</us>
```html
<template>
<div class="icons-list">
<a-icon type="smile" theme="twoTone" />
<a-icon type="heart" theme="twoTone" twoToneColor="#eb2f96" />
<a-icon type="check-circle" theme="twoTone" twoToneColor="#52c41a" />
</div>
</template>
<style scoped>
.icons-list >>> .anticon {
margin-right: 6px;
font-size: 24px;
}
</style>
```

View File

@ -1,4 +1,164 @@
import Icon from './icon'
import classNames from 'classnames'
import * as allIcons from '@ant-design/icons/lib/dist'
import VueIcon from '@ant-design/icons-vue'
import createFromIconfontCN from './IconFont'
import {
svgBaseProps, withThemeSuffix,
removeTypeTheme, getThemeFromTypeName,
alias,
} from './utils'
import warning from '../_util/warning'
import { getTwoToneColor, setTwoToneColor } from './twoTonePrimaryColor'
import { filterEmpty } from '../_util/props-util'
// Initial setting
VueIcon.add(...Object.keys(allIcons).map((key) => allIcons[key]))
setTwoToneColor('#1890ff')
const defaultTheme = 'outlined'
let dangerousTheme
// export interface CustomIconComponentProps {
// width: string | number;
// height: string | number;
// fill: string;
// viewBox?: string;
// className?: string;
// style?: React.CSSProperties;
// ['aria-hidden']?: string;
// }
// export type ThemeType = 'filled' | 'outlined' | 'twoTone';
// export interface IconProps {
// type?: string;
// className?: string;
// theme?: ThemeType;
// title?: string;
// onClick?: React.MouseEventHandler<HTMLElement>;
// component?: React.ComponentType<CustomIconComponentProps>;
// twoToneColor?: string;
// viewBox?: string;
// spin?: boolean;
// style?: React.CSSProperties;
// prefixCls?: string;
// }
// export interface IconComponent<P> extends React.SFC<P> {
// createFromIconfontCN: typeof createFromIconfontCN;
// getTwoToneColor: typeof getTwoToneColor;
// setTwoToneColor: typeof setTwoToneColor;
// unstable_ChangeThemeOfIconsDangerously?: typeof unstable_ChangeThemeOfIconsDangerously;
// unstable_ChangeDefaultThemeOfIcons?: typeof unstable_ChangeDefaultThemeOfIcons;
// }
const Icon = {
functional: true,
name: 'AIcon',
render (h, context) {
const { props, slots, listeners } = context
const {
// affect inner <svg>...</svg>
type,
component: Component,
viewBox,
spin,
// other
theme, // default to outlined
twoToneColor,
} = props
const slotsMap = slots()
let children = filterEmpty(slotsMap.default)
children = children.length === 0 ? undefined : children
warning(
Boolean(type || Component || children),
'Icon should have `type` prop or `component` prop or `children`.',
)
const classString = classNames({
[`anticon`]: true,
[`anticon-${type}`]: !!type,
})
const svgClassString = classNames({
[`anticon-spin`]: !!spin || type === 'loading',
})
let innerNode
// component > children > type
if (Component) {
const innerSvgProps = {
attrs: {
...svgBaseProps,
viewBox,
},
class: svgClassString,
}
if (!viewBox) {
delete innerSvgProps.attrs.viewBox
}
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,
}
innerNode = (
<svg {...innerSvgProps} viewBox={viewBox}>
{children}
</svg>
)
}
if (typeof type === 'string') {
let computedType = type
if (theme) {
const themeInName = getThemeFromTypeName(type)
warning(!themeInName || theme === themeInName,
`The icon name '${type}' already specify a theme '${themeInName}',` +
` the 'theme' prop '${theme}' will be ignored.`)
}
computedType = withThemeSuffix(
removeTypeTheme(alias(type)),
dangerousTheme || theme || defaultTheme,
)
innerNode = (
<VueIcon
class={svgClassString}
type={computedType}
primaryColor={twoToneColor}
/>
)
}
return (
<i {...{ on: listeners }} class={classString}>
{innerNode}
</i>
)
},
}
Icon.createFromIconfontCN = createFromIconfontCN
Icon.getTwoToneColor = getTwoToneColor
Icon.setTwoToneColor = setTwoToneColor
/* istanbul ignore next */
Icon.install = function (Vue) {

View File

@ -0,0 +1,12 @@
import VueIcon from '@ant-design/icons-vue'
export function setTwoToneColor (primaryColor) {
return VueIcon.setTwoToneColors({
primaryColor,
})
}
export function getTwoToneColor () {
const colors = VueIcon.getTwoToneColors()
return colors.primaryColor
}

58
components/icon/utils.js Normal file
View File

@ -0,0 +1,58 @@
import warning from '../_util/warning'
// These props make sure that the SVG behaviours like general text.
// Reference: https://blog.prototypr.io/align-svg-icons-to-text-and-say-goodbye-to-font-icons-d44b3d7b26b4
export const svgBaseProps = {
width: '1em',
height: '1em',
fill: 'currentColor',
'aria-hidden': 'true',
focusable: 'false',
}
const fillTester = /-fill$/
const outlineTester = /-o$/
const twoToneTester = /-twotone$/
export function getThemeFromTypeName (type) {
let result = null
if (fillTester.test(type)) {
result = 'filled'
} else if (outlineTester.test(type)) {
result = 'outlined'
} else if (twoToneTester.test(type)) {
result = 'twoTone'
}
return result
}
export function removeTypeTheme (type) {
return type
.replace(fillTester, '')
.replace(outlineTester, '')
.replace(twoToneTester, '')
}
export function withThemeSuffix (type, theme) {
let result = type
if (theme === 'filled') {
result += '-fill'
} else if (theme === 'outlined') {
result += '-o'
} else if (theme === 'twoTone') {
result += '-twotone'
} else {
warning(false, `This icon '${type}' has unknown theme '${theme}'`)
}
return result
}
// For alias or compatibility
export function alias (type) {
switch (type) {
case 'cross':
return 'close'
default:
}
return type
}

View File

@ -156,6 +156,8 @@
"webpack-merge": "^4.1.1"
},
"dependencies": {
"@ant-design/icons": "^1.1.15",
"@ant-design/icons-vue": "^1.0.0",
"add-dom-event-listener": "^1.0.2",
"array-tree-filter": "^2.1.0",
"async-validator": "^1.8.2",
@ -180,4 +182,4 @@
"shallowequal": "^1.0.2",
"warning": "^3.0.0"
}
}
}