feat: update icon

This commit is contained in:
tangjinzhou 2020-04-04 22:03:18 +08:00
parent 8466ee816e
commit 35433667d4
17 changed files with 36 additions and 414 deletions

@ -1 +1 @@
Subproject commit d5d00665ebc2a2393339f6dbfbdab7b30fe385a5
Subproject commit b5604687d6adb5706a2672cf6971ddaab1bd0fa0

View File

@ -156,7 +156,7 @@ export default {
v-show={!hidden}
className={scrollNumberCls}
count={displayCount}
displayComponent={this.renderDispayComponent()} // <Badge status="success" count={<Icon type="xxx" />}></Badge>
displayComponent={this.renderDispayComponent()}
title={this.getScrollNumberTitle()}
style={statusStyle}
key="scrollNumber"

View File

@ -1,52 +0,0 @@
import Icon from './index';
import { mergeProps } from '../_util/props-util';
const customCache = new Set();
export default function create(options) {
const { scriptUrl, extraCommonProps = {} } = 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',
props: Icon.props,
render(h, context) {
const { props, slots, listeners, data } = 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;
}
const iconProps = mergeProps(extraCommonProps, data, { props: restProps, on: listeners });
return <Icon {...iconProps}>{content}</Icon>;
},
};
return Iconfont;
}

View File

@ -1,236 +0,0 @@
import { mount } from '@vue/test-utils';
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() {
return <Icon type="message" class="my-icon-classname" />;
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('should support basic usage', () => {
const wrapper = mount({
render() {
return (
<div>
<Icon type="home" />
<Icon type="setting" theme="filled" />
<Icon type="smile" theme="outlined" />
<Icon type="sync" spin />
<Icon type="loading" />
</div>
);
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('should support older usage', () => {
const wrapper = mount({
render() {
return (
<div>
<Icon type="home-o" />
<Icon type="setting-fill" />
<Icon type="smile-o" />
<Icon type="check-circle-twotone" />
</div>
);
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('should support two-tone icon', () => {
const wrapper = mount({
render() {
return <Icon type="check-circle" theme="twoTone" twoToneColor="#f5222d" />;
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('should support config global two-tone primary color', () => {
const colors = VueIcon.getTwoToneColors();
Icon.setTwoToneColor('#1890ff');
expect(Icon.getTwoToneColor()).toBe('#1890ff');
const wrapper = mount({
render() {
return <Icon type="check-circle" theme="twoTone" />;
},
});
expect(wrapper.html()).toMatchSnapshot();
VueIcon.setTwoToneColors(colors);
});
it('should support pass svg paths as children', () => {
const wrapper = mount({
render() {
return (
<Icon viewBox="0 0 24 24">
<title>Cool Home</title>
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
</Icon>
);
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('should give warning and render <i>{null}</i>', () => {
const wrapper = mount({
render() {
return <Icon viewBox="0 0 24 24" />;
},
});
expect(wrapper.html()).toMatchSnapshot();
});
it('should support custom usage of children', () => {
expect(() => {
mount({
render() {
return <Icon type="custom">&E648</Icon>;
},
});
}).not.toThrow();
});
describe('warning on conflicting theme', () => {
let errorSpy;
beforeEach(() => {
errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
});
afterEach(() => {
errorSpy.mockRestore();
});
it('does not warn', () => {
mount({
render() {
return <Icon type="clock-circle-o" theme="outlined" />;
},
});
expect(errorSpy).not.toHaveBeenCalled();
});
it('warns', () => {
mount({
render() {
return <Icon type="clock-circle-o" theme="filled" />;
},
});
expect(errorSpy).toBeCalledWith(
"Warning: [antdv: Icon] The icon name 'clock-circle-o' already specify a theme 'outlined', the 'theme' prop 'filled' will be ignored.",
);
});
});
describe('`component` prop', () => {
it('can access to svg defs if has children', () => {
const wrapper = mount({
render() {
const component = {
render() {
return (
<svg>
<defs>
<linearGradient id="gradient">
<stop offset="20%" stopColor="#39F" />
<stop offset="90%" stopColor="#F3F" />
</linearGradient>
</defs>
{this.$slots.default.map(child => {
cloneElement(child, {
attrs: child.type === 'path' ? { fill: 'scriptUrl(#gradient)' } : {},
});
})}
</svg>
);
},
};
return (
<Icon class="my-home-icon" component={component}>
<title>Cool Home</title>
<path d="'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'" />
</Icon>
);
},
});
expect(wrapper.html()).toMatchSnapshot();
});
});
it('should support svg vue component', () => {
const SvgComponent = {
render() {
return (
<svg viewBox="0 0 24 24">
<title>Cool Home</title>
<path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" />
</svg>
);
},
};
const wrapper = mount({
render() {
return (
<Icon class="my-home-icon" component={SvgComponent}>
<title>Cool Home</title>
<path d="'M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z'" />
</Icon>
);
},
});
expect(wrapper.html()).toMatchSnapshot();
});
});
describe('utils', () => {
it('getThemeFromTypeName() should work', () => {
const testCases = [
'check-circle',
'check-circle-o',
'check-circle-fill',
'check-circle-twotone',
];
const result = testCases.map(type => getThemeFromTypeName(type));
expect(result).toEqual([null, 'outlined', 'filled', 'twoTone']);
});
it('withThemeSuffix() should work', () => {
const testCases = [
{ type: 'home', theme: 'filled' },
{ type: 'home', theme: 'outlined' },
{ type: 'home', theme: 'twoTone' },
{ type: 'home', theme: 'This-is-the-secret' },
{ type: 'home-o', theme: 'filled' },
{ type: 'home-fill', theme: 'outlined' },
{ type: 'home-o', theme: 'twoTone' },
{ type: 'home-o', theme: 'This-is-the-secret' },
];
const result = testCases.map(({ type, theme }) => withThemeSuffix(type, theme));
expect(result).toEqual([
'home-fill',
'home-o',
'home-twotone',
'home',
'home-o-fill',
'home-fill-o',
'home-o-twotone',
'home-o',
]);
});
});

View File

@ -1,12 +0,0 @@
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;
}

View File

@ -1,77 +0,0 @@
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, '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':
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:
}
warning(
newType === type,
'Icon',
`Icon '${type}' was a typo and is now deprecated, please use '${newType}' instead.`,
);
return newType;
}

View File

@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils';
import List from '..';
import Icon from '../../icon';
import { LoadingOutlined } from '@ant-design/icons-vue';
describe('List', () => {
it('renders empty loading', () => {
@ -34,7 +34,7 @@ describe('List', () => {
<List
loading={{
spinning: true,
indicator: <Icon type="loading" style={{ fontSize: '24px' }} spin />,
indicator: <LoadingOutlined style={{ fontSize: '24px' }} />,
}}
dataSource={[1]}
renderItem={() => <List.Item />}

View File

@ -1,7 +1,7 @@
import { mount } from '@vue/test-utils';
import { asyncExpect } from '@/tests/utils';
import Menu from '..';
import Icon from '../../icon';
import { InboxOutlined, PieChartOutlined } from '@ant-design/icons-vue';
import mountTest from '../../../tests/shared/mountTest';
jest.mock('mutationobserver-shim', () => {
@ -318,7 +318,7 @@ describe('Menu', () => {
inlineCollapsed={this.inlineCollapsed}
>
<Menu.Item key="menu1">
<Icon type="inbox" />
<InboxOutlined />
<span>Option</span>
</Menu.Item>
<SubMenu key="1" title="submenu1">
@ -388,7 +388,7 @@ describe('Menu', () => {
inlineCollapsed={this.inlineCollapsed}
>
<Menu.Item key="menu1">
<Icon type="inbox" />
<InboxOutlined />
<span>Option</span>
</Menu.Item>
<SubMenu key="1" title="submenu1">
@ -550,7 +550,7 @@ describe('Menu', () => {
return (
<Menu mode="inline" inlineCollapsed>
<Menu.Item key="1" title="bamboo lucky">
<Icon type="pie-chart" />
<PieChartOutlined />
<span>
Option 1
<img

View File

@ -3,7 +3,7 @@ import PropTypes from '../_util/vue-types';
import { getOptionProps, getComponentFromProp, getListeners } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
import VcRate from '../vc-rate';
import Icon from '../icon';
import StarFilled from '@ant-design/icons-vue/StarFilled';
import Tooltip from '../tooltip';
import Base from '../base';
@ -48,9 +48,7 @@ const Rate = {
const getPrefixCls = this.configProvider.getPrefixCls;
const prefixCls = getPrefixCls('rate', customizePrefixCls);
const character = getComponentFromProp(this, 'character') || (
<Icon type="star" theme="filled" />
);
const character = getComponentFromProp(this, 'character') || <StarFilled />;
const rateProps = {
props: {
character,

View File

@ -1,17 +1,20 @@
import PropTypes from '../_util/vue-types';
import { getComponentFromProp } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
import Icon from '../icon';
import CheckCircleFilled from '@ant-design/icons-vue/CheckCircleFilled';
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
import ExclamationCircleFilled from '@ant-design/icons-vue/ExclamationCircleFilled';
import WarningFilled from '@ant-design/icons-vue/WarningFilled';
import Base from '../base';
import noFound from './noFound';
import serverError from './serverError';
import unauthorized from './unauthorized';
export const IconMap = {
success: 'check-circle',
error: 'close-circle',
info: 'exclamation-circle',
warning: 'warning',
success: CheckCircleFilled,
error: CloseCircleFilled,
info: ExclamationCircleFilled,
warning: WarningFilled,
};
export const ExceptionMap = {
@ -41,9 +44,8 @@ const renderIcon = (h, prefixCls, { status, icon }) => {
</div>
);
}
// prop `icon` require slot or VNode
const iconString = IconMap[status];
const iconNode = icon || <Icon type={iconString} theme="filled" />;
const IconComponent = IconMap[status];
const iconNode = icon || <IconComponent />;
return <div class={`${prefixCls}-icon`}>{iconNode}</div>;
};

View File

@ -1,7 +1,7 @@
import { mount } from '@vue/test-utils';
import { asyncExpect } from '@/tests/utils';
import Select from '..';
import Icon from '../../icon';
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
import focusTest from '../../../tests/shared/focusTest';
import mountTest from '../../../tests/shared/mountTest';
@ -185,9 +185,9 @@ describe('Select', () => {
render() {
return (
<Select
removeIcon={<Icon type="close" />}
clearIcon={<Icon type="close" />}
menuItemSelectedIcon={<Icon type="close" />}
removeIcon={<CloseOutlined />}
clearIcon={<CloseOutlined />}
menuItemSelectedIcon={<CloseOutlined />}
>
<Option value="1">1</Option>
</Select>

View File

@ -10,7 +10,9 @@ import {
isValidElement,
getListeners,
} from '../_util/props-util';
import Icon from '../icon';
import CloseOutlined from '@ant-design/icons-vue/CloseOutlined';
import CloseCircleFilled from '@ant-design/icons-vue/CloseCircleFilled';
import CheckOutlined from '@ant-design/icons-vue/CheckOutlined';
import { cloneElement } from '../_util/vnode';
import Base from '../base';
@ -161,9 +163,9 @@ const Select = {
: suffixIcon;
}
if (loading) {
return <Icon type="loading" />;
return <LoadingOutlined />;
}
return <Icon type="down" class={`${prefixCls}-arrow-icon`} />;
return <DownOutlined class={`${prefixCls}-arrow-icon`} />;
},
},
render() {
@ -218,19 +220,17 @@ const Select = {
const finalRemoveIcon = (removeIcon &&
(isValidElement(removeIcon)
? cloneElement(removeIcon, { class: `${prefixCls}-remove-icon` })
: removeIcon)) || <Icon type="close" class={`${prefixCls}-remove-icon`} />;
: removeIcon)) || <CloseOutlined class={`${prefixCls}-remove-icon`} />;
const finalClearIcon = (clearIcon &&
(isValidElement(clearIcon)
? cloneElement(clearIcon, { class: `${prefixCls}-clear-icon` })
: clearIcon)) || (
<Icon type="close-circle" theme="filled" class={`${prefixCls}-clear-icon`} />
);
: clearIcon)) || <CloseCircleFilled class={`${prefixCls}-clear-icon`} />;
const finalMenuItemSelectedIcon = (menuItemSelectedIcon &&
(isValidElement(menuItemSelectedIcon)
? cloneElement(menuItemSelectedIcon, { class: `${prefixCls}-selected-icon` })
: menuItemSelectedIcon)) || <Icon type="check" class={`${prefixCls}-selected-icon`} />;
: menuItemSelectedIcon)) || <CheckOutlined class={`${prefixCls}-selected-icon`} />;
const selectProps = {
props: {

View File

@ -16,7 +16,6 @@ import BaseMixin from '../_util/BaseMixin';
import { ConfigConsumerProps } from '../config-provider';
import { TableProps } from './interface';
import Pagination from '../pagination';
import Icon from '../icon';
import Spin from '../spin';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale-provider/default';

View File

@ -7,7 +7,7 @@ import { AntdComponent } from './component';
export declare class PageHeader extends AntdComponent {
/**
* Custom backIcon
* @default <Icon type="arrow-left" />
* @default <ArrowLeftOutlined />
* @type any (string | slot)
*/
backIcon: any;

View File

@ -34,7 +34,7 @@ export declare class Popconfirm extends TooltipCommon {
/**
* customize icon of confirmation
* @default <Icon type="exclamation-circle" />
* @default <ExclamationCircleOutlined />
* @type any (VNode | slot)
*/
icon: any;

2
types/rate.d.ts vendored
View File

@ -28,7 +28,7 @@ export declare class Rate extends AntdComponent {
/**
* custom character of rate
* @default <Icon type="star" />
* @default <StarOutlined />
* @type any (String or slot="character")
*/
character: any;

View File

@ -17,7 +17,7 @@ export declare class Timeline extends AntdComponent {
/**
* Set the dot of the last ghost node when pending is true
* @default <Icon type="loading" />
* @default <LoadingOutlined />
* @type any (string | slot)
*/
pendingDot: any;