ant-design-vue/components/icon/index.js
2019-10-30 16:42:01 +08:00

181 lines
4.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import classNames from 'classnames';
import * as allIcons from '@ant-design/icons/lib/dist';
import VueIcon from '@ant-design/icons-vue';
import PropTypes from '../_util/vue-types';
import createFromIconfontCN from './IconFont';
import {
svgBaseProps,
withThemeSuffix,
removeTypeTheme,
getThemeFromTypeName,
alias,
} from './utils';
import warning from '../_util/warning';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import { getTwoToneColor, setTwoToneColor } from './twoTonePrimaryColor';
import { filterEmpty, getClass } from '../_util/props-util';
import Base from '../base';
// Initial setting
VueIcon.add(...Object.keys(allIcons).map(key => allIcons[key]));
setTwoToneColor('#1890ff');
const defaultTheme = 'outlined';
let dangerousTheme;
function renderIcon(h, locale, context) {
const { props, slots, listeners, data } = context;
const {
// affect inner <svg>...</svg>
type,
component: Component,
viewBox,
spin,
// other
theme, // default to outlined
twoToneColor,
rotate,
tabIndex,
} = 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({
...getClass(context),
[`anticon`]: true,
[`anticon-${type}`]: !!type,
});
const svgClassString = classNames({
[`anticon-spin`]: !!spin || type === 'loading',
});
const svgStyle = rotate
? {
msTransform: `rotate(${rotate}deg)`,
transform: `rotate(${rotate}deg)`,
}
: undefined;
let innerNode;
// component > children > type
if (Component) {
const innerSvgProps = {
attrs: {
...svgBaseProps,
viewBox,
},
class: svgClassString,
style: svgStyle,
};
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,
style: svgStyle,
};
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(computedType)),
dangerousTheme || theme || defaultTheme,
);
innerNode = (
<VueIcon
focusable="false"
class={svgClassString}
type={computedType}
primaryColor={twoToneColor}
style={svgStyle}
/>
);
}
let iconTabIndex = tabIndex;
if (iconTabIndex === undefined && 'click' in listeners) {
iconTabIndex = -1;
}
const { attrs, ...restDataProps } = data;
// functional component not support nativeOnhttps://github.com/vuejs/vue/issues/7526
const iProps = {
...restDataProps,
attrs: {
...attrs,
'aria-label': type && `${locale.icon}: ${type}`,
tabIndex: iconTabIndex,
},
on: { ...listeners, ...data.nativeOn },
class: classString,
staticClass: '',
};
return <i {...iProps}>{innerNode}</i>;
}
const Icon = {
functional: true,
name: 'AIcon',
props: {
tabIndex: PropTypes.number,
type: PropTypes.string,
component: PropTypes.any,
viewBox: PropTypes.any,
spin: PropTypes.bool.def(false),
rotate: PropTypes.number,
theme: PropTypes.oneOf(['filled', 'outlined', 'twoTone']),
twoToneColor: PropTypes.string,
role: PropTypes.string,
},
render(h, context) {
return (
<LocaleReceiver
componentName="Icon"
scopedSlots={{ default: locale => renderIcon(h, locale, context) }}
/>
);
},
};
Icon.createFromIconfontCN = createFromIconfontCN;
Icon.getTwoToneColor = getTwoToneColor;
Icon.setTwoToneColor = setTwoToneColor;
/* istanbul ignore next */
Icon.install = function(Vue) {
Vue.use(Base);
Vue.component(Icon.name, Icon);
};
export default Icon;