Merge branch 'master' into feature-3.6.0

This commit is contained in:
jim 2018-05-23 16:34:59 +08:00
commit af8f4dc5c3
57 changed files with 1142 additions and 335 deletions

View File

@ -8,8 +8,8 @@
[![](https://img.shields.io/travis/ant-design/ant-design.svg?style=flat-square)](https://travis-ci.org/ant-design/ant-design)
[![Codecov](https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square)](https://codecov.io/gh/ant-design/ant-design/branch/master)
[![bitHound Dependencies](https://www.bithound.io/github/ant-design/ant-design/badges/dependencies.svg)](https://www.bithound.io/github/ant-design/ant-design/master/dependencies/npm)
[![bitHound Dev Dependencies](https://www.bithound.io/github/ant-design/ant-design/badges/devDependencies.svg)](https://www.bithound.io/github/ant-design/ant-design/master/dependencies/npm)
[![bitHound [![Dependencies](https://img.shields.io/david/ant-design/ant-design.svg)](https://david-dm.org/ant-design/ant-design)
[![DevDependencies](https://img.shields.io/david/dev/ant-design/ant-design.svg)](https://david-dm.org/ant-design/ant-design#info=devDependencies&view=list)
[![npm package](https://img.shields.io/npm/v/antd.svg?style=flat-square)](https://www.npmjs.org/package/antd)
[![NPM downloads](http://img.shields.io/npm/dm/antd.svg?style=flat-square)](http://www.npmtrends.com/antd)

View File

@ -8,8 +8,8 @@
[![](https://img.shields.io/travis/ant-design/ant-design.svg?style=flat-square)](https://travis-ci.org/ant-design/ant-design)
[![Codecov](https://img.shields.io/codecov/c/github/ant-design/ant-design/master.svg?style=flat-square)](https://codecov.io/gh/ant-design/ant-design/branch/master)
[![bitHound Dependencies](https://www.bithound.io/github/ant-design/ant-design/badges/dependencies.svg)](https://www.bithound.io/github/ant-design/ant-design/master/dependencies/npm)
[![bitHound Dev Dependencies](https://www.bithound.io/github/ant-design/ant-design/badges/devDependencies.svg)](https://www.bithound.io/github/ant-design/ant-design/master/dependencies/npm)
[![Dependencies](https://img.shields.io/david/ant-design/ant-design.svg)](https://david-dm.org/ant-design/ant-design)
[![DevDependencies](https://img.shields.io/david/dev/ant-design/ant-design.svg)](https://david-dm.org/ant-design/ant-design#info=devDependencies&view=list)
[![npm package](https://img.shields.io/npm/v/antd.svg?style=flat-square)](https://www.npmjs.org/package/antd)
[![NPM downloads](http://img.shields.io/npm/dm/antd.svg?style=flat-square)](http://www.npmtrends.com/antd)

View File

@ -1,46 +0,0 @@
const availablePrefixs = ['moz', 'ms', 'webkit'];
function requestAnimationFramePolyfill() {
let lastTime = 0;
return function(callback: (n: number) => void) {
const currTime = new Date().getTime();
const timeToCall = Math.max(0, 16 - (currTime - lastTime));
const id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall);
lastTime = currTime + timeToCall;
return id;
};
}
export default function getRequestAnimationFrame() {
if (typeof window === 'undefined') {
return () => {};
}
if (window.requestAnimationFrame) {
// https://github.com/vuejs/vue/issues/4465
return window.requestAnimationFrame.bind(window);
}
const prefix = availablePrefixs.filter(key => `${key}RequestAnimationFrame` in window)[0];
return prefix
? (window as any)[`${prefix}RequestAnimationFrame`]
: requestAnimationFramePolyfill();
}
export function cancelRequestAnimationFrame(id: number) {
if (typeof window === 'undefined') {
return null;
}
if (window.cancelAnimationFrame) {
return window.cancelAnimationFrame(id);
}
const prefix = availablePrefixs.filter(key =>
`${key}CancelAnimationFrame` in window || `${key}CancelRequestAnimationFrame` in window,
)[0];
return prefix ?
(
(window as any)[`${prefix}CancelAnimationFrame`] ||
(window as any)[`${prefix}CancelRequestAnimationFrame`]
).call(this, id) : clearTimeout(id);
}

View File

@ -1,24 +0,0 @@
let animation: boolean;
function isCssAnimationSupported() {
if (animation !== undefined) {
return animation;
}
const domPrefixes = 'Webkit Moz O ms Khtml'.split(' ');
const elm = document.createElement('div');
if (elm.style.animationName !== undefined) {
animation = true;
}
if (animation !== undefined) {
for (let i = 0; i < domPrefixes.length; i++) {
if ((elm.style as any)[`${domPrefixes[i]}AnimationName`] !== undefined) {
animation = true;
break;
}
}
}
animation = animation || false;
return animation;
}
export default isCssAnimationSupported;

View File

@ -1,7 +1,5 @@
import cssAnimation from 'css-animation';
import getRequestAnimationFrame, { cancelRequestAnimationFrame } from './getRequestAnimationFrame';
const reqAnimFrame = getRequestAnimationFrame();
import raf from 'raf';
function animate(node: HTMLElement, show: boolean, done: () => void) {
let height: number;
@ -19,16 +17,16 @@ function animate(node: HTMLElement, show: boolean, done: () => void) {
},
active() {
if (requestAnimationFrameId) {
cancelRequestAnimationFrame(requestAnimationFrameId);
raf.cancel(requestAnimationFrameId);
}
requestAnimationFrameId = reqAnimFrame(() => {
requestAnimationFrameId = raf(() => {
node.style.height = `${show ? height : 0}px`;
node.style.opacity = show ? '1' : '0';
});
},
end() {
if (requestAnimationFrameId) {
cancelRequestAnimationFrame(requestAnimationFrameId);
raf.cancel(requestAnimationFrameId);
}
node.style.height = '';
node.style.opacity = '';

View File

@ -1,6 +1,4 @@
import getRequestAnimationFrame, { cancelRequestAnimationFrame } from '../_util/getRequestAnimationFrame';
const reqAnimFrame = getRequestAnimationFrame();
import raf from 'raf';
export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
let requestId: number | null;
@ -12,11 +10,11 @@ export default function throttleByAnimationFrame(fn: (...args: any[]) => void) {
const throttled = (...args: any[]) => {
if (requestId == null) {
requestId = reqAnimFrame(later(args));
requestId = raf(later(args));
}
};
(throttled as any).cancel = () => cancelRequestAnimationFrame(requestId!);
(throttled as any).cancel = () => raf.cancel(requestId!);
return throttled;
}

View File

@ -6,7 +6,7 @@ import addEventListener from 'rc-util/lib/Dom/addEventListener';
import Affix from '../affix';
import AnchorLink from './AnchorLink';
import getScroll from '../_util/getScroll';
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
import raf from 'raf';
function getDefaultContainer() {
return window;
@ -43,7 +43,6 @@ function easeInOutCubic(t: number, b: number, c: number, d: number) {
return cc / 2 * ((t -= 2) * t * t + 2) + b;
}
const reqAnimFrame = getRequestAnimationFrame();
const sharpMatcherRegx = /#([^#]+)$/;
function scrollTo(href: string, offsetTop = 0, getContainer: () => AnchorContainer, callback = () => { }) {
const container = getContainer();
@ -67,12 +66,12 @@ function scrollTo(href: string, offsetTop = 0, getContainer: () => AnchorContain
(container as HTMLElement).scrollTop = nextScrollTop;
}
if (time < 450) {
reqAnimFrame(frameFunc);
raf(frameFunc);
} else {
callback();
}
};
reqAnimFrame(frameFunc);
raf(frameFunc);
history.pushState(null, '', href);
}

View File

@ -4,9 +4,7 @@ import addEventListener from 'rc-util/lib/Dom/addEventListener';
import classNames from 'classnames';
import omit from 'omit.js';
import getScroll from '../_util/getScroll';
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
const reqAnimFrame = getRequestAnimationFrame();
import raf from 'raf';
const easeInOutCubic = (t: number, b: number, c: number, d: number) => {
const cc = c - b;
@ -64,10 +62,10 @@ export default class BackTop extends React.Component<BackTopProps, any> {
const time = timestamp - startTime;
this.setScrollTop(easeInOutCubic(time, scrollTop, 0, 450));
if (time < 450) {
reqAnimFrame(frameFunc);
raf(frameFunc);
}
};
reqAnimFrame(frameFunc);
raf(frameFunc);
(this.props.onClick || noop)(e);
}

View File

@ -1,8 +1,17 @@
import React from 'react';
import { mount } from 'enzyme';
import Badge from '../index';
import Tooltip from '../../tooltip';
describe('Badge', () => {
beforeEach(() => {
jest.useFakeTimers();
});
afterEach(() => {
jest.useRealTimers();
});
test('badge dot not scaling count > 9', () => {
const badge = mount(<Badge count={10} dot />);
expect(badge.find('.ant-card-multiple-words').length).toBe(0);
@ -17,4 +26,16 @@ describe('Badge', () => {
const badge = mount(<Badge count={10} title="Custom title" />);
expect(badge.find('.ant-scroll-number').getDOMNode().attributes.getNamedItem('title').value).toEqual('Custom title');
});
// https://github.com/ant-design/ant-design/issues/10626
it('should be composable with Tooltip', () => {
const wrapper = mount(
<Tooltip title="Fix the error">
<Badge status="error" />
</Tooltip>
);
wrapper.find('Badge').simulate('mouseenter');
jest.runAllTimers();
expect(wrapper.instance().tooltip.props.visible).toBe(true);
});
});

View File

@ -92,7 +92,7 @@ export default class Badge extends React.Component<BadgeProps, any> {
// <Badge status="success" />
if (!children && status) {
return (
<span className={badgeCls} style={styleWithOffset}>
<span {...restProps} className={badgeCls} style={styleWithOffset}>
<span className={statusCls} />
<span className={`${prefixCls}-status-text`}>{text}</span>
</span>

View File

@ -211,7 +211,7 @@ exports[`renders ./components/cascader/demo/lazy.md correctly 1`] = `
exports[`renders ./components/cascader/demo/search.md correctly 1`] = `
<span
class="ant-cascader-picker"
class="ant-cascader-picker ant-cascader-picker-show-search"
tabindex="0"
>
<span

View File

@ -12,7 +12,6 @@ export interface CascaderOptionType {
label?: React.ReactNode;
disabled?: boolean;
children?: Array<CascaderOptionType>;
__IS_FILTERED_OPTION?: boolean;
[key: string]: any;
}
@ -90,7 +89,7 @@ export interface CascaderState {
inputValue: string;
value: string[];
popupVisible: boolean | undefined;
flattenOptions: CascaderOptionType[][];
flattenOptions: CascaderOptionType[][] | undefined;
}
function highlightKeyword(str: string, keyword: string, prefixCls: string | undefined) {
@ -119,7 +118,9 @@ function defaultRenderFilteredOption(
});
}
function defaultSortFilteredOption(a: any[], b: any[], inputValue: string, names: FilledFiledNamesType) {
function defaultSortFilteredOption(
a: CascaderOptionType[], b: CascaderOptionType[], inputValue: string, names: FilledFiledNamesType,
) {
function callback(elem: CascaderOptionType) {
return (elem[names.label] as string).indexOf(inputValue) > -1;
}
@ -162,7 +163,8 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
inputValue: '',
inputFocused: false,
popupVisible: props.popupVisible,
flattenOptions: props.showSearch && this.flattenTree(props.options, props.changeOnSelect, props.filedNames),
flattenOptions:
props.showSearch ? this.flattenTree(props.options, props.changeOnSelect, props.filedNames) : undefined,
};
}
@ -180,7 +182,7 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
}
}
handleChange = (value: any, selectedOptions: any[]) => {
handleChange = (value: any, selectedOptions: CascaderOptionType[]) => {
this.setState({ inputValue: '' });
if (selectedOptions[0].__IS_FILTERED_OPTION) {
const unwrappedValue = value[0];
@ -232,7 +234,7 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
this.setState({ inputValue });
}
setValue = (value: string[], selectedOptions: any[] = []) => {
setValue = (value: string[], selectedOptions: CascaderOptionType[] = []) => {
if (!('value' in this.props)) {
this.setState({ value });
}
@ -271,9 +273,9 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
filedNames: FiledNamesType | undefined,
ancestor: CascaderOptionType[] = [],
) {
const names: FiledNamesType = getFilledFieldNames(filedNames);
let flattenOptions: any = [];
let childrenName: any = names.children;
const names: FilledFiledNamesType = getFilledFieldNames(filedNames);
let flattenOptions = [] as CascaderOptionType[][];
let childrenName = names.children;
options.forEach((option) => {
const path = ancestor.concat(option);
if (changeOnSelect || !option[childrenName] || !option[childrenName].length) {
@ -301,18 +303,18 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
render = defaultRenderFilteredOption,
sort = defaultSortFilteredOption,
} = showSearch as ShowSearchType;
const { flattenOptions, inputValue } = this.state;
const { flattenOptions = [], inputValue } = this.state;
const filtered = flattenOptions.filter((path) => filter(this.state.inputValue, path, names))
.sort((a, b) => sort(a, b, inputValue, names));
if (filtered.length > 0) {
return filtered.map((path: any) => {
return filtered.map((path: CascaderOptionType[]) => {
return {
__IS_FILTERED_OPTION: true,
path,
[names.label]: render(inputValue, path, prefixCls, names),
[names.value]: path.map((o: CascaderOptionType) => o[names.value]),
disabled: path.some((o: CascaderOptionType) => o.disabled),
disabled: path.some((o: CascaderOptionType) => !!o.disabled),
} as CascaderOptionType;
});
}
@ -359,6 +361,7 @@ export default class Cascader extends React.Component<CascaderProps, CascaderSta
[`${prefixCls}-picker-with-value`]: state.inputValue,
[`${prefixCls}-picker-disabled`]: disabled,
[`${prefixCls}-picker-${size}`]: !!size,
[`${prefixCls}-picker-show-search`]: !!showSearch,
});
// Fix bug of https://github.com/facebook/react/pull/5004

View File

@ -17,6 +17,10 @@
position: static;
}
&-picker-show-search &-input.@{ant-prefix}-input {
position: relative;
}
&-picker {
.reset-component;
position: relative;

View File

@ -19,6 +19,18 @@ There are four kinds of picker:
- RangePicker
- WeekPicker
### Localization
The default locale is en-US, if you need to use other languages, recommend to use internationalized components provided by us at the entrance. Look at: [LocaleProvider](http://ant.design/components/locale-provider/).
If there are special needs (only modifying single component language), Please use the property: local. Example: [default](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json).
```jsx
import locale from 'antd/lib/date-picker/locale/zh_CN';
<DatePicker locale={locale} />
```
**Note:** Part of locale of DatePicker, MonthPicker, RangePicker, WeekPicker is read from value. So, please set the locale of moment correctly.
```jsx

View File

@ -20,6 +20,18 @@ subtitle: 日期选择框
- RangePicker
- WeekPicker
### 国际化配置
默认配置为 en-US如果你需要设置其他语言推荐在入口处使用我们提供的国际化组件,详见:[LocaleProvider国际化](http://ant.design/components/locale-provider-cn/)。
如有特殊需求(仅修改单一组件的语言),请使用 locale 参数,参考:[默认配置](https://github.com/ant-design/ant-design/blob/master/components/date-picker/locale/example.json)。
```jsx
import locale from 'antd/lib/date-picker/locale/zh_CN';
<DatePicker locale={locale} />
```
**注意:**DatePicker、MonthPicker、RangePicker、WeekPicker 部分 locale 是从 value 中读取,所以请先正确设置 moment 的 locale。
```jsx

View File

@ -18,6 +18,8 @@ A divider line separates different content.
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| dashed | whether line is dashed | Boolean | false |
| dashed | whether line is dashed | boolean | false |
| type | direction type of divider | enum: `horizontal` `vertical` | `horizontal` |
| orientation | position of title inside divider | enum: `left` `right` `center` | `center` |
| className | className of container | string | - |
| style | style object of container | object | - |

View File

@ -24,7 +24,10 @@
margin: 24px 0;
clear: both;
}
&-horizontal&-with-text {
&-horizontal&-with-text,
&-horizontal&-with-text-left,
&-horizontal&-with-text-right {
display: table;
white-space: nowrap;
text-align: center;
@ -33,7 +36,6 @@
color: @heading-color;
font-size: @font-size-lg;
margin: 16px 0;
&:before,
&:after {
content: '';
@ -45,77 +47,43 @@
transform: translateY(50%);
}
}
&-inner-text {
display: inline-block;
padding: 0 24px;
}
&-horizontal&-with-text-left {
display: table;
white-space: nowrap;
text-align: center;
background: transparent;
font-weight: 500;
color: @heading-color;
font-size: @font-size-base;
margin: 16px 0;
&:before {
content: '';
display: table-cell;
position: relative;
top: 50%;
width: 5%;
border-top: 1px solid @border-color-split;
transform: translateY(50%);
}
&:after {
content: '';
display: table-cell;
position: relative;
top: 50%;
width: 95%;
border-top: 1px solid @border-color-split;
transform: translateY(50%);
}
&-inner-text {
&-horizontal&-with-text-left,
&-horizontal&-with-text-right {
font-size: @font-size-base;
.@{divider-prefix-cls}-inner-text {
display: inline-block;
padding: 0 10px;
}
}
&-horizontal&-with-text-left {
&:before {
top: 50%;
width: 5%;
}
&:after {
top: 50%;
width: 95%;
}
}
&-horizontal&-with-text-right {
display: table;
white-space: nowrap;
text-align: center;
background: transparent;
font-weight: 500;
color: @heading-color;
font-size: @font-size-base;
margin: 16px 0;
&:before {
content: '';
display: table-cell;
position: relative;
top: 50%;
width: 95%;
border-top: 1px solid @border-color-split;
transform: translateY(50%);
}
&:after {
content: '';
display: table-cell;
position: relative;
top: 50%;
width: 5%;
border-top: 1px solid @border-color-split;
transform: translateY(50%);
}
&-inner-text {
display: inline-block;
padding: 0 10px;
}
}
&-inner-text {
display: inline-block;
padding: 0 24px;
}
&-dashed {
background: none;
border-top: 1px dashed @border-color-split;

View File

@ -35,9 +35,9 @@ export default class DropdownButton extends React.Component<DropdownButtonProps,
onVisibleChange,
placement,
getPopupContainer,
};
} as DropDownProps;
if ('visible' in this.props) {
(dropdownProps as any).visible = visible;
dropdownProps.visible = visible;
}
return (

View File

@ -41,11 +41,13 @@ export default class Dropdown extends React.Component<DropDownProps, any> {
componentDidMount() {
const { overlay } = this.props;
const overlayProps = (overlay as any).props as any;
warning(
!overlayProps.mode || overlayProps.mode === 'vertical',
`mode="${overlayProps.mode}" is not supported for Dropdown\'s Menu.`,
);
if (overlay) {
const overlayProps = (overlay as React.ReactElement<any>).props;
warning(
!overlayProps.mode || overlayProps.mode === 'vertical',
`mode="${overlayProps.mode}" is not supported for Dropdown\'s Menu.`,
);
}
}
render() {

View File

@ -2,7 +2,12 @@ import * as React from 'react';
import classNames from 'classnames';
import RcInputNumber from 'rc-input-number';
export interface InputNumberProps {
import { Omit } from '../_util/type';
// omitting this attrs because they conflicts with the ones defined in InputNumberProps
export type OmitAttrs = 'defaultValue' | 'onChange' | 'size';
export interface InputNumberProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, OmitAttrs> {
prefixCls?: string;
min?: number;
max?: number;
@ -10,7 +15,6 @@ export interface InputNumberProps {
step?: number | string;
defaultValue?: number;
tabIndex?: number;
onKeyDown?: React.FormEventHandler<any>;
onChange?: (value: number | string | undefined) => void;
disabled?: boolean;
size?: 'large' | 'small' | 'default';

View File

@ -5,47 +5,23 @@ import omit from 'omit.js';
import Group from './Group';
import Search from './Search';
import TextArea from './TextArea';
import { Omit } from '../_util/type';
function fixControlledValue(value: undefined | null | string) {
function fixControlledValue<T>(value: T) {
if (typeof value === 'undefined' || value === null) {
return '';
}
return value;
}
export interface AbstractInputProps {
export interface InputProps extends Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size' | 'prefix'> {
prefixCls?: string;
className?: string;
defaultValue?: any;
value?: any;
tabIndex?: number;
style?: React.CSSProperties;
}
export interface InputProps extends AbstractInputProps {
placeholder?: string;
type?: string;
id?: number | string;
name?: string;
size?: 'large' | 'default' | 'small';
maxLength?: number | string;
disabled?: boolean;
readOnly?: boolean;
onPressEnter?: React.KeyboardEventHandler<HTMLInputElement>;
addonBefore?: React.ReactNode;
addonAfter?: React.ReactNode;
onPressEnter?: React.FormEventHandler<HTMLInputElement>;
onKeyDown?: React.FormEventHandler<HTMLInputElement>;
onKeyUp?: React.FormEventHandler<HTMLInputElement>;
onChange?: React.ChangeEventHandler<HTMLInputElement>;
onClick?: React.FormEventHandler<HTMLInputElement>;
onDoubleClick?: React.FormEventHandler<HTMLInputElement>;
onFocus?: React.FocusEventHandler<HTMLInputElement>;
onBlur?: React.FocusEventHandler<HTMLInputElement>;
autoComplete?: string;
prefix?: React.ReactNode;
suffix?: React.ReactNode;
spellCheck?: boolean;
autoFocus?: boolean;
}
export default class Input extends React.Component<InputProps, any> {

View File

@ -1,7 +1,6 @@
import * as React from 'react';
import omit from 'omit.js';
import classNames from 'classnames';
import { AbstractInputProps } from './Input';
import calculateNodeHeight from './calculateNodeHeight';
function onNextFrame(cb: () => void) {
@ -24,9 +23,10 @@ export interface AutoSizeType {
maxRows?: number;
}
export interface TextAreaProps extends AbstractInputProps {
export interface TextAreaProps extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {
prefixCls?: string;
autosize?: boolean | AutoSizeType;
onPressEnter?: React.FormEventHandler<any>;
onPressEnter?: React.KeyboardEventHandler<HTMLTextAreaElement>;
}
export interface TextAreaState {

View File

@ -9,13 +9,11 @@ title:
我们为 `<Input />` 输入框定义了三种尺寸(大、默认、小),高度分别为 `40px`、`32px` 和 `24px`
注意: 在表单里面,我们只使用大尺寸的输入框。
## en-US
There are three sizes of an Input box: `large` (40px)、`default` (32px) and `small` (24px).
Note: Inside of forms, only the large size is used.
````jsx
import { Input } from 'antd';

View File

@ -120638,7 +120638,7 @@ exports[`Locale Provider should display the text as ru 1`] = `
class="ant-transfer-list-header-selected"
>
<span>
0 item
0 элем.
</span>
<span
class="ant-transfer-list-header-title"
@ -120725,7 +120725,7 @@ exports[`Locale Provider should display the text as ru 1`] = `
class="ant-transfer-list-header-selected"
>
<span>
0 item
0 элем.
</span>
<span
class="ant-transfer-list-header-title"

View File

@ -29,8 +29,8 @@ export default {
Transfer: {
notFoundContent: 'Ничего не найдено',
searchPlaceholder: 'Введите название для поиска',
itemUnit: 'item',
itemsUnit: 'items',
itemUnit: 'элем.',
itemsUnit: 'элем.',
},
Select: {
notFoundContent: 'Ничего не найдено',

View File

@ -0,0 +1,804 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders ./components/mention/demo/async.md correctly 1`] = `
<div
class="ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/avatar.md correctly 1`] = `
<div
class="ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/basic.md correctly 1`] = `
<div
class="ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span>
<span
data-offset-key="123-0-0"
>
<span
data-text="true"
>
@afc163
</span>
</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/controllder-simple.md correctly 1`] = `
<div
class="ant-mention-wrapper"
>
<div
class="ant-mention-editor oneline"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span>
<span
data-offset-key="123-0-0"
>
<span
data-text="true"
>
@afc163
</span>
</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/controlled.md correctly 1`] = `
<form
class="ant-form ant-form-horizontal"
>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col-6 ant-form-item-label"
>
<label
class=""
for="control-mention"
title="Top coders"
>
Top coders
</label>
</div>
<div
class="ant-col-16 ant-form-item-control-wrapper"
>
<div
class="ant-form-item-control has-success"
>
<span
class="ant-form-item-children"
>
<div
class="ant-mention-wrapper"
>
<div
class="ant-mention-editor oneline"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span>
<span
data-offset-key="123-0-0"
>
<span
data-text="true"
>
@afc163
</span>
</span>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</span>
</div>
</div>
</div>
<div
class="ant-row ant-form-item"
>
<div
class="ant-col-14 ant-col-offset-6 ant-form-item-control-wrapper"
>
<div
class="ant-form-item-control"
>
<span
class="ant-form-item-children"
>
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Submit
</span>
</button>
   
<button
class="ant-btn"
type="button"
>
<span>
Reset
</span>
</button>
</span>
</div>
</div>
</div>
</form>
`;
exports[`renders ./components/mention/demo/custom-tag.md correctly 1`] = `
<div
class="ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="public-DraftEditorPlaceholder-root"
>
<div
class="public-DraftEditorPlaceholder-inner"
id="placeholder-123"
style="white-space:pre-wrap"
>
@someone
</div>
</div>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/multilines.md correctly 1`] = `
<div
class="ant-mention-wrapper multilines"
style="width:100%;height:100px"
>
<div
class="ant-mention-editor"
style="width:100%;height:100px"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%;height:100px"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/multiple-trigger.md correctly 1`] = `
<div
class="ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="public-DraftEditorPlaceholder-root"
>
<div
class="public-DraftEditorPlaceholder-inner"
id="placeholder-123"
style="white-space:pre-wrap"
>
input @ to mention people, # to mention tag
</div>
</div>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/placement.md correctly 1`] = `
<div
class="ant-mention-placement-top ant-mention-wrapper"
style="width:100%"
>
<div
class="ant-mention-editor oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="notranslate public-DraftEditor-content"
contenteditable="true"
role="textbox"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`renders ./components/mention/demo/popupContainer.md correctly 1`] = `
<button
class="ant-btn ant-btn-primary"
type="button"
>
<span>
Click Me
</span>
</button>
`;
exports[`renders ./components/mention/demo/readonly.md correctly 1`] = `
<div>
<div
style="margin-bottom:10px"
>
<div
class="ant-mention-wrapper disabled"
style="width:100%"
>
<div
class="ant-mention-editor readonly oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="public-DraftEditorPlaceholder-root"
>
<div
class="public-DraftEditorPlaceholder-inner"
id="placeholder-123"
style="white-space:pre-wrap"
>
this is disabled Mention
</div>
</div>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="public-DraftEditor-content"
contenteditable="false"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<input
style="width:0;opacity:0;border:0;position:absolute;left:0;top:0"
/>
</div>
</div>
</div>
</div>
<div
class="ant-mention-wrapper readonly"
style="width:100%"
>
<div
class="ant-mention-editor readonly oneline"
style="width:100%"
>
<div
class="ant-mention-toolbar"
/>
<div
class="ant-mention-editor-wrapper"
style="width:100%"
>
<div
class="DraftEditor-root"
>
<div
class="public-DraftEditorPlaceholder-root"
>
<div
class="public-DraftEditorPlaceholder-inner"
id="placeholder-123"
style="white-space:pre-wrap"
>
this is readOnly Mention
</div>
</div>
<div
class="DraftEditor-editorContainer"
>
<div
aria-describedby="placeholder-123"
class="public-DraftEditor-content"
contenteditable="false"
spellcheck="false"
style="outline:none;user-select:text;-webkit-user-select:text;white-space:pre-wrap;word-wrap:break-word"
>
<div
data-contents="true"
>
<div
class=""
data-block="true"
data-editor="123"
data-offset-key="123-0-0"
>
<div
class="public-DraftStyleDefault-block public-DraftStyleDefault-ltr"
data-offset-key="123-0-0"
>
<span
data-offset-key="123-0-0"
>
<br
data-text="true"
/>
</span>
</div>
</div>
</div>
</div>
</div>
</div>
<input
style="width:0;opacity:0;border:0;position:absolute;left:0;top:0"
/>
</div>
</div>
</div>
</div>
`;

View File

@ -1,3 +1,5 @@
import demoTest from '../../../tests/shared/demoTest';
demoTest('mention', { skip: true });
jest.mock('draft-js/lib/generateRandomKey', () => () => '123');
demoTest('mention', { skip: process.env.LIB_DIR === 'dist' });

View File

@ -0,0 +1,61 @@
import React from 'react';
import { mount } from 'enzyme';
import Mention from '..';
const { toContentState } = Mention;
describe('Mention', () => {
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
it('should has focus function', () => {
const handleFocus = jest.fn();
const wrapper = mount(
<Mention
defaultValue={toContentState('@afc163')}
onFocus={handleFocus}
suggestions={['afc163', 'benjycui', 'yiminghe', 'RaoHai', '中文', 'にほんご']}
/>
);
wrapper.instance().focus();
jest.runAllTimers();
expect(handleFocus).toBeCalled();
});
it('basic suggestion', () => {
const handleSearch = jest.fn();
const wrapper = mount(
<Mention
suggestions={['afc163', 'raohai']}
onSearchChange={handleSearch}
/>
);
wrapper.find('DraftEditorContents').simulate('focus');
const ed = wrapper.find('.public-DraftEditor-content');
ed.simulate('beforeInput', { data: '@a' });
jest.runAllTimers();
expect(handleSearch).toBeCalledWith('a', '@');
});
it('change suggestions', () => {
const container = mount(<div id="container" />);
const wrapper = mount(
<Mention suggestions={['afc163', 'raohai']} getSuggestionContainer={() => container.getDOMNode()} />
);
wrapper.find('DraftEditorContents').simulate('focus');
const ed = wrapper.find('.public-DraftEditor-content');
ed.simulate('beforeInput', { data: '@' });
jest.runAllTimers();
expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item').length).toBe(2);
expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item')[0].innerHTML).toBe('afc163');
wrapper.setState({ suggestions: ['yesmeck', 'yiminghe', 'lucy'] });
jest.runAllTimers();
expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item').length).toBe(3);
expect(container.getDOMNode().querySelectorAll('.ant-mention-dropdown-item')[0].innerHTML).toBe('yesmeck');
});
});

View File

@ -1,5 +1,5 @@
---
order: 4
order: 5
title:
zh-CN: 智能提示
en-US: Automatic completion

View File

@ -1,5 +1,5 @@
---
order: 6
order: 7
title:
zh-CN: 联动
en-US: coordinate

View File

@ -1,5 +1,5 @@
---
order: 5
order: 6
title:
zh-CN: 分组
en-US: Option Group

View File

@ -1,5 +1,5 @@
---
order: 1
order: 3
title:
zh-CN: 三种大小
en-US: Sizes

View File

@ -1,5 +1,5 @@
---
order: 3
order: 4
title:
zh-CN: 标签
en-US: Tags

View File

@ -2,7 +2,6 @@ import * as React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import Animate from 'rc-animate';
import isCssAnimationSupported from '../_util/isCssAnimationSupported';
import omit from 'omit.js';
export type SpinSize = 'small' | 'default' | 'large';
@ -57,15 +56,6 @@ export default class Spin extends React.Component<SpinProps, SpinState> {
return !!(this.props && this.props.children);
}
componentDidMount() {
if (!isCssAnimationSupported()) {
// Show text in IE9
this.setState({
notCssAnimationSupported: true,
});
}
}
componentWillUnmount() {
if (this.debounceTimeout) {
clearTimeout(this.debounceTimeout);
@ -120,13 +110,13 @@ export default class Spin extends React.Component<SpinProps, SpinState> {
render() {
const { className, size, prefixCls, tip, wrapperClassName, ...restProps } = this.props;
const { spinning, notCssAnimationSupported } = this.state;
const { spinning } = this.state;
const spinClassName = classNames(prefixCls, {
[`${prefixCls}-sm`]: size === 'small',
[`${prefixCls}-lg`]: size === 'large',
[`${prefixCls}-spinning`]: spinning,
[`${prefixCls}-show-text`]: !!tip || notCssAnimationSupported,
[`${prefixCls}-show-text`]: !!tip,
}, className);
// fix https://fb.me/react-unknown-prop

View File

@ -4,13 +4,10 @@
zoom: 1;
&:before,
&:after {
content: " ";
content: "";
display: table;
}
&:after {
clear: both;
visibility: hidden;
font-size: 0;
height: 0;
}
}

View File

@ -2945,7 +2945,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
class="ant-table-tbody"
>
<tr
class="ant-table-row ant-table-row-level-0"
class="ant-table-row editable-row ant-table-row-level-0"
>
<td
class=""
@ -2969,9 +2969,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
<td
class=""
>
<div
class="editable-row-operations"
>
<div>
<a>
Edit
</a>
@ -2979,7 +2977,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
class="ant-table-row editable-row ant-table-row-level-0"
>
<td
class=""
@ -3003,9 +3001,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
<td
class=""
>
<div
class="editable-row-operations"
>
<div>
<a>
Edit
</a>
@ -3013,7 +3009,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
class="ant-table-row editable-row ant-table-row-level-0"
>
<td
class=""
@ -3037,9 +3033,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
<td
class=""
>
<div
class="editable-row-operations"
>
<div>
<a>
Edit
</a>
@ -3047,7 +3041,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
class="ant-table-row editable-row ant-table-row-level-0"
>
<td
class=""
@ -3071,9 +3065,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
<td
class=""
>
<div
class="editable-row-operations"
>
<div>
<a>
Edit
</a>
@ -3081,7 +3073,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
class="ant-table-row editable-row ant-table-row-level-0"
>
<td
class=""
@ -3105,9 +3097,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
<td
class=""
>
<div
class="editable-row-operations"
>
<div>
<a>
Edit
</a>
@ -3115,7 +3105,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
class="ant-table-row editable-row ant-table-row-level-0"
>
<td
class=""
@ -3139,9 +3129,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
<td
class=""
>
<div
class="editable-row-operations"
>
<div>
<a>
Edit
</a>
@ -3149,7 +3137,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
class="ant-table-row editable-row ant-table-row-level-0"
>
<td
class=""
@ -3173,9 +3161,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
<td
class=""
>
<div
class="editable-row-operations"
>
<div>
<a>
Edit
</a>
@ -3183,7 +3169,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
class="ant-table-row editable-row ant-table-row-level-0"
>
<td
class=""
@ -3207,9 +3193,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
<td
class=""
>
<div
class="editable-row-operations"
>
<div>
<a>
Edit
</a>
@ -3217,7 +3201,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
class="ant-table-row editable-row ant-table-row-level-0"
>
<td
class=""
@ -3241,9 +3225,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
<td
class=""
>
<div
class="editable-row-operations"
>
<div>
<a>
Edit
</a>
@ -3251,7 +3233,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
class="ant-table-row editable-row ant-table-row-level-0"
>
<td
class=""
@ -3275,9 +3257,7 @@ exports[`renders ./components/table/demo/edit-row.md correctly 1`] = `
<td
class=""
>
<div
class="editable-row-operations"
>
<div>
<a>
Edit
</a>

View File

@ -39,9 +39,9 @@ const EditableFormRow = Form.create()(EditableRow);
class EditableCell extends React.Component {
getInput = () => {
if (this.props.inputType === 'number') {
return <InputNumber size="small" />;
return <InputNumber />;
}
return <Input size="small" />;
return <Input />;
};
render() {
const {
@ -60,20 +60,16 @@ class EditableCell extends React.Component {
return (
<td {...restProps}>
{editing ? (
<FormItem>
<FormItem style={{ margin: 0 }}>
{getFieldDecorator(dataIndex, {
rules: [
{
required: true,
message: `Please Input ${title}!`,
},
],
rules: [{
required: true,
message: `Please Input ${title}!`,
}],
initialValue: record[dataIndex],
})(this.getInput())}
</FormItem>
) : (
restProps.children
)}
) : restProps.children}
</td>
);
}}
@ -111,7 +107,7 @@ class EditableTable extends React.Component {
render: (text, record) => {
const editable = this.isEditing(record);
return (
<div className="editable-row-operations">
<div>
{editable ? (
<span>
<EditableContext.Consumer>
@ -119,6 +115,7 @@ class EditableTable extends React.Component {
<a
href="javascript:;"
onClick={() => this.save(form, record.key)}
style={{ marginRight: 8 }}
>
Save
</a>
@ -146,8 +143,8 @@ class EditableTable extends React.Component {
edit(key) {
this.setState({ editingKey: key });
}
save(from, key) {
from.validateFields((error, row) => {
save(form, key) {
form.validateFields((error, row) => {
if (error) {
return;
}
@ -199,6 +196,7 @@ class EditableTable extends React.Component {
bordered
dataSource={this.state.data}
columns={columns}
rowClassName="editable-row"
/>
);
}
@ -208,7 +206,9 @@ ReactDOM.render(<EditableTable />, mountNode);
```
```css
.editable-row-operations a {
margin-right: 8px;
.editable-row .ant-form-explain {
position: absolute;
font-size: 12px;
margin-top: -4px;
}
```

View File

@ -213,7 +213,7 @@ According to [React documentation](https://facebook.github.io/react/docs/lists-a
If `dataSource[i].key` is not provided, then you should specify the primary key of dataSource value via `rowKey`. If not, warnings like above will show in browser console.
![](https://os.alipayobjects.com/rmsportal/luLdLvhPOiRpyss.png)
![console warning](https://os.alipayobjects.com/rmsportal/luLdLvhPOiRpyss.png)
```jsx
// primary key is uid

View File

@ -213,7 +213,7 @@ class NameColumn extends Table.Column<IUser> {}
如果你的数据没有这个属性,务必使用 `rowKey` 来指定数据列的主键。若没有指定,控制台会出现以下的提示,表格组件也会出现各类奇怪的错误。
![](https://os.alipayobjects.com/rmsportal/luLdLvhPOiRpyss.png)
![控制台警告](https://os.alipayobjects.com/rmsportal/luLdLvhPOiRpyss.png)
```jsx
// 比如你的数据主键是 uid

View File

@ -93,7 +93,7 @@
height: 24px;
line-height: 24px;
display: inline-block;
vertical-align: middle;
vertical-align: top;
border: 0 none;
cursor: pointer;
outline: none;

View File

@ -79,7 +79,7 @@ export default class Upload extends React.Component<UploadProps, UploadState> {
this.progressTimer = setInterval(() => {
curPercent = getPercent(curPercent);
this.onProgress({
percent: curPercent,
percent: curPercent * 100,
}, file);
}, 200);
}

View File

@ -86,6 +86,43 @@ describe('Upload', () => {
});
});
it('should increase percent automaticly when call autoUpdateProgress in IE', (done) => {
let uploadInstance;
let lastPercent = -1;
const props = {
action: 'http://jsonplaceholder.typicode.com/posts/',
onChange: ({ file }) => {
if (file.percent === 0 && file.status === 'uploading') {
// manually call it
uploadInstance.autoUpdateProgress(0, file);
}
if (file.status === 'uploading') {
expect(file.percent).toBeGreaterThan(lastPercent);
lastPercent = file.percent;
}
if (file.status === 'done' || file.status === 'error') {
done();
}
},
};
const wrapper = mount(
<Upload {...props}>
<button>upload</button>
</Upload>
);
wrapper.find('input').simulate('change', {
target: {
files: [
{ file: 'foo.png' },
],
},
});
uploadInstance = wrapper.instance();
});
it('should not stop upload when return value of beforeUpload is not false', (done) => {
const data = jest.fn();
const props = {

View File

@ -73,7 +73,7 @@ class Avatar extends React.Component {
beforeUpload={beforeUpload}
onChange={this.handleChange}
>
{imageUrl ? <img src={imageUrl} alt="" /> : uploadButton}
{imageUrl ? <img src={imageUrl} alt="avatar" /> : uploadButton}
</Upload>
);
}

View File

@ -39,7 +39,7 @@ export function genPercentAdd() {
if (k < 0.001) {
k = 0.001;
}
return start * 100;
return start;
};
}

View File

@ -5,7 +5,7 @@ title: Customize Theme
Ant Design allows you to customize some basic design aspects in order to meet the needs of UI diversity from business and brand, including primary color, border radius, border color, etc.
![](https://zos.alipayobjects.com/rmsportal/zTFoszBtDODhXfLAazfSpYbSLSEeytoG.png)
![customized themes](https://zos.alipayobjects.com/rmsportal/zTFoszBtDODhXfLAazfSpYbSLSEeytoG.png)
## Less variables

View File

@ -5,7 +5,7 @@ title: 定制主题
Ant Design 设计规范上支持一定程度的样式定制,以满足业务和品牌上多样化的视觉需求,包括但不限于主色、圆角、边框和部分组件的视觉定制。
![](https://zos.alipayobjects.com/rmsportal/zTFoszBtDODhXfLAazfSpYbSLSEeytoG.png)
![一些配置好的主题](https://zos.alipayobjects.com/rmsportal/zTFoszBtDODhXfLAazfSpYbSLSEeytoG.png)
## 样式变量

View File

@ -179,7 +179,7 @@ If you see logs like below screenshot, you might be importing all components by
You are using a whole package of antd, please use https://www.npmjs.com/package/babel-plugin-import to reduce app bundle size.
```
> ![](https://zos.alipayobjects.com/rmsportal/GHIRszVcmjccgZRakJDQ.png)
> ![console warning](https://zos.alipayobjects.com/rmsportal/GHIRszVcmjccgZRakJDQ.png)
However, we can import individual components on demand:

View File

@ -179,7 +179,7 @@ IE8 需要配合使用 [react@0.14.x](https://facebook.github.io/react/blog/2016
You are using a whole package of antd, please use https://www.npmjs.com/package/babel-plugin-import to reduce app bundle size.
```
> ![](https://zos.alipayobjects.com/rmsportal/GHIRszVcmjccgZRakJDQ.png)
> ![控制台警告](https://zos.alipayobjects.com/rmsportal/GHIRszVcmjccgZRakJDQ.png)
可以通过以下的写法来按需加载组件。

View File

@ -133,8 +133,8 @@ module.exports = function override(config, env) {
tsLoader.options = {
getCustomTransformers: () => ({
before: [ tsImportPluginFactory({
libraryName: 'antd',
libraryDirectory: 'es',
libraryName: 'antd',
style: 'css',
}) ]
})

View File

@ -132,8 +132,8 @@ module.exports = function override(config, env) {
tsLoader.options = {
getCustomTransformers: () => ({
before: [ tsImportPluginFactory({
libraryName: 'antd',
libraryDirectory: 'es',
libraryName: 'antd',
style: 'css',
}) ]
})

View File

@ -51,6 +51,7 @@
"moment": "^2.19.3",
"omit.js": "^1.0.0",
"prop-types": "^15.5.7",
"raf": "^3.4.0",
"rc-animate": "^2.4.1",
"rc-calendar": "~9.6.0",
"rc-cascader": "~0.13.0",
@ -153,7 +154,7 @@
"react-infinite-scroller": "^1.0.15",
"react-intl": "^2.0.1",
"react-sublime-video": "^0.2.0",
"react-virtualized": "~9.18.5",
"react-virtualized": "~9.19.0",
"remark-frontmatter": "^1.1.0",
"remark-parse": "^5.0.0",
"remark-stringify": "^5.0.0",
@ -161,7 +162,7 @@
"reqwest": "^2.0.5",
"rimraf": "^2.5.4",
"scrollama": "^1.4.1",
"stylelint": "9.2.0",
"stylelint": "9.2.1",
"stylelint-config-standard": "^18.0.0",
"typescript": "~2.8.1",
"unified": "^7.0.0",

View File

@ -71,6 +71,26 @@
<script
src="https://as.alipayobjects.com/g/component/??console-polyfill/0.2.2/index.js,media-match/2.0.2/media.match.min.js"></script>
<![endif]-->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=UA-72788897-1"></script>
<script>
if (!location.port) {
// Enable Google Analytics
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-72788897-1');
// Enable Baidu tongji
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?5d9056573b37c7d6365eaff1d71d62e7";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
}
</script>
<script>
if (!window.Intl) {
document.writeln('<script src="https://as.alipayobjects.com/g/component/intl/1.0.1/??Intl.js,locale-data/jsonp/en.js,locale-data/jsonp/zh.js">' + '<' + '/script>');
@ -78,24 +98,6 @@
if (!window.Promise) {
document.writeln('<script src="https://as.alipayobjects.com/g/component/es6-promise/3.2.2/es6-promise.min.js"' + '>' + '<' + '/' + 'script>');
}
// Enable Google Analytics
if (!location.port) {
/* eslint-disable */
(function (i, s, o, g, r, a, m) {
i['GoogleAnalyticsObject'] = r;
i[r] = i[r] || function () {
(i[r].q = i[r].q || []).push(arguments)
}, i[r].l = 1 * new Date();
a = s.createElement(o),
m = s.getElementsByTagName(o)[0];
a.async = 1;
a.src = g;
m.parentNode.insertBefore(a, m)
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
ga('create', 'UA-72788897-1', 'auto');
ga('send', 'pageview');
/* eslint-enable */
}
</script>
<!-- Hotjar Tracking Code for ant.design -->
<script>

View File

@ -66,12 +66,12 @@ export default function BannerImage() {
<g stroke="none" strokeWidth="1" fill="none" fillRule="evenodd" transform="translate(0, 30)">
<g id="Group-7" transform="translate(56.000000, 124)">
<TweenOneG animation={animate.rotateY}>
<image id="cc2" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/DJWUmdpxcQakQHwhPjzf.png" width="124px" height="130px" />
<image id="cc2" alt="globe" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/DJWUmdpxcQakQHwhPjzf.png" width="124px" height="130px" />
</TweenOneG>
</g>
<g id="Group-8" transform="translate(127.000000, 82)">
<TweenOneG animation={animate.rotateR}>
<image id="cc1" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/DEaRdiYbAyVNRelJpwXx.png" width="195px" height="163px" />
<image id="cc1" alt="globe" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/DEaRdiYbAyVNRelJpwXx.png" width="195px" height="163px" />
</TweenOneG>
</g>
<g id="Group-13" transform="translate(0.000000, 41.000000)">
@ -104,18 +104,18 @@ export default function BannerImage() {
</g>
<g id="Group-9" transform="translate(322.000000, 107.000000)">
<TweenOneG style={{ transformOrigin: '50px 40px' }} animation={animate.rotateR}>
<image id="cc3" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/cCmuVrmQIJYlrhFjiPDZ.png" width="160px" height="66px" />
<image id="cc3" alt="globe" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/cCmuVrmQIJYlrhFjiPDZ.png" width="160px" height="66px" />
</TweenOneG>
</g>
<g id="Group-12" transform="translate(271.000000, 2)">
<TweenOneG style={{ transformOrigin: '125px 200px' }} animation={animate.rotate}>
<image id="cc0" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/TOElddMOrCWlgZvWTJna.png" width="184px" height="293px" />
<image id="cc0" alt="globe" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/TOElddMOrCWlgZvWTJna.png" width="184px" height="293px" />
</TweenOneG>
</g>
</TweenOneG>
<g id="Group-14" transform="translate(150.000000, 230.000000)">
<g id="Group-22" transform="translate(62.000000, 7.000000)">
<image id="cc4" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/FpKOqFadwoFFIZFExjaf.png" width="151px" height="234px" />
<image id="cc4" alt="globe" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/FpKOqFadwoFFIZFExjaf.png" width="151px" height="234px" />
</g>
<mask id="mask-2">
<use xlinkHref="#mask" fill="white" transform="translate(-42, -33)" />
@ -127,7 +127,7 @@ export default function BannerImage() {
<path d="M83.1700911,35.9320015 C63.5256194,37.9279025 44.419492,43.1766434 25.8517088,51.6782243 C14.3939956,57.7126276 7.77167019,64.8449292 7.77167019,72.4866248 C7.77167019,94.1920145 61.1993389,111.787709 127.105708,111.787709 C193.012078,111.787709 246.439746,94.1920145 246.439746,72.4866248 C246.439746,55.2822262 212.872939,40.6598106 166.13127,35.3351955" id="line-s" stroke="#0D1A26" strokeWidth="1.35" strokeLinecap="round" transform="translate(127.105708, 73.561453) rotate(-16.000000) translate(-127.105708, -73.561453) " />
</g>
<TweenOneG animation={animate.path}>
<image id="id2" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/IauKICnGjGnotJBEyCRK.png" x="16" y="62" width="26px" height="26px" />
<image alt="globe" id="id2" xlinkHref="https://gw.alipayobjects.com/zos/rmsportal/IauKICnGjGnotJBEyCRK.png" x="16" y="62" width="26px" height="26px" />
</TweenOneG>
</g>
</TweenOneG>

View File

@ -226,7 +226,7 @@ class Footer extends React.Component {
<Col md={6} sm={24} xs={24}>
<div className="footer-center">
<h2>
<img className="title-icon" src="https://gw.alipayobjects.com/zos/rmsportal/nBVXkrFdWHxbZlmMbsaH.svg" alt="" />
<img className="title-icon" src="https://gw.alipayobjects.com/zos/rmsportal/nBVXkrFdWHxbZlmMbsaH.svg" alt="AFX Cloud" />
<FormattedMessage id="app.footer.more-product" />
</h2>
<div>

View File

@ -55,11 +55,16 @@ export default class Layout extends React.Component {
}
componentDidMount() {
if (typeof window.ga !== 'undefined') {
this.context.router.listen((loc) => {
this.context.router.listen((loc) => {
if (typeof window.ga !== 'undefined') {
window.ga('send', 'pageview', loc.pathname + loc.search);
});
}
}
// eslint-disable-next-line
if (typeof window._hmt !== 'undefined') {
// eslint-disable-next-line
window._hmt.push(['_trackPageview', loc.pathname + loc.search]);
}
});
const nprogressHiddenStyle = document.getElementById('nprogress-style');
if (nprogressHiddenStyle) {

View File

@ -5,6 +5,7 @@ if (typeof window !== 'undefined') {
global.window.innerHeight = height || global.window.innerHeight;
global.window.dispatchEvent(new Event('resize'));
};
global.window.scrollTo = () => {};
}
// The built-in requestAnimationFrame and cancelAnimationFrame not working with jest.runFakeTimes()

View File

@ -96,6 +96,8 @@ declare module "prop-types";
declare module "lodash/debounce";
declare module "lodash/uniqBy"
declare module "lodash/uniqBy";
declare module 'intersperse';
declare module "raf";