Merge pull request #15775 from ant-design/merge-feature

Merge feature
This commit is contained in:
zombieJ 2019-04-01 11:07:45 +08:00 committed by GitHub
commit 550ff72e1e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
57 changed files with 3686 additions and 1016 deletions

View File

@ -0,0 +1,18 @@
import { tuple } from './type';
export const PresetColorTypes = tuple(
'pink',
'red',
'yellow',
'orange',
'cyan',
'green',
'blue',
'purple',
'geekblue',
'magenta',
'volcano',
'gold',
'lime'
);
export type PresetColorType = (typeof PresetColorTypes)[number];

View File

@ -475,6 +475,262 @@ exports[`renders ./components/badge/demo/change.md correctly 1`] = `
</div>
`;
exports[`renders ./components/badge/demo/colorful.md correctly 1`] = `
<div>
<h4
style="margin-bottom:16px"
>
Presets:
</h4>
<div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-pink"
/>
<span
class="ant-badge-status-text"
>
pink
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-red"
/>
<span
class="ant-badge-status-text"
>
red
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-yellow"
/>
<span
class="ant-badge-status-text"
>
yellow
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-orange"
/>
<span
class="ant-badge-status-text"
>
orange
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-cyan"
/>
<span
class="ant-badge-status-text"
>
cyan
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-green"
/>
<span
class="ant-badge-status-text"
>
green
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-blue"
/>
<span
class="ant-badge-status-text"
>
blue
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-purple"
/>
<span
class="ant-badge-status-text"
>
purple
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-geekblue"
/>
<span
class="ant-badge-status-text"
>
geekblue
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-magenta"
/>
<span
class="ant-badge-status-text"
>
magenta
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-volcano"
/>
<span
class="ant-badge-status-text"
>
volcano
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-gold"
/>
<span
class="ant-badge-status-text"
>
gold
</span>
</span>
</div>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot ant-badge-status-lime"
/>
<span
class="ant-badge-status-text"
>
lime
</span>
</span>
</div>
</div>
<h4
style="margin:16px 0"
>
Custom:
</h4>
<div>
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot"
style="background:#f50"
/>
<span
class="ant-badge-status-text"
>
#f50
</span>
</span>
<br />
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot"
style="background:#2db7f5"
/>
<span
class="ant-badge-status-text"
>
#2db7f5
</span>
</span>
<br />
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot"
style="background:#87d068"
/>
<span
class="ant-badge-status-text"
>
#87d068
</span>
</span>
<br />
<span
class="ant-badge ant-badge-status ant-badge-not-a-wrapper"
>
<span
class="ant-badge-status-dot"
style="background:#108ee9"
/>
<span
class="ant-badge-status-text"
>
#108ee9
</span>
</span>
</div>
</div>
`;
exports[`renders ./components/badge/demo/dot.md correctly 1`] = `
<div>
<span

View File

@ -0,0 +1,51 @@
---
order: 8
title:
zh-CN: 多彩徽标
en-US: Colorful Badge
---
## zh-CN
3.16.0 后新增。我们添加了多种预设色彩的徽标样式,用作不同场景使用。如果预设值不能满足你的需求,可以设置为具体的色值。
## en-US
New feature after 3.16.0. We preset a series of colorful Badge style for different situation usage.
And you can always set it to a hex color string for custom color.
````jsx
import { Badge } from 'antd';
const colors = ['pink', 'red', 'yellow', 'orange', 'cyan', 'green', 'blue', 'purple', 'geekblue', 'magenta', 'volcano', 'gold', 'lime'];
ReactDOM.render(
<div>
<h4 style={{ marginBottom: 16 }}>Presets:</h4>
<div>
{colors.map((color) => (
<div key={color}>
<Badge color={color} text={color} />
</div>
))}
</div>
<h4 style={{ margin: '16px 0' }}>Custom:</h4>
<div>
<Badge color="#f50" text="#f50" />
<br />
<Badge color="#2db7f5" text="#2db7f5" />
<br />
<Badge color="#87d068" text="#87d068" />
<br />
<Badge color="#108ee9" text="#108ee9" />
</div>
</div>,
mountNode
);
````
````css
.ant-tag {
margin-bottom: 8px;
}
````

View File

@ -22,13 +22,14 @@ Badge normally appears in proximity to notifications or user avatars with eye-ca
<Badge count={5} />
```
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| count | Number to show in badge | ReactNode | |
| dot | Whether to display a red dot instead of `count` | boolean | `false` |
| offset | set offset of the badge dot, like`[x, y]` | `[number, number]` | - |
| overflowCount | Max count to show | number | 99 |
| showZero | Whether to show badge when `count` is zero | boolean | `false` |
| status | Set Badge as a status dot | `success` \| `processing` \| `default` \| `error` \| `warning` | `''` |
| text | If `status` is set, `text` sets the display text of the status `dot` | string | `''` |
| title | Text to show when hovering over the badge | string | `count` |
| Property | Description | Type | Default | Version |
| -------- | ----------- | ---- | ------- | ------- |
| color | Customize Badge dot color | string | - | 3.16.0 |
| count | Number to show in badge | ReactNode | | |
| dot | Whether to display a red dot instead of `count` | boolean | `false` | |
| offset | set offset of the badge dot, like`[x, y]` | `[number, number]` | - | |
| overflowCount | Max count to show | number | 99 | |
| showZero | Whether to show badge when `count` is zero | boolean | `false` | |
| status | Set Badge as a status dot | `success` \| `processing` \| `default` \| `error` \| `warning` | `''` | |
| text | If `status` is set, `text` sets the display text of the status `dot` | string | `''` | |
| title | Text to show when hovering over the badge | string | `count` | |

View File

@ -3,6 +3,7 @@ import * as PropTypes from 'prop-types';
import Animate from 'rc-animate';
import classNames from 'classnames';
import ScrollNumber from './ScrollNumber';
import { PresetColorTypes } from '../_util/colors';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
export { ScrollNumberProps } from './ScrollNumber';
@ -20,11 +21,16 @@ export interface BadgeProps {
scrollNumberPrefixCls?: string;
className?: string;
status?: 'success' | 'processing' | 'default' | 'error' | 'warning';
color?: string;
text?: React.ReactNode;
offset?: [number | string, number | string];
title?: string;
}
function isPresetColor(color?: string): boolean {
return (PresetColorTypes as any[]).indexOf(color) !== -1;
}
export default class Badge extends React.Component<BadgeProps, any> {
static defaultProps = {
count: null,
@ -41,22 +47,27 @@ export default class Badge extends React.Component<BadgeProps, any> {
};
getBadgeClassName(prefixCls: string) {
const { className, status, children } = this.props;
const { className, children } = this.props;
return classNames(className, prefixCls, {
[`${prefixCls}-status`]: !!status,
[`${prefixCls}-status`]: this.hasStatus(),
[`${prefixCls}-not-a-wrapper`]: !children,
}) as string;
}
hasStatus(): boolean {
const { status, color } = this.props;
return !!status || !!color;
}
isZero() {
const numberedDispayCount = this.getNumberedDispayCount();
return numberedDispayCount === '0' || numberedDispayCount === 0;
}
isDot() {
const { dot, status } = this.props;
const { dot } = this.props;
const isZero = this.isZero();
return (dot && !isZero) || status;
return (dot && !isZero) || this.hasStatus();
}
isHidden() {
@ -124,7 +135,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
}
renderBadgeNumber(prefixCls: string, scrollNumberPrefixCls: string) {
const { count, status } = this.props;
const { status, count } = this.props;
const displayCount = this.getDispayCount();
const isDot = this.isDot();
@ -135,7 +146,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
[`${prefixCls}-count`]: !isDot,
[`${prefixCls}-multiple-words`]:
!isDot && count && count.toString && count.toString().length > 1,
[`${prefixCls}-status-${status}`]: !!status,
[`${prefixCls}-status-${status}`]: this.hasStatus(),
});
return hidden ? null : (
@ -167,6 +178,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
text,
offset,
title,
color,
...restProps
} = this.props;
@ -177,17 +189,22 @@ export default class Badge extends React.Component<BadgeProps, any> {
const statusText = this.renderStatusText(prefixCls);
const statusCls = classNames({
[`${prefixCls}-status-dot`]: !!status,
[`${prefixCls}-status-dot`]: this.hasStatus(),
[`${prefixCls}-status-${status}`]: !!status,
[`${prefixCls}-status-${color}`]: isPresetColor(color),
});
const statusStyle: React.CSSProperties = {};
if (color && !isPresetColor(color)) {
statusStyle.background = color;
}
// <Badge status="success" />
if (!children && status) {
if (!children && this.hasStatus()) {
const styleWithOffset = this.getStyleWithOffset();
const statusTextColor = styleWithOffset && styleWithOffset.color;
return (
<span {...restProps} className={this.getBadgeClassName(prefixCls)} style={styleWithOffset}>
<span className={statusCls} />
<span className={statusCls} style={statusStyle} />
<span style={{ color: statusTextColor }} className={`${prefixCls}-status-text`}>
{text}
</span>

View File

@ -23,13 +23,14 @@ title: Badge
<Badge count={5} />
```
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| count | 展示的数字,大于 overflowCount 时显示为 `${overflowCount}+`,为 0 时隐藏 | ReactNode | |
| dot | 不展示数字,只有一个小红点 | boolean | false |
| offset | 设置状态点的位置偏移,格式为 `[x, y]` | `[number, number]` | - |
| overflowCount | 展示封顶的数字值 | number | 99 |
| showZero | 当数值为 0 时,是否展示 Badge | boolean | false |
| status | 设置 Badge 为状态点 | Enum{ 'success', 'processing, 'default', 'error', 'warning' } | '' |
| text | 在设置了 `status` 的前提下有效,设置状态点的文本 | string | '' |
| title | 设置鼠标放在状态点上时显示的文字 | string | `count` |
| 参数 | 说明 | 类型 | 默认值 | 版本 |
| --- | --- | --- | --- | --- |
| color | 自定义小圆点的颜色 | string | - | 3.16.0 |
| count | 展示的数字,大于 overflowCount 时显示为 `${overflowCount}+`,为 0 时隐藏 | ReactNode | | |
| dot | 不展示数字,只有一个小红点 | boolean | false | |
| offset | 设置状态点的位置偏移,格式为 `[x, y]` | `[number, number]` | - | |
| overflowCount | 展示封顶的数字值 | number | 99 | |
| showZero | 当数值为 0 时,是否展示 Badge | boolean | false | |
| status | 设置 Badge 为状态点 | Enum{ 'success', 'processing, 'default', 'error', 'warning' } | '' | |
| text | 在设置了 `status` 的前提下有效,设置状态点的文本 | string | '' | |
| title | 设置鼠标放在状态点上时显示的文字 | string | `count` | |

View File

@ -94,6 +94,18 @@
&-warning {
background-color: @warning-color;
}
// mixin to iterate over colors and create CSS class for each one
.make-color-classes(@i: length(@preset-colors)) when (@i > 0) {
.make-color-classes(@i - 1);
@color: extract(@preset-colors, @i);
@darkColor: '@{color}-6';
&-@{color} {
background: @@darkColor;
}
}
.make-color-classes();
&-text {
margin-left: 8px;
color: @text-color;

View File

@ -156,7 +156,7 @@
white-space: nowrap;
text-align: center;
background-image: none;
border: @border-width-base @border-style-base transparent;
border: @btn-border-width @btn-border-style transparent;
box-shadow: @btn-shadow;
cursor: pointer;
transition: all 0.3s @ease-in-out;

View File

@ -3,8 +3,6 @@ import { mount } from 'enzyme';
import Card from '../index';
import Button from '../../button/index';
const testMethod = typeof window !== 'undefined' ? it : xit;
describe('Card', () => {
beforeAll(() => {
jest.useFakeTimers();
@ -14,30 +12,6 @@ describe('Card', () => {
jest.useRealTimers();
});
function fakeResizeWindowTo(wrapper, width) {
Object.defineProperties(wrapper.instance().container, {
offsetWidth: {
get() {
return width;
},
configurable: true,
},
});
window.resizeTo(width);
}
testMethod('resize card will trigger different padding', () => {
const wrapper = mount(<Card title="xxx">xxx</Card>);
fakeResizeWindowTo(wrapper, 1000);
jest.runAllTimers();
wrapper.update();
expect(wrapper.find('.ant-card-wider-padding').length).toBe(1);
fakeResizeWindowTo(wrapper, 800);
jest.runAllTimers();
wrapper.update();
expect(wrapper.find('.ant-card-wider-padding').length).toBe(0);
});
it('should still have padding when card which set padding to 0 is loading', () => {
const wrapper = mount(
<Card loading bodyStyle={{ padding: 0 }}>
@ -69,13 +43,6 @@ describe('Card', () => {
warnSpy.mockRestore();
});
it('unmount', () => {
const wrapper = mount(<Card>xxx</Card>);
const removeResizeEventSpy = jest.spyOn(wrapper.instance().resizeEvent, 'remove');
wrapper.unmount();
expect(removeResizeEventSpy).toHaveBeenCalled();
});
it('onTabChange should work', () => {
const tabList = [
{

View File

@ -1,6 +1,5 @@
import * as React from 'react';
import classNames from 'classnames';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import omit from 'omit.js';
import Grid from './Grid';
import Meta from './Meta';
@ -8,7 +7,6 @@ import Tabs from '../tabs';
import Row from '../row';
import Col from '../col';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { throttleByAnimationFrameDecorator } from '../_util/throttleByAnimationFrame';
import warning from '../_util/warning';
import { Omit } from '../_util/type';
@ -48,26 +46,11 @@ export interface CardProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 't
defaultActiveTabKey?: string;
}
export interface CardState {
widerPadding: boolean;
}
export default class Card extends React.Component<CardProps, CardState> {
export default class Card extends React.Component<CardProps, {}> {
static Grid: typeof Grid = Grid;
static Meta: typeof Meta = Meta;
state = {
widerPadding: false,
};
private resizeEvent: any;
private updateWiderPaddingCalled: boolean = false;
private container: HTMLDivElement;
componentDidMount() {
this.updateWiderPadding();
this.resizeEvent = addEventListener(window, 'resize', this.updateWiderPadding);
if ('noHovering' in this.props) {
warning(
!this.props.noHovering,
@ -82,42 +65,12 @@ export default class Card extends React.Component<CardProps, CardState> {
}
}
componentWillUnmount() {
if (this.resizeEvent) {
this.resizeEvent.remove();
}
(this.updateWiderPadding as any).cancel();
}
@throttleByAnimationFrameDecorator()
updateWiderPadding() {
if (!this.container) {
return;
}
// 936 is a magic card width pixel number indicated by designer
const WIDTH_BOUNDARY_PX = 936;
if (this.container.offsetWidth >= WIDTH_BOUNDARY_PX && !this.state.widerPadding) {
this.setState({ widerPadding: true }, () => {
this.updateWiderPaddingCalled = true; // first render without css transition
});
}
if (this.container.offsetWidth < WIDTH_BOUNDARY_PX && this.state.widerPadding) {
this.setState({ widerPadding: false }, () => {
this.updateWiderPaddingCalled = true; // first render without css transition
});
}
}
onTabChange = (key: string) => {
if (this.props.onTabChange) {
this.props.onTabChange(key);
}
};
saveRef = (node: HTMLDivElement) => {
this.container = node;
};
isContainGrid() {
let containGrid;
React.Children.forEach(this.props.children, (element: JSX.Element) => {
@ -174,8 +127,6 @@ export default class Card extends React.Component<CardProps, CardState> {
[`${prefixCls}-loading`]: loading,
[`${prefixCls}-bordered`]: bordered,
[`${prefixCls}-hoverable`]: this.getCompatibleHoverable(),
[`${prefixCls}-wider-padding`]: this.state.widerPadding,
[`${prefixCls}-padding-transition`]: this.updateWiderPaddingCalled,
[`${prefixCls}-contain-grid`]: this.isContainGrid(),
[`${prefixCls}-contain-tabs`]: tabList && tabList.length,
[`${prefixCls}-${size}`]: size !== 'default',
@ -274,7 +225,7 @@ export default class Card extends React.Component<CardProps, CardState> {
) : null;
const divProps = omit(others, ['onTabChange']);
return (
<div {...divProps} className={classString} ref={this.saveRef}>
<div {...divProps} className={classString}>
{head}
{coverDom}
{body}

View File

@ -172,19 +172,6 @@
}
}
&-wider-padding &-head {
padding: 0 @card-padding-wider;
}
&-wider-padding &-body {
padding: @card-padding-base @card-padding-wider;
}
&-padding-transition &-head,
&-padding-transition &-body {
transition: padding 0.3s;
}
&-type-inner &-head {
padding: 0 @card-padding-base;
background: @background-color-light;

View File

@ -1180,7 +1180,7 @@ exports[`Cascader should render not found content 1`] = `
title=""
>
<Consumer>
<Empty
<OriginEmpty
className="ant-empty-small"
image="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
>
@ -1207,7 +1207,7 @@ exports[`Cascader should render not found content 1`] = `
</div>
</LocaleReceiver>
</Consumer>
</Empty>
</OriginEmpty>
</Consumer>
</li>
</ul>

View File

@ -100,6 +100,7 @@ export default class Checkbox extends React.Component<CheckboxProps, {}> {
}
checkboxGroup.toggleOption({ label: children, value: props.value });
};
checkboxProps.name = checkboxGroup.name;
checkboxProps.checked = checkboxGroup.value.indexOf(props.value) !== -1;
checkboxProps.disabled = props.disabled || checkboxGroup.disabled;
}

View File

@ -81,6 +81,7 @@ class CheckboxGroup extends React.Component<CheckboxGroupProps, CheckboxGroupSta
toggleOption: this.toggleOption,
value: this.state.value,
disabled: this.props.disabled,
name: this.props.name,
},
};
}

View File

@ -71,6 +71,16 @@ describe('CheckboxGroup', () => {
expect(onChangeGroup).toBeCalledWith(['Apple']);
});
it('all children should have a name property', () => {
const wrapper = mount(<Checkbox.Group name="checkboxgroup" options={['Yes', 'No']} />);
expect(
wrapper.find('input[type="checkbox"]').forEach(el => {
expect(el.props().name).toEqual('checkboxgroup');
}),
);
});
it('passes prefixCls down to checkbox', () => {
const options = [{ label: 'Apple', value: 'Apple' }, { label: 'Orange', value: 'Orange' }];

View File

@ -32,6 +32,7 @@ Checkbox component.
| -------- | ----------- | ---- | ------- |
| defaultValue | Default selected value | string\[] | \[] |
| disabled | Disable all checkboxes | boolean | false |
| name | The `name` property of all `input[type="checkbox"]` children | string | - |
| options | Specifies options | string\[] | \[] |
| value | Used for setting the currently selected value. | string\[] | \[] |
| onChange | The callback function that is triggered when the state changes. | Function(checkedValue) | - |

View File

@ -33,6 +33,7 @@ title: Checkbox
| --- | --- | --- | --- |
| defaultValue | 默认选中的选项 | string\[] | \[] |
| disabled | 整组失效 | boolean | false |
| name | CheckboxGroup 下所有 `input[type="checkbox"]``name` 属性 | string | - |
| options | 指定可选项 | string\[] | \[] |
| value | 指定选中的选项 | string\[] | \[] |
| onChange | 变化时回调函数 | Function(checkedValue) | - |

View File

@ -11420,48 +11420,56 @@ exports[`ConfigProvider components Table configProvider 1`] = `
<div
class="config-table-column-sorters"
>
Name
<div
class="config-table-column-sorter"
title="Sort"
<span
class="config-table-column-title"
>
<i
aria-label="icon: caret-up"
class="anticon anticon-caret-up config-table-column-sorter-up off"
Name
</span>
<span
class="config-table-column-sorter"
>
<div
class="config-table-column-sorter-inner config-table-column-sorter-inner-full"
title="Sort"
>
<svg
aria-hidden="true"
class=""
data-icon="caret-up"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
<i
aria-label="icon: caret-up"
class="anticon anticon-caret-up config-table-column-sorter-up off"
>
<path
d="M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z"
/>
</svg>
</i>
<i
aria-label="icon: caret-down"
class="anticon anticon-caret-down config-table-column-sorter-down off"
>
<svg
aria-hidden="true"
class=""
data-icon="caret-down"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
<svg
aria-hidden="true"
class=""
data-icon="caret-up"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z"
/>
</svg>
</i>
<i
aria-label="icon: caret-down"
class="anticon anticon-caret-down config-table-column-sorter-down off"
>
<path
d="M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z"
/>
</svg>
</i>
</div>
<svg
aria-hidden="true"
class=""
data-icon="caret-down"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z"
/>
</svg>
</i>
</div>
</span>
</div>
<i
aria-label="icon: filter"
@ -11623,48 +11631,56 @@ exports[`ConfigProvider components Table normal 1`] = `
<div
class="ant-table-column-sorters"
>
Name
<div
class="ant-table-column-sorter"
title="Sort"
<span
class="ant-table-column-title"
>
<i
aria-label="icon: caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up off"
Name
</span>
<span
class="ant-table-column-sorter"
>
<div
class="ant-table-column-sorter-inner ant-table-column-sorter-inner-full"
title="Sort"
>
<svg
aria-hidden="true"
class=""
data-icon="caret-up"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
<i
aria-label="icon: caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up off"
>
<path
d="M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z"
/>
</svg>
</i>
<i
aria-label="icon: caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down off"
>
<svg
aria-hidden="true"
class=""
data-icon="caret-down"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
<svg
aria-hidden="true"
class=""
data-icon="caret-up"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z"
/>
</svg>
</i>
<i
aria-label="icon: caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down off"
>
<path
d="M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z"
/>
</svg>
</i>
</div>
<svg
aria-hidden="true"
class=""
data-icon="caret-down"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z"
/>
</svg>
</i>
</div>
</span>
</div>
<i
aria-label="icon: filter"
@ -11826,48 +11842,56 @@ exports[`ConfigProvider components Table prefixCls 1`] = `
<div
class="prefix-Table-column-sorters"
>
Name
<div
class="prefix-Table-column-sorter"
title="Sort"
<span
class="prefix-Table-column-title"
>
<i
aria-label="icon: caret-up"
class="anticon anticon-caret-up prefix-Table-column-sorter-up off"
Name
</span>
<span
class="prefix-Table-column-sorter"
>
<div
class="prefix-Table-column-sorter-inner prefix-Table-column-sorter-inner-full"
title="Sort"
>
<svg
aria-hidden="true"
class=""
data-icon="caret-up"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
<i
aria-label="icon: caret-up"
class="anticon anticon-caret-up prefix-Table-column-sorter-up off"
>
<path
d="M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z"
/>
</svg>
</i>
<i
aria-label="icon: caret-down"
class="anticon anticon-caret-down prefix-Table-column-sorter-down off"
>
<svg
aria-hidden="true"
class=""
data-icon="caret-down"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
<svg
aria-hidden="true"
class=""
data-icon="caret-up"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z"
/>
</svg>
</i>
<i
aria-label="icon: caret-down"
class="anticon anticon-caret-down prefix-Table-column-sorter-down off"
>
<path
d="M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z"
/>
</svg>
</i>
</div>
<svg
aria-hidden="true"
class=""
data-icon="caret-down"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z"
/>
</svg>
</i>
</div>
</span>
</div>
<i
aria-label="icon: filter"

View File

@ -1,7 +1,6 @@
import * as React from 'react';
import Empty from '../empty';
import { ConfigConsumer, ConfigConsumerProps } from './';
import emptyImg from './empty.svg';
import { ConfigConsumer, ConfigConsumerProps } from '.';
const renderEmpty = (componentName?: string): React.ReactNode => (
<ConfigConsumer>
@ -11,14 +10,13 @@ const renderEmpty = (componentName?: string): React.ReactNode => (
switch (componentName) {
case 'Table':
case 'List':
return <Empty image={emptyImg} className={`${prefix}-normal`} />;
return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} className={`${prefix}-normal`} />;
case 'Select':
case 'TreeSelect':
case 'Cascader':
case 'Transfer':
return <Empty image={emptyImg} className={`${prefix}-small`} />;
return <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} className={`${prefix}-small`} />;
default:
return <Empty />;
}

View File

@ -381,14 +381,28 @@ exports[`renders ./components/empty/demo/config-provider.md correctly 1`] = `
class=""
>
<div>
Name
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Age
<span
class="ant-table-column-title"
>
Age
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>
@ -470,6 +484,7 @@ exports[`renders ./components/empty/demo/customize.md correctly 1`] = `
>
<div
class="ant-empty-image"
style="height:200px"
>
<img
alt="empty"
@ -502,3 +517,24 @@ exports[`renders ./components/empty/demo/customize.md correctly 1`] = `
</div>
</div>
`;
exports[`renders ./components/empty/demo/simple.md correctly 1`] = `
<div
class="ant-empty"
>
<div
class="ant-empty-image"
style="height:40px"
>
<img
alt="No Data"
src="data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNjQiIGhlaWdodD0iNDEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoMCAxKSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj4KICAgIDxlbGxpcHNlIGZpbGw9IiNGNUY1RjUiIGN4PSIzMiIgY3k9IjMzIiByeD0iMzIiIHJ5PSI3Ii8+CiAgICA8ZyBmaWxsLXJ1bGU9Im5vbnplcm8iIHN0cm9rZT0iI0Q5RDlEOSI+CiAgICAgIDxwYXRoIGQ9Ik01NSAxMi43Nkw0NC44NTQgMS4yNThDNDQuMzY3LjQ3NCA0My42NTYgMCA0Mi45MDcgMEgyMS4wOTNjLS43NDkgMC0xLjQ2LjQ3NC0xLjk0NyAxLjI1N0w5IDEyLjc2MVYyMmg0NnYtOS4yNHoiLz4KICAgICAgPHBhdGggZD0iTTQxLjYxMyAxNS45MzFjMC0xLjYwNS45OTQtMi45MyAyLjIyNy0yLjkzMUg1NXYxOC4xMzdDNTUgMzMuMjYgNTMuNjggMzUgNTIuMDUgMzVoLTQwLjFDMTAuMzIgMzUgOSAzMy4yNTkgOSAzMS4xMzdWMTNoMTEuMTZjMS4yMzMgMCAyLjIyNyAxLjMyMyAyLjIyNyAyLjkyOHYuMDIyYzAgMS42MDUgMS4wMDUgMi45MDEgMi4yMzcgMi45MDFoMTQuNzUyYzEuMjMyIDAgMi4yMzctMS4zMDggMi4yMzctMi45MTN2LS4wMDd6IiBmaWxsPSIjRkFGQUZBIi8+CiAgICA8L2c+CiAgPC9nPgo8L3N2Zz4K"
/>
</div>
<p
class="ant-empty-description"
>
No Data
</p>
</div>
`;

View File

@ -0,0 +1,10 @@
import React from 'react';
import { mount } from 'enzyme';
import Empty from '..';
describe('Empty', () => {
it('image size should change', () => {
const wrapper = mount(<Empty imageStyle={{ height: 20 }} />);
expect(wrapper.find('.ant-empty-image').props().style.height).toBe(20);
});
});

View File

@ -7,11 +7,11 @@ title:
## zh-CN
自定义图片、描述、附属内容。
自定义图片链接、图片大小、描述、附属内容。
## en-US
Customize image, description and extra content.
Customize image source, image size, description and extra content.
```jsx
import { Empty, Button } from 'antd';
@ -19,6 +19,9 @@ import { Empty, Button } from 'antd';
ReactDOM.render(
<Empty
image="https://gw.alipayobjects.com/mdn/miniapp_social/afts/img/A*pevERLJC9v0AAAAAAAAAAABjAQAAAQ/original"
imageStyle={{
height: 200,
}}
description={
<span>
Customize <a href="#API">Description</a>
@ -27,6 +30,6 @@ ReactDOM.render(
>
<Button type="primary">Create Now</Button>
</Empty>,
mountNode
mountNode,
);
```

View File

@ -0,0 +1,23 @@
---
order: 1
title:
zh-CN: 选择图片
en-US: Chose image
---
## zh-CN
可以通过设置 image 为 Empty.PRESENTED_IMAGE_SIMPLE 选择另一种风格的图片。
## en-US
You can choose another style of image by setting image to Empty.PRESENTED_IMAGE_SIMPLE
```jsx
import { Empty } from 'antd';
ReactDOM.render(
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} imageStyle={{ height:40 }} />,
mountNode
);
```

View File

@ -11,6 +11,18 @@ Empty state placeholder.
When there is no data provided, display for friendly tips.
## Built-in image
+ Empty.PRESENTED_IMAGE_SIMPLE
<img src="https://user-images.githubusercontent.com/507615/54591679-b0ceb580-4a65-11e9-925c-ad15b4eae93d.png" height="35px">
+ Empty.PRESENTED_IMAGE_DEFAULT
<img src="https://user-images.githubusercontent.com/507615/54591670-ac0a0180-4a65-11e9-846c-e55ffce0fe7b.png" height="100px">
## API
```jsx
@ -22,4 +34,5 @@ When there is no data provided, display for friendly tips.
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| description | Customize description | string \| ReactNode | - |
| image | Customize image. Will tread as image url when string provided | string \| ReactNode | false |
| imageStyle | style of image | CSSProperties | - |
| image | Customize image. Will tread as image url when string provided. | string \| ReactNode | `Empty.PRESENTED_IMAGE_DEFAULT` |

View File

@ -1,44 +1,50 @@
import * as React from 'react';
import React from 'react';
import classNames from 'classnames';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import LocaleReceiver from '../locale-provider/LocaleReceiver';
import emptyImg from './empty.svg';
import defaultEmptyImg from './empty.svg';
import simpleEmptyImg from './simple.svg';
export interface TransferLocale {
description: string;
}
export interface EmptyProps {
prefixCls?: string;
className?: string;
style?: React.CSSProperties;
/**
* @since 3.16.0
*/
imageStyle?: React.CSSProperties;
image?: React.ReactNode;
description?: React.ReactNode;
children?: React.ReactNode;
}
const Empty: React.SFC<EmptyProps> = (props: EmptyProps) => (
const OriginEmpty: React.SFC<EmptyProps> = (props: EmptyProps) => (
<ConfigConsumer>
{({ getPrefixCls }: ConfigConsumerProps) => {
const {
className,
prefixCls: customizePrefixCls,
image,
image = defaultEmptyImg,
description,
children,
imageStyle,
...restProps
} = props;
const prefixCls = getPrefixCls('empty', customizePrefixCls);
return (
<LocaleReceiver componentName="Empty">
{(locale: TransferLocale) => {
const prefixCls = getPrefixCls('empty', customizePrefixCls);
const des = description || locale.description;
const alt = typeof des === 'string' ? des : 'empty';
let imageNode: React.ReactNode = null;
if (!image) {
imageNode = <img alt={alt} src={emptyImg} />;
} else if (typeof image === 'string') {
if (typeof image === 'string') {
imageNode = <img alt={alt} src={image} />;
} else {
imageNode = image;
@ -46,7 +52,9 @@ const Empty: React.SFC<EmptyProps> = (props: EmptyProps) => (
return (
<div className={classNames(prefixCls, className)} {...restProps}>
<div className={`${prefixCls}-image`}>{imageNode}</div>
<div className={`${prefixCls}-image`} style={imageStyle}>
{imageNode}
</div>
<p className={`${prefixCls}-description`}>{des}</p>
@ -60,4 +68,13 @@ const Empty: React.SFC<EmptyProps> = (props: EmptyProps) => (
</ConfigConsumer>
);
type EmptyType = typeof OriginEmpty & {
PRESENTED_IMAGE_DEFAULT: string;
PRESENTED_IMAGE_SIMPLE: string;
};
const Empty: EmptyType = OriginEmpty as EmptyType;
Empty.PRESENTED_IMAGE_DEFAULT = defaultEmptyImg;
Empty.PRESENTED_IMAGE_SIMPLE = simpleEmptyImg;
export default Empty;

View File

@ -12,6 +12,16 @@ cols: 1
当目前没有数据时,用于显式的用户提示。
## 内置图片 (3.16.0 以上版本)
+ Empty.PRESENTED_IMAGE_SIMPLE
<img src="https://user-images.githubusercontent.com/507615/54591679-b0ceb580-4a65-11e9-925c-ad15b4eae93d.png" height="35px">
+ Empty.PRESENTED_IMAGE_DEFAULT
<img src="https://user-images.githubusercontent.com/507615/54591670-ac0a0180-4a65-11e9-846c-e55ffce0fe7b.png" height="100px">
## API
```jsx
@ -23,4 +33,5 @@ cols: 1
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| description | 自定义描述内容 | string \| ReactNode | - |
| image | 设置显示图片,为 string 时表示自定义图片地址 | string \| ReactNode | false |
| imageStyle | 图片样式 | CSSProperties | - |
| image | 设置显示图片,为 string 时表示自定义图片地址。 | string \| ReactNode | `Empty.PRESENTED_IMAGE_DEFAULT` |

View File

Before

Width:  |  Height:  |  Size: 657 B

After

Width:  |  Height:  |  Size: 657 B

View File

@ -1757,7 +1757,14 @@ exports[`renders ./components/locale-provider/demo/all.md correctly 1`] = `
class="ant-table-column-has-actions ant-table-column-has-filters"
>
<div>
Name
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
<i
aria-label="icon: filter"
@ -1784,7 +1791,14 @@ exports[`renders ./components/locale-provider/demo/all.md correctly 1`] = `
class=""
>
<div>
Age
<span
class="ant-table-column-title"
>
Age
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>

View File

@ -46,6 +46,7 @@ More layouts with navigation: [layout](/components/layout).
| onDeselect | callback executed when a menu item is deselected, only supported for multiple mode | function({ item, key, selectedKeys }) | - |
| onOpenChange | called when open/close sub menu | function(openKeys: string\[]) | noop |
| onSelect | callback executed when a menu item is selected | function({ item, key, selectedKeys }) | none |
| overflowedIndicator | Customized icon when menu collapsed | ReactNode | - |
> More options in [rc-menu](https://github.com/react-component/menu#api)

View File

@ -54,6 +54,7 @@ export interface MenuProps {
focusable?: boolean;
onMouseEnter?: (e: MouseEvent) => void;
getPopupContainer?: (triggerNode?: HTMLElement) => HTMLElement;
overflowedIndicator?: React.ReactNode;
}
export interface MenuState {

View File

@ -47,6 +47,7 @@ subtitle: 导航菜单
| onDeselect | 取消选中时调用,仅在 multiple 生效 | function({ item, key, selectedKeys }) | - |
| onOpenChange | SubMenu 展开/关闭的回调 | function(openKeys: string\[]) | noop |
| onSelect | 被选中时调用 | function({ item, key, selectedKeys }) | 无   |
| overflowedIndicator | 自定义Menu折叠时的图标 | ReactNode | - |
> More options in [rc-menu](https://github.com/react-component/menu#api)

View File

@ -36,7 +36,9 @@ const ConfirmDialog = (props: ConfirmDialogProps) => {
'Modal',
`The property 'iconType' is deprecated. Use the property 'icon' instead.`,
);
const icon = props.icon ? props.icon : iconType;
// 支持传入{ icon: null }来隐藏`Modal.confirm`默认的Icon
const icon = props.icon === undefined ? iconType : props.icon;
const okType = props.okType || 'primary';
const prefixCls = props.prefixCls || 'ant-modal';
const contentPrefixCls = `${prefixCls}-confirm`;

View File

@ -33,7 +33,6 @@
.@{confirm-prefix-cls}-content {
margin-top: 8px;
margin-left: 38px;
color: @text-color;
font-size: @font-size-base;
}
@ -42,6 +41,11 @@
float: left;
margin-right: 16px;
font-size: 22px;
// `content` after `icon` should set marginLeft
+ .@{confirm-prefix-cls}-title + .@{confirm-prefix-cls}-content {
margin-left: 38px;
}
}
}

View File

@ -84,7 +84,7 @@
}
&-body {
padding: 24px;
padding: @modal-body-padding;
font-size: @font-size-base;
line-height: @line-height-base;
word-wrap: break-word;
@ -93,6 +93,7 @@
&-footer {
padding: @modal-footer-padding-vertical @modal-footer-padding-horizontal;
text-align: right;
background: @modal-footer-bg;
border-top: @border-width-base @border-style-base @border-color-split;
border-radius: 0 0 @border-radius-base @border-radius-base;
button + button {

View File

@ -6,11 +6,10 @@
.@{pageheader-prefix-cls} {
.reset-component;
position: relative;
padding: 16px 32px;
padding: @page-header-padding-vertical @page-header-padding-horizontal;
background: @component-background;
&.@{pageheader-prefix-cls}-has-footer {
padding: 20px 32px;
padding-bottom: 0;
}
@ -61,7 +60,7 @@
&-extra {
position: absolute;
top: 16px;
right: 32px;
right: @page-header-padding-horizontal;
> * {
margin-right: 8px;
}

View File

@ -1,12 +1,61 @@
import * as React from 'react';
import { validProgress } from './utils';
import { ProgressProps } from './progress';
import { ProgressProps, ProgressGradient, StringGradients } from './progress';
interface LineProps extends ProgressProps {
prefixCls: string;
children: React.ReactNode;
}
/**
* {
* '0%': '#afc163',
* '75%': '#009900',
* '50%': 'green', ====> '#afc163 0%, #66FF00 25%, #00CC00 50%, #009900 75%, #ffffff 100%'
* '25%': '#66FF00',
* '100%': '#ffffff'
* }
*/
export const sortGradient = (gradients: ProgressGradient) => {
let tempArr = [];
for (const [key, value] of Object.entries(gradients)) {
const formatKey = parseFloat(key.replace(/%/g, ''));
if (isNaN(formatKey)) {
return {};
}
tempArr.push({
key: formatKey,
value,
});
}
tempArr = tempArr.sort((a, b) => a.key - b.key);
return tempArr.map(({ key, value }) => `${value} ${key}%`).join(', ');
};
/**
* {
* '0%': '#afc163',
* '25%': '#66FF00',
* '50%': '#00CC00', ====> linear-gradient(to right, #afc163 0%, #66FF00 25%,
* '75%': '#009900', #00CC00 50%, #009900 75%, #ffffff 100%)
* '100%': '#ffffff'
* }
*
* Then this man came to realize the truth:
* Besides six pence, there is the moon.
* Besides bread and butter, there is the bug.
* And...
* Besides women, there is the code.
*/
export const handleGradient = (strokeColor: ProgressGradient) => {
const { from = '#1890ff', to = '#1890ff', direction = 'to right', ...rest } = strokeColor;
if (Object.keys(rest).length !== 0) {
const sortedGradients = sortGradient(rest as StringGradients);
return { backgroundImage: `linear-gradient(${direction}, ${sortedGradients})` };
}
return { backgroundImage: `linear-gradient(${direction}, ${from}, ${to})` };
};
const Line: React.SFC<LineProps> = props => {
const {
prefixCls,
@ -18,11 +67,19 @@ const Line: React.SFC<LineProps> = props => {
strokeLinecap,
children,
} = props;
let backgroundProps;
if (strokeColor && typeof strokeColor !== 'string') {
backgroundProps = handleGradient(strokeColor);
} else {
backgroundProps = {
background: strokeColor,
};
}
const percentStyle = {
width: `${validProgress(percent)}%`,
height: strokeWidth || (size === 'small' ? 6 : 8),
background: strokeColor,
borderRadius: strokeLinecap === 'square' ? 0 : '100px',
...backgroundProps,
};
const successPercentStyle = {
width: `${validProgress(successPercent)}%`,

View File

@ -632,6 +632,59 @@ exports[`renders ./components/progress/demo/format.md correctly 1`] = `
</div>
`;
exports[`renders ./components/progress/demo/gradient-line.md correctly 1`] = `
<div>
<div
class="ant-progress ant-progress-line ant-progress-status-active ant-progress-show-info ant-progress-default"
>
<div>
<div
class="ant-progress-outer"
>
<div
class="ant-progress-inner"
>
<div
class="ant-progress-bg"
style="width:99.9%;height:8px;border-radius:100px;background-image:linear-gradient(to right, #108ee9 0%, #87d068 100%)"
/>
</div>
</div>
<span
class="ant-progress-text"
title="99.9%"
>
99.9%
</span>
</div>
</div>
<div
class="ant-progress ant-progress-line ant-progress-status-active ant-progress-show-info ant-progress-default"
>
<div>
<div
class="ant-progress-outer"
>
<div
class="ant-progress-inner"
>
<div
class="ant-progress-bg"
style="width:99.9%;height:8px;border-radius:100px;background-image:linear-gradient(to right, #108ee9, #87d068)"
/>
</div>
</div>
<span
class="ant-progress-text"
title="99.9%"
>
99.9%
</span>
</div>
</div>
</div>
`;
exports[`renders ./components/progress/demo/line.md correctly 1`] = `
<div>
<div

View File

@ -245,3 +245,141 @@ exports[`Progress render strokeColor 1`] = `
</div>
</div>
`;
exports[`Progress render strokeColor 2`] = `
<Progress
gapDegree={0}
percent={50}
showInfo={true}
size="default"
strokeColor={
Object {
"from": "#108ee9",
"to": "#87d068",
}
}
strokeLinecap="round"
trailColor="#f3f3f3"
type="line"
>
<Consumer>
<div
className="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default"
>
<Line
gapDegree={0}
percent={50}
prefixCls="ant-progress"
showInfo={true}
size="default"
strokeColor={
Object {
"from": "#108ee9",
"to": "#87d068",
}
}
strokeLinecap="round"
trailColor="#f3f3f3"
type="line"
>
<div>
<div
className="ant-progress-outer"
>
<div
className="ant-progress-inner"
>
<div
className="ant-progress-bg"
style={
Object {
"backgroundImage": "linear-gradient(to right, #108ee9, #87d068)",
"borderRadius": "100px",
"height": 8,
"width": "50%",
}
}
/>
</div>
</div>
<span
className="ant-progress-text"
title="50%"
>
50%
</span>
</div>
</Line>
</div>
</Consumer>
</Progress>
`;
exports[`Progress render strokeColor 3`] = `
<Progress
gapDegree={0}
percent={50}
showInfo={true}
size="default"
strokeColor={
Object {
"0%": "#108ee9",
"100%": "#87d068",
}
}
strokeLinecap="round"
trailColor="#f3f3f3"
type="line"
>
<Consumer>
<div
className="ant-progress ant-progress-line ant-progress-status-normal ant-progress-show-info ant-progress-default"
>
<Line
gapDegree={0}
percent={50}
prefixCls="ant-progress"
showInfo={true}
size="default"
strokeColor={
Object {
"0%": "#108ee9",
"100%": "#87d068",
}
}
strokeLinecap="round"
trailColor="#f3f3f3"
type="line"
>
<div>
<div
className="ant-progress-outer"
>
<div
className="ant-progress-inner"
>
<div
className="ant-progress-bg"
style={
Object {
"backgroundImage": "linear-gradient(to right, #108ee9 0%, #87d068 100%)",
"borderRadius": "100px",
"height": 8,
"width": "50%",
}
}
/>
</div>
</div>
<span
className="ant-progress-text"
title="50%"
>
50%
</span>
</div>
</Line>
</div>
</Consumer>
</Progress>
`;

View File

@ -1,6 +1,7 @@
import React from 'react';
import { mount } from 'enzyme';
import Progress from '..';
import { handleGradient, sortGradient } from '../Line';
describe('Progress', () => {
it('successPercent should decide the progress status when it exists', () => {
@ -48,10 +49,41 @@ describe('Progress', () => {
it('render strokeColor', () => {
const wrapper = mount(<Progress type="circle" percent={50} strokeColor="red" />);
expect(wrapper.render()).toMatchSnapshot();
wrapper.setProps({
strokeColor: {
from: '#108ee9',
to: '#87d068',
},
type: 'line',
});
expect(wrapper).toMatchSnapshot();
wrapper.setProps({
strokeColor: {
'0%': '#108ee9',
'100%': '#87d068',
},
});
expect(wrapper).toMatchSnapshot();
});
it('render normal progress', () => {
const wrapper = mount(<Progress status="normal" />);
expect(wrapper.render()).toMatchSnapshot();
});
it('get correct line-gradient', () => {
expect(handleGradient({ from: 'test', to: 'test' }).backgroundImage).toBe(
'linear-gradient(to right, test, test)',
);
expect(handleGradient({}).backgroundImage).toBe('linear-gradient(to right, #1890ff, #1890ff)');
expect(handleGradient({ from: 'test', to: 'test', '0%': 'test' }).backgroundImage).toBe(
'linear-gradient(to right, test 0%)',
);
});
it('sort gradients correctly', () => {
expect(sortGradient({ '10%': 'test10', '30%': 'test30', '20%': 'test20' })).toBe(
'test10 10%, test20 20%, test30 30%',
);
});
});

View File

@ -0,0 +1,41 @@
---
order: 11
title:
zh-CN: 自定义进度条渐变色
en-US: Custom line gradient
---
## zh-CN
`linear-gradient` 的封装。推荐只传两种颜色。
## en-US
A package of `linear-gradient`. It is recommended to only pass two colors.
````jsx
import { Progress } from 'antd';
const Demo = () => (
<div>
<Progress
strokeColor={{
'0%': '#108ee9',
'100%': '#87d068',
}}
percent={99.9}
status="active"
/>
<Progress
strokeColor={{
from: '#108ee9',
to: '#87d068',
}}
percent={99.9}
status="active"
/>
</div>
);
ReactDOM.render(<Demo />, mountNode);
````

View File

@ -33,6 +33,7 @@ Properties that shared by all types.
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| strokeWidth | to set the width of the progress bar, unit: `px` | number | 10 |
| strokeColor | color of progress bar, render `linear-gradient` when passing an object | string \| { from: string; to: string; direction: string } | - |
### `type="circle"`

View File

@ -34,6 +34,7 @@ title: Progress
| 属性 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| strokeWidth | 进度条线的宽度,单位 px | number | 10 |
| strokeColor | 进度条的色彩,传入 object 时为渐变 | string \| { from: string; to: string; direction: string } | - |
### `type="circle"`

View File

@ -12,7 +12,9 @@ const ProgressTypes = tuple('line', 'circle', 'dashboard');
export type ProgressType = (typeof ProgressTypes)[number];
const ProgressStatuses = tuple('normal', 'exception', 'active', 'success');
export type ProgressSize = 'default' | 'small';
export type StringGradients = { [percentage: string]: string };
type FromToGradients = { from: string; to: string };
export type ProgressGradient = { direction?: string } & (StringGradients | FromToGradients);
export interface ProgressProps {
prefixCls?: string;
className?: string;
@ -24,7 +26,7 @@ export interface ProgressProps {
showInfo?: boolean;
strokeWidth?: number;
strokeLinecap?: string;
strokeColor?: string;
strokeColor?: string | ProgressGradient;
trailColor?: string;
width?: number;
style?: React.CSSProperties;
@ -33,7 +35,7 @@ export interface ProgressProps {
size?: ProgressSize;
}
export default class Progress extends React.Component<ProgressProps, {}> {
export default class Progress extends React.Component<ProgressProps> {
static defaultProps = {
type: 'line',
percent: 0,
@ -52,7 +54,7 @@ export default class Progress extends React.Component<ProgressProps, {}> {
width: PropTypes.number,
strokeWidth: PropTypes.number,
strokeLinecap: PropTypes.oneOf(['round', 'square']),
strokeColor: PropTypes.string,
strokeColor: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
trailColor: PropTypes.string,
format: PropTypes.func,
gapDegree: PropTypes.number,

View File

@ -144,3 +144,6 @@
@gold-8: color(~`colorPalette('@{gold-6}', 8) `);
@gold-9: color(~`colorPalette('@{gold-6}', 9) `);
@gold-10: color(~`colorPalette('@{gold-6}', 10) `);
@preset-colors: pink, magenta, red, volcano, orange, yellow, gold, cyan, lime, green, blue, geekblue,
purple;

View File

@ -141,6 +141,8 @@
@btn-font-weight: 400;
@btn-border-radius-base: @border-radius-base;
@btn-border-radius-sm: @border-radius-base;
@btn-border-width: @border-width-base;
@btn-border-style: @border-style-base;
@btn-shadow: 0 2px 0 rgba(0, 0, 0, 0.015);
@btn-primary-shadow: 0 2px 0 rgba(0, 0, 0, 0.045);
@btn-text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.12);
@ -342,7 +344,9 @@
// Modal
// --
@modal-body-padding: 24px;
@modal-header-bg: @component-background;
@modal-footer-bg: tranparent;
@modal-mask-bg: fade(@black, 65%);
// Progress
@ -429,7 +433,6 @@
@card-head-padding: 16px;
@card-inner-head-padding: 12px;
@card-padding-base: 24px;
@card-padding-wider: 32px;
@card-actions-background: @background-color-light;
@card-background: #cfd8dc;
@card-shadow: 0 2px 8px rgba(0, 0, 0, 0.09);
@ -500,6 +503,11 @@
@pagination-font-weight-active: 500;
@pagination-item-bg-active: transparent;
// PageHeader
// ---
@page-header-padding-horizontal: 24px;
@page-header-padding-vertical: 16px;
// Breadcrumb
// ---
@breadcrumb-base-color: @text-color-secondary;

View File

@ -884,7 +884,14 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
);
sortButton = (
<div title={locale.sortTitle} className={`${prefixCls}-column-sorter`} key="sorter">
<div
title={locale.sortTitle}
className={classNames(
`${prefixCls}-column-sorter-inner`,
ascend && descend && `${prefixCls}-column-sorter-inner-full`,
)}
key="sorter"
>
{ascend}
{descend}
</div>
@ -919,8 +926,10 @@ export default class Table<T> extends React.Component<TableProps<T>, TableState<
}),
title: [
<div key="title" className={sortButton ? `${prefixCls}-column-sorters` : undefined}>
{this.renderColumnTitle(column.title)}
{sortButton}
<span className={`${prefixCls}-column-title`}>
{this.renderColumnTitle(column.title)}
</span>
<span className={`${prefixCls}-column-sorter`}>{sortButton}</span>
</div>,
filterDropdown,
],

View File

@ -97,7 +97,14 @@ exports[`Table.filter renders filter correctly 1`] = `
class="ant-table-column-has-actions ant-table-column-has-filters"
>
<div>
Name
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
<i
aria-label="icon: filter"

View File

@ -33,7 +33,14 @@ exports[`Table.pagination Accepts pagination as true 1`] = `
class=""
>
<div>
Name
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>
@ -210,7 +217,14 @@ exports[`Table.pagination renders pagination correctly 1`] = `
class=""
>
<div>
Name
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>

View File

@ -39,32 +39,46 @@ exports[`Table.rowSelection fix selection column on the left 1`] = `
class="ant-table-fixed-columns-in-body ant-table-selection-column"
>
<div>
<div
class="ant-table-selection"
<span
class="ant-table-column-title"
>
<label
class="ant-checkbox-wrapper"
<div
class="ant-table-selection"
>
<span
class="ant-checkbox"
<label
class="ant-checkbox-wrapper"
>
<input
class="ant-checkbox-input"
type="checkbox"
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</div>
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</div>
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Name
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>
@ -242,25 +256,32 @@ exports[`Table.rowSelection fix selection column on the left 1`] = `
class="ant-table-selection-column"
>
<div>
<div
class="ant-table-selection"
<span
class="ant-table-column-title"
>
<label
class="ant-checkbox-wrapper"
<div
class="ant-table-selection"
>
<span
class="ant-checkbox"
<label
class="ant-checkbox-wrapper"
>
<input
class="ant-checkbox-input"
type="checkbox"
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</div>
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
</div>
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>

View File

@ -11,48 +11,56 @@ exports[`Table.sorter renders sorter icon correctly 1`] = `
<div
class="ant-table-column-sorters"
>
Name
<div
class="ant-table-column-sorter"
title="Sort"
<span
class="ant-table-column-title"
>
<i
aria-label="icon: caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up off"
Name
</span>
<span
class="ant-table-column-sorter"
>
<div
class="ant-table-column-sorter-inner ant-table-column-sorter-inner-full"
title="Sort"
>
<svg
aria-hidden="true"
class=""
data-icon="caret-up"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
<i
aria-label="icon: caret-up"
class="anticon anticon-caret-up ant-table-column-sorter-up off"
>
<path
d="M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z"
/>
</svg>
</i>
<i
aria-label="icon: caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down off"
>
<svg
aria-hidden="true"
class=""
data-icon="caret-down"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
<svg
aria-hidden="true"
class=""
data-icon="caret-up"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M858.9 689L530.5 308.2c-9.4-10.9-27.5-10.9-37 0L165.1 689c-12.2 14.2-1.2 35 18.5 35h656.8c19.7 0 30.7-20.8 18.5-35z"
/>
</svg>
</i>
<i
aria-label="icon: caret-down"
class="anticon anticon-caret-down ant-table-column-sorter-down off"
>
<path
d="M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z"
/>
</svg>
</i>
</div>
<svg
aria-hidden="true"
class=""
data-icon="caret-down"
fill="currentColor"
height="1em"
viewBox="0 0 1024 1024"
width="1em"
>
<path
d="M840.4 300H183.6c-19.7 0-30.7 20.8-18.5 35l328.4 380.8c9.4 10.9 27.5 10.9 37 0L858.9 335c12.2-14.2 1.2-35-18.5-35z"
/>
</svg>
</i>
</div>
</span>
</div>
</th>
</tr>

View File

@ -36,7 +36,14 @@ exports[`Table renders JSX correctly 1`] = `
colspan="2"
>
<div>
Name
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
@ -44,7 +51,14 @@ exports[`Table renders JSX correctly 1`] = `
rowspan="2"
>
<div>
Age
<span
class="ant-table-column-title"
>
Age
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>
@ -53,14 +67,28 @@ exports[`Table renders JSX correctly 1`] = `
class=""
>
<div>
First Name
<span
class="ant-table-column-title"
>
First Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Last Name
<span
class="ant-table-column-title"
>
Last Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>

File diff suppressed because it is too large Load Diff

View File

@ -40,56 +40,112 @@ exports[`Table renders empty table 1`] = `
class=""
>
<div>
Column 1
<span
class="ant-table-column-title"
>
Column 1
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 2
<span
class="ant-table-column-title"
>
Column 2
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 3
<span
class="ant-table-column-title"
>
Column 3
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 4
<span
class="ant-table-column-title"
>
Column 4
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 5
<span
class="ant-table-column-title"
>
Column 5
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 6
<span
class="ant-table-column-title"
>
Column 6
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 7
<span
class="ant-table-column-title"
>
Column 7
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 8
<span
class="ant-table-column-title"
>
Column 8
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>
@ -167,56 +223,112 @@ exports[`Table renders empty table with custom emptyText 1`] = `
class=""
>
<div>
Column 1
<span
class="ant-table-column-title"
>
Column 1
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 2
<span
class="ant-table-column-title"
>
Column 2
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 3
<span
class="ant-table-column-title"
>
Column 3
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 4
<span
class="ant-table-column-title"
>
Column 4
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 5
<span
class="ant-table-column-title"
>
Column 5
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 6
<span
class="ant-table-column-title"
>
Column 6
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 7
<span
class="ant-table-column-title"
>
Column 7
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 8
<span
class="ant-table-column-title"
>
Column 8
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>
@ -290,77 +402,154 @@ exports[`Table renders empty table with fixed columns 1`] = `
class="ant-table-fixed-columns-in-body"
>
<div>
Full Name
<span
class="ant-table-column-title"
>
Full Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class="ant-table-fixed-columns-in-body"
>
<div>
Age
<span
class="ant-table-column-title"
>
Age
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 1
<span
class="ant-table-column-title"
>
Column 1
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 2
<span
class="ant-table-column-title"
>
Column 2
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 3
<span
class="ant-table-column-title"
>
Column 3
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 4
<span
class="ant-table-column-title"
>
Column 4
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 5
<span
class="ant-table-column-title"
>
Column 5
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 6
<span
class="ant-table-column-title"
>
Column 6
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 7
<span
class="ant-table-column-title"
>
Column 7
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 8
<span
class="ant-table-column-title"
>
Column 8
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class="ant-table-fixed-columns-in-body"
>
<div>
Action
<span
class="ant-table-column-title"
>
Action
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>
@ -421,14 +610,28 @@ exports[`Table renders empty table with fixed columns 1`] = `
class=""
>
<div>
Full Name
<span
class="ant-table-column-title"
>
Full Name
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Age
<span
class="ant-table-column-title"
>
Age
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>
@ -466,7 +669,14 @@ exports[`Table renders empty table with fixed columns 1`] = `
class=""
>
<div>
Action
<span
class="ant-table-column-title"
>
Action
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>
@ -547,56 +757,112 @@ exports[`Table renders empty table without emptyText when loading 1`] = `
class=""
>
<div>
Column 1
<span
class="ant-table-column-title"
>
Column 1
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 2
<span
class="ant-table-column-title"
>
Column 2
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 3
<span
class="ant-table-column-title"
>
Column 3
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 4
<span
class="ant-table-column-title"
>
Column 4
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 5
<span
class="ant-table-column-title"
>
Column 5
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 6
<span
class="ant-table-column-title"
>
Column 6
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 7
<span
class="ant-table-column-title"
>
Column 7
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
<th
class=""
>
<div>
Column 8
<span
class="ant-table-column-title"
>
Column 8
</span>
<span
class="ant-table-column-sorter"
/>
</div>
</th>
</tr>

View File

@ -69,30 +69,43 @@
}
.@{table-prefix-cls}-column-sorter {
position: absolute;
top: 50%;
right: 6px;
width: 14px;
height: @font-size-lg + 1px;
margin-top: -(@font-size-lg + 1px) / 2;
color: @table-header-icon-color;
text-align: center;
transition: all 0.3s;
display: table-cell;
vertical-align: middle;
&-up,
&-down {
.iconfont-size-under-12px(11px);
display: block;
height: 4px;
line-height: 4px;
.@{table-prefix-cls}-column-sorter-inner {
height: 1em;
margin-top: 0.35em;
margin-left: 0.57142857em;
color: @table-header-icon-color;
line-height: 1em;
text-align: center;
transition: all 0.3s;
&.on {
color: @primary-color;
}
}
&-down {
margin-top: 4px;
.@{table-prefix-cls}-column-sorter-up,
.@{table-prefix-cls}-column-sorter-down {
.iconfont-size-under-12px(11px);
display: block;
height: 1em;
line-height: 1em;
transition: all 0.3s;
&.on {
color: @primary-color;
}
}
&-full {
margin-top: -0.15em;
.@{table-prefix-cls}-column-sorter-up,
.@{table-prefix-cls}-column-sorter-down {
height: 0.5em;
line-height: 0.5em;
}
.@{table-prefix-cls}-column-sorter-down {
margin-top: 0.125em;
}
}
}
}
@ -110,7 +123,7 @@
background: @table-header-filter-active-bg;
}
}
// Very complicated styles logic but neccessary
// Very complicated styles logic but necessary
&:hover {
.@{iconfont-css-prefix}-filter,
.@{table-prefix-cls}-filter-icon {
@ -154,6 +167,13 @@
}
.@{table-prefix-cls}-column-sorters {
display: table;
> .@{table-prefix-cls}-column-title {
display: table-cell;
vertical-align: middle;
}
> *:not(.@{table-prefix-cls}-column-sorter) {
position: relative;
}
@ -172,10 +192,6 @@
}
}
&.@{table-prefix-cls}-column-has-filters .@{table-prefix-cls}-column-sorter {
right: 28px + 6px;
}
&.@{table-prefix-cls}-column-has-sorters {
user-select: none;
}

View File

@ -5,6 +5,7 @@ import { polyfill } from 'react-lifecycles-compat';
import Icon from '../icon';
import CheckableTag from './CheckableTag';
import { ConfigConsumer, ConfigConsumerProps } from '../config-provider';
import { PresetColorTypes } from '../_util/colors';
import Wave from '../_util/wave';
import warning from '../_util/warning';
@ -25,6 +26,8 @@ interface TagState {
visible: boolean;
}
const PresetColorRegex = new RegExp(`^(${PresetColorTypes.join('|')})(-inverse)?$`);
class Tag extends React.Component<TagProps, TagState> {
static CheckableTag = CheckableTag;
static defaultProps = {
@ -78,9 +81,7 @@ class Tag extends React.Component<TagProps, TagState> {
if (!color) {
return false;
}
return /^(pink|red|yellow|orange|cyan|green|blue|purple|geekblue|magenta|volcano|gold|lime)(-inverse)?$/.test(
color,
);
return PresetColorRegex.test(color);
}
getTagStyle() {

View File

@ -81,13 +81,10 @@
display: none;
}
@colors: pink, magenta, red, volcano, orange, yellow, gold, cyan, lime, green, blue, geekblue,
purple;
// mixin to iterate over colors and create CSS class for each one
.make-color-classes(@i: length(@colors)) when (@i > 0) {
.make-color-classes(@i: length(@preset-colors)) when (@i > 0) {
.make-color-classes(@i - 1);
@color: extract(@colors, @i);
@color: extract(@preset-colors, @i);
@lightColor: '@{color}-1';
@lightBorderColor: '@{color}-3';
@darkColor: '@{color}-6';