diff --git a/components/icon/demo/basic.md b/components/icon/demo/basic.md
index 63c7e76c0..180f40e1b 100644
--- a/components/icon/demo/basic.md
+++ b/components/icon/demo/basic.md
@@ -15,6 +15,7 @@ Use tag `` to create an icon and set its type in the `type` prop. Specif
+
diff --git a/components/icon/index.en-US.md b/components/icon/index.en-US.md
index 057dea421..6c95b708e 100644
--- a/components/icon/index.en-US.md
+++ b/components/icon/index.en-US.md
@@ -6,6 +6,7 @@
| style | Style properties of icon, like `fontSize` and `color` | CSSProperties | - |
| theme | Theme of the ant design icon | 'filled' \| 'outlined' \| 'twoTone' | 'outlined' |
| spin | Rotate icon with animation | boolean | false |
+| rotate | Rotate degrees (added in 1.40.0, not working in IE9) | number | - |
| component | The component used for the root node. This will override the **`type`** property. | ComponentType | - |
| twoToneColor | Only support the two-tone icon. Specific the primary color. | string (hex color) | - |
diff --git a/components/icon/index.js b/components/icon/index.js
index b5d438b6e..8cde86400 100644
--- a/components/icon/index.js
+++ b/components/icon/index.js
@@ -11,6 +11,7 @@ import {
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';
@@ -20,109 +21,146 @@ setTwoToneColor('#1890ff');
const defaultTheme = 'outlined';
let dangerousTheme;
+function renderIcon(h, locale, context) {
+ const { props, slots, listeners, data } = context;
+ const {
+ // affect inner
+ 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,
+ style: svgStyle,
+ viewBox,
+ },
+ class: svgClassString,
+ };
+ if (!viewBox) {
+ delete innerSvgProps.attrs.viewBox;
+ }
+
+ innerNode = {children};
+ }
+ 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 = (
+
+ );
+ }
+
+ 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 = (
+
+ );
+ }
+ let iconTabIndex = tabIndex;
+ if (iconTabIndex === undefined && ('click' in listeners)) {
+ iconTabIndex = -1;
+ }
+ const { attrs, ...restDataProps } = data;
+ // functional component not support nativeOn,https://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 {innerNode};
+}
+
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) {
- const { props, slots, listeners, data } = context;
- const {
- // affect inner
- 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`.',
+ return (
+ renderIcon(h, locale, context) }}
+ />
);
-
- const classString = classNames({
- ...getClass(context),
- [`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 = {children};
- }
- 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 = (
-
- );
- }
-
- 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 = (
-
- );
- }
- // functional component not support nativeOn,https://github.com/vuejs/vue/issues/7526
- const iProps = {
- ...data,
- on: { ...listeners, ...data.nativeOn },
- class: classString,
- staticClass: '',
- };
- return {innerNode};
},
};
diff --git a/components/icon/index.zh-CN.md b/components/icon/index.zh-CN.md
index 538b39e86..eed622db4 100644
--- a/components/icon/index.zh-CN.md
+++ b/components/icon/index.zh-CN.md
@@ -7,6 +7,7 @@
| style | 设置图标的样式,例如 `fontSize` 和 `color` | CSSProperties | - |
| theme | 图标主题风格。可选实心、描线、双色等主题风格,适用于官方图标 | 'filled' \| 'outlined' \| 'twoTone' | 'outlined' |
| spin | 是否有旋转动画 | boolean | false |
+| rotate | 图标旋转角度(1.40.0 后新增,IE9 无效) | number | - |
| component | 控制如何渲染图标,通常是一个渲染根标签为 `