Merge from master

This commit is contained in:
afc163 2017-08-19 12:40:40 +08:00
commit d4171badfd
76 changed files with 465 additions and 343 deletions

View File

@ -1,5 +1,6 @@
components/**/*.js
components/**/*.jsx
components/*/__tests__/type.tsx
!.eslintrc.js
!components/*/__tests__/*
!components/*/__tests__/**/*.js
!components/*/demo/*

View File

@ -2,13 +2,9 @@ const libDir = process.env.LIB_DIR;
const transformIgnorePatterns = [
'/dist/',
'/node_modules/reqwest',
'node_modules\/[^/]+?\/(?!(es|node_modules)\/)', // Ignore modules without es dir
];
if (libDir !== 'es') {
transformIgnorePatterns.push('/node_modules/');
}
module.exports = {
setupFiles: [
'./tests/setup.js',
@ -30,9 +26,9 @@ module.exports = {
'node',
],
transform: {
'\\.tsx?$': './node_modules/typescript-babel-jest',
'\\.js$': './node_modules/babel-jest',
'\\.md$': './node_modules/antd-demo-jest',
'\\.tsx?$': './node_modules/antd-tools/lib/jest/codePreprocessor',
'\\.js$': './node_modules/antd-tools/lib/jest/codePreprocessor',
'\\.md$': './node_modules/antd-tools/lib/jest/demoPreprocessor',
},
testRegex: libDir === 'dist' ? 'demo\\.test\\.js$' : '.*\\.test\\.js$',
collectCoverageFrom: [
@ -40,6 +36,7 @@ module.exports = {
'!components/*/style/index.tsx',
'!components/style/index.tsx',
'!components/*/locale/index.tsx',
'!components/*/__tests__/**/type.tsx',
],
transformIgnorePatterns,
snapshotSerializers: [

View File

@ -9,9 +9,9 @@ module.exports = {
'md',
],
transform: {
'\\.tsx?$': './node_modules/typescript-babel-jest',
'\\.js$': './node_modules/babel-jest',
'\\.md$': './node_modules/antd-demo-jest',
'\\.tsx?$': './node_modules/antd-tools/lib/jest/codePreprocessor',
'\\.js$': './node_modules/antd-tools/lib/jest/codePreprocessor',
'\\.md$': './node_modules/antd-tools/lib/jest/demoPreprocessor',
},
testRegex: 'demo\\.test\\.js$',
testEnvironment: 'node',

View File

@ -31,10 +31,7 @@ If you want to read change logs before `2.0.0`, please visit [GitHub](https://gi
- Layout
- Fix stretched layout by content. [500b222](https://github.com/ant-design/ant-design/commit/500b2225567f03397d9faec5f4e60a8f35fc4d28)
- Fix the collapse trigger's position. [f689ede](https://github.com/ant-design/ant-design/commit/f689ede0fa836dd0d99f4e4d96e0c43d0ff19742)
- Upload
- Fix doesn't handle some error scenarios which response is not a string. [#6818](https://github.com/ant-design/ant-design/issues/6818)
- Fix `listType` prop of docs. [#7175](https://github.com/ant-design/ant-design/pull/7175) [@zheeeng](https://github.com/zheeeng)
- Add `onChange` prop of docs. [#7180](https://github.com/ant-design/ant-design/pull/7180) [@hansnow](https://github.com/hansnow)
- Fix Upload doesn't handle some error scenarios which response is not a string. [#6818](https://github.com/ant-design/ant-design/issues/6818)
- Form
- Add `validateFirst` prop of docs. [#6959](https://github.com/ant-design/ant-design/issues/6959)
- Fix `wrappedComponentRef`. [#6545](https://github.com/ant-design/ant-design/issues/6545)

View File

@ -31,10 +31,7 @@ timeline: true
- Layout
- 修复了组件的拉伸展示问题。[500b222](https://github.com/ant-design/ant-design/commit/500b2225567f03397d9faec5f4e60a8f35fc4d28)
- 修复了折叠箭头的位置。[f689ede](https://github.com/ant-design/ant-design/commit/f689ede0fa836dd0d99f4e4d96e0c43d0ff19742)
- Upload
- 修复了 response 在不是 string 的情况下没有处理错误提示信息的问题。[#6818](https://github.com/ant-design/ant-design/issues/6818)
- 修复了 `listType` 的文档说明。[#7175](https://github.com/ant-design/ant-design/pull/7175) [@zheeeng](https://github.com/zheeeng)
- 调整了文档 `onChange` 的说明。[#7180](https://github.com/ant-design/ant-design/pull/7180) [@hansnow](https://github.com/hansnow)
- 修复了 Upload 的 response 不是 string 的情况下没有处理错误提示信息的问题。[#6818](https://github.com/ant-design/ant-design/issues/6818)
- Form
- 补充了文档中缺少的 `validateFirst` 属性描述。[#6959](https://github.com/ant-design/ant-design/issues/6959)
- 修复了 `wrappedComponentRef`。[#6545](https://github.com/ant-design/ant-design/issues/6545)

View File

@ -56,7 +56,7 @@ ReactDOM.render(<DatePicker />, mountNode);
import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
```
按需加载可通过此写法 `import DatePicker from 'antd/lib/date-picker'` 或使用插件 [babel-plugin-import](https://github.com/ant-design/babel-plugin-import)。
按需加载可通过此写法 `import DatePicker from 'antd/lib/date-picker'` 或使用 Babel 插件 [babel-plugin-import](https://github.com/ant-design/babel-plugin-import),或使用 TypeScript 插件 [ts-import-plugin](https://github.com/Brooooooklyn/ts-import-plugin)。
## TypeScript

View File

@ -35,7 +35,7 @@ An enterprise-class UI design language and React-based implementation.
## Let's build a better antd together [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
`antd` is an open source project, improvements are welcomed. If you are interested in contributing to `antd`, you can watch this repository, join in [discussion](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3ADiscussion), or try to implement some [features which have been accepted](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22PR+welcome%22). Actually, there are [many ways](https://opensource.guide/how-to-contribute/) to contribute. And we are always happy to [offer collaborator permission](https://github.com/ant-design/ant-design/issues/3222) for some active contributors.
`antd` is an open source project; improvements are welcomed. If you are interested in contributing to `antd`, you can watch this repository, join in [discussion](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3ADiscussion), or try to implement some [features which have been accepted](https://github.com/ant-design/ant-design/issues?q=is%3Aopen+is%3Aissue+label%3A%22PR+welcome%22). Actually, there are [many ways](https://opensource.guide/how-to-contribute/) to contribute. And we are always happy to [offer collaborator permission](https://github.com/ant-design/ant-design/issues/3222) for some active contributors.
## Install
@ -101,6 +101,19 @@ import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
> - set `allowSyntheticDefaultImports` to prevent `error TS1192: Module 'react' has no default export`.
> - Don't use @types/antd, antd provide a built-in ts definition already.
#### Use [ts-import-plugin](https://github.com/Brooooooklyn/ts-import-plugin) with modularized antd
```js
{
loader: "ts-loader", // or awesome-typescript-loader
options {
getCustomTransformers: () => ({
before: [ tsImportPluginFactory({ libraryName: "antd", style: "css" }) ]
})
}
}
```
## Internationalization
See [i18n](http://ant.design/docs/react/i18n).
@ -135,4 +148,4 @@ Open your browser and visit http://127.0.0.1:8001 , see more at https://github.c
## Contributing
We welcome all contributions, please read our [CONTRIBUTING.md](https://github.com/ant-design/ant-design/blob/master/.github/CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/ant-design/ant-design/pulls) or as [GitHub issues](https://github.com/ant-design/ant-design/issues). If you'd like to improve code, check out the [Development Instructions](https://github.com/ant-design/ant-design/wiki/Development) and have a good time! :)
We welcome all contributions. Please read our [CONTRIBUTING.md](https://github.com/ant-design/ant-design/blob/master/.github/CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/ant-design/ant-design/pulls) or as [GitHub issues](https://github.com/ant-design/ant-design/issues). If you'd like to improve code, check out the [Development Instructions](https://github.com/ant-design/ant-design/wiki/Development) and have a good time! :)

View File

@ -73,6 +73,18 @@ export default class Affix extends React.Component<AffixProps, any> {
fixedNode: HTMLElement;
};
events = [
'resize',
'scroll',
'touchstart',
'touchmove',
'touchend',
'pageshow',
'load',
];
eventHandlers = {};
constructor(props) {
super(props);
this.state = {
@ -190,7 +202,7 @@ export default class Affix extends React.Component<AffixProps, any> {
componentWillReceiveProps(nextProps) {
if (this.props.target !== nextProps.target) {
this.clearScrollEventListeners();
this.clearEventListeners();
this.setTargetEventListeners(nextProps.target);
// Mock Event object.
@ -199,7 +211,7 @@ export default class Affix extends React.Component<AffixProps, any> {
}
componentWillUnmount() {
this.clearScrollEventListeners();
this.clearEventListeners();
clearTimeout(this.timeout);
(this.updatePosition as any).cancel();
}
@ -209,15 +221,18 @@ export default class Affix extends React.Component<AffixProps, any> {
if (!target) {
return;
}
this.clearScrollEventListeners();
this.scrollEvent = addEventListener(target, 'scroll', this.updatePosition);
this.resizeEvent = addEventListener(target, 'resize', this.updatePosition);
this.clearEventListeners();
this.events.forEach(eventName => {
this.eventHandlers[eventName] = addEventListener(target, eventName, this.updatePosition);
});
}
clearScrollEventListeners() {
['scrollEvent', 'resizeEvent'].forEach((name) => {
if (this[name]) {
this[name].remove();
clearEventListeners() {
this.events.forEach(eventName => {
const handler = this.eventHandlers[eventName];
if (handler && handler.remove) {
handler.remove();
}
});
}

View File

@ -10,10 +10,17 @@ export default class InputElement extends React.Component<any, any> {
blur = () => {
this.ele.blur ? this.ele.blur() : (findDOMNode(this.ele) as HTMLInputElement).blur();
}
saveRef = (ele: HTMLInputElement) => {
this.ele = ele;
const childRef = this.props.children.ref;
if (typeof childRef === 'function') {
childRef(ele);
}
}
render() {
return React.cloneElement(this.props.children, {
...this.props,
ref: ele => this.ele = (ele as HTMLInputElement),
ref: this.saveRef,
}, null);
}
}

View File

@ -17,4 +17,14 @@ describe('AutoComplete with Custom Input Element Render', () => {
// should not filter data source defaultly
expect(dropdownWrapper.find('MenuItem').length).toBe(3);
});
it('child.ref should work', () => {
const mockRef = jest.fn();
mount(
<AutoComplete dataSource={[]}>
<input ref={mockRef} />
</AutoComplete>
);
expect(mockRef).toHaveBeenCalled();
});
});

View File

@ -15,7 +15,7 @@
}
& > span:last-child {
font-weight: bold;
font-weight: 500;
color: @text-color;
}

View File

@ -154,7 +154,7 @@ export default class Button extends React.Component<ButtonProps, any> {
const iconType = loading ? 'loading' : icon;
const iconNode = iconType ? <Icon type={iconType} /> : null;
const needInserted = React.Children.count(children) === 1 && !iconType;
const needInserted = React.Children.count(children) === 1 && (!iconType || iconType === 'loading');
const kids = React.Children.map(children, child => insertSpace(child, needInserted));
return (

View File

@ -15,6 +15,13 @@
.btn;
.btn-default;
// Make sure that the target of Button's click event always be `button`
// Ref: https://github.com/ant-design/ant-design/issues/7034
> i,
> span {
pointer-events: none;
}
&-primary {
.btn-primary;

View File

@ -8,20 +8,20 @@ exports[`renders ./components/card/demo/basic.md correctly 1`] = `
<div
class="ant-card-head"
>
<h3
<div
class="ant-card-head-title"
>
Card title
</h3>
</div>
<div
class="ant-card-extra"
>
<a
href="#"
</div>
<div
class="ant-card-extra"
>
More
</a>
<a
href="#"
>
More
</a>
</div>
</div>
<div
class="ant-card-body"
@ -50,11 +50,11 @@ exports[`renders ./components/card/demo/border-less.md correctly 1`] = `
<div
class="ant-card-head"
>
<h3
<div
class="ant-card-head-title"
>
Card title
</h3>
</div>
</div>
<div
class="ant-card-body"
@ -80,11 +80,11 @@ exports[`renders ./components/card/demo/grid-card.md correctly 1`] = `
<div
class="ant-card-head"
>
<h3
<div
class="ant-card-head-title"
>
Card Title
</h3>
</div>
</div>
<div
class="ant-card-body"
@ -153,11 +153,11 @@ exports[`renders ./components/card/demo/in-column.md correctly 1`] = `
<div
class="ant-card-head"
>
<h3
<div
class="ant-card-head-title"
>
Card title
</h3>
</div>
</div>
<div
class="ant-card-body"
@ -176,11 +176,11 @@ exports[`renders ./components/card/demo/in-column.md correctly 1`] = `
<div
class="ant-card-head"
>
<h3
<div
class="ant-card-head-title"
>
Card title
</h3>
</div>
</div>
<div
class="ant-card-body"
@ -199,11 +199,11 @@ exports[`renders ./components/card/demo/in-column.md correctly 1`] = `
<div
class="ant-card-head"
>
<h3
<div
class="ant-card-head-title"
>
Card title
</h3>
</div>
</div>
<div
class="ant-card-body"
@ -224,11 +224,11 @@ exports[`renders ./components/card/demo/loading.md correctly 1`] = `
<div
class="ant-card-head"
>
<h3
<div
class="ant-card-head-title"
>
Card title
</h3>
</div>
</div>
<div
class="ant-card-body"

View File

@ -18,7 +18,7 @@ export interface CardProps {
className?: string;
}
export default class Card extends Component<CardProps> {
export default class Card extends Component<CardProps, {}> {
static Grid: typeof Grid = Grid;
container: HTMLDivElement;
resizeEvent: any;
@ -108,16 +108,11 @@ export default class Card extends Component<CardProps> {
}
let head;
if (!title) {
head = null;
} else {
head = typeof title === 'string' ? (
if (title || extra) {
head = (
<div className={`${prefixCls}-head`}>
<h3 className={`${prefixCls}-head-title`}>{title}</h3>
</div>
) : (
<div className={`${prefixCls}-head`}>
<div className={`${prefixCls}-head-title`}>{title}</div>
{title ? <div className={`${prefixCls}-head-title`}>{title}</div> : null}
{extra ? <div className={`${prefixCls}-extra`}>{extra}</div> : null}
</div>
);
}
@ -125,7 +120,6 @@ export default class Card extends Component<CardProps> {
return (
<div {...others} className={classString} ref={this.saveRef}>
{head}
{extra ? <div className={`${prefixCls}-extra`}>{extra}</div> : null}
<div className={`${prefixCls}-body`} style={bodyStyle}>{children}</div>
</div>
);

View File

@ -28,23 +28,23 @@
border-bottom: @border-width-base @border-style-base @border-color-split;
padding: 0 @card-padding-base;
border-radius: @border-radius-sm @border-radius-sm 0 0;
.clearfix;
margin-bottom: -1px; // Fix card grid overflow bug: https://gw.alipayobjects.com/zos/rmsportal/XonYxBikwpgbqIQBeuhk.png
&-title {
font-size: @font-size-lg;
display: inline-block;
text-overflow: ellipsis;
width: 100%;
max-width: 100%;
overflow: hidden;
white-space: nowrap;
color: @card-head-color;
font-weight: 500;
float: left;
}
}
&-extra {
position: absolute;
right: @card-padding-base;
top: 14px;
float: right;
}
&-body {

View File

@ -0,0 +1,13 @@
import React from 'react';
import { mount } from 'enzyme';
import Carousel from '..';
describe('Carousel', () => {
it('should has innerSlider', () => {
const wrapper = mount(<Carousel><div /></Carousel>);
const innerSlider = wrapper.node.innerSlider;
const innerSliderFromRefs = wrapper.node.refs.slick.innerSlider;
expect(innerSlider).toBe(innerSliderFromRefs);
expect(typeof innerSlider.slickNext).toBe('function');
});
});

View File

@ -75,6 +75,8 @@ export default class Carousel extends React.Component<CarouselProps, any> {
slick: any,
};
innerSlider: any;
constructor() {
super();
this.onWindowResized = debounce(this.onWindowResized, 500, {
@ -87,6 +89,9 @@ export default class Carousel extends React.Component<CarouselProps, any> {
if (autoplay) {
window.addEventListener('resize', this.onWindowResized);
}
const { slick } = this.refs;
// https://github.com/ant-design/ant-design/issues/7191
this.innerSlider = slick && slick.innerSlider;
}
componentWillUnmount() {

View File

@ -25,6 +25,7 @@ Cascade selection box.
| defaultValue | initial selected value | [CascaderOptionType](https://git.io/vMMoK)[] |[] |
| value | selected value | [CascaderOptionType](https://git.io/vMMoK)[] | - |
| onChange | callback when finishing cascader select | `(value, selectedOptions) => void` | - |
| onPopupVisibleChange | callback when popup shown or hidden | `(value) => void` | - |
| displayRender | render function of displaying selected options | `(label, selectedOptions) => ReactNode` | `label => label.join(' / ')` |
| style | additional style | string | - |
| className | additional css class | string | - |

View File

@ -26,6 +26,7 @@ subtitle: 级联选择
| defaultValue | 默认的选中项 | [CascaderOptionType](https://git.io/vMMoK)[] |[] |
| value | 指定选中项 | [CascaderOptionType](https://git.io/vMMoK)[] | - |
| onChange | 选择完成后的回调 | `(value, selectedOptions) => void` | - |
| onPopupVisibleChange | 显示/隐藏浮层的回调 | `(value) => void` | - |
| displayRender | 选择后展示的渲染函数 | `(label, selectedOptions) => ReactNode` | `label => label.join(' / ')` |
| style | 自定义样式 | string | - |
| className | 自定义类名 | string | - |

View File

@ -174,7 +174,7 @@
&,
&:hover {
background: @background-color-base;
font-weight: bold;
font-weight: 600;
}
}
&-expand {

View File

@ -321,7 +321,7 @@
.btn;
.btn-primary;
.button-size(@btn-height-sm; @btn-padding-sm; @font-size-base; @border-radius-base);
line-height: @line-height-base;
line-height: @btn-height-sm - 2px;
&-disabled {
.button-color(@btn-disable-color; @btn-disable-bg; @btn-disable-border);

View File

@ -28,7 +28,7 @@ You can get the menu list by `antd.Menu`, and set a callback function `onSelect`
> Warning: You must set a unique `key` for `Menu.Item`.
> Remove the highlighted style after click menu item via `<Menu selectedKey={[]}>`.
> Remove the highlighted style after click menu item via `<Menu selectedKeys={[]}>`.
### Dropdown.Button

View File

@ -29,7 +29,7 @@ title: Dropdown
> 注意: Menu.Item 必须设置唯一的 key 属性。
> 如果希望去掉菜单选中的背景效果,可以指定 `<Menu selectedKey={[]}>`.
> 如果希望去掉菜单选中的背景效果,可以指定 `<Menu selectedKeys={[]}>`.
### Dropdown.Button

View File

@ -110,9 +110,14 @@ export interface FormComponentProps {
form: WrappedFormUtils;
}
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/9951
export type Diff<T extends string, U extends string> =
({ [P in T]: P } & { [P in U]: never } & { [x: string]: never })[T];
export type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>;
export interface ComponentDecorator<TOwnProps> {
(component: React.ComponentClass<FormComponentProps & TOwnProps>): React.ComponentClass<TOwnProps>;
<P extends FormComponentProps>(
component: React.ComponentClass<P>,
): React.ComponentClass<Omit<P, keyof FormComponentProps> & TOwnProps>;
}
export default class Form extends React.Component<FormProps, any> {

View File

@ -2167,6 +2167,7 @@ exports[`renders ./components/form/demo/validate-other.md correctly 1`] = `
id="input-number"
max="10"
min="1"
step="1"
value="3"
/>
</div>
@ -2941,6 +2942,7 @@ exports[`renders ./components/form/demo/without-form-create.md correctly 1`] = `
class="ant-input-number-input"
max="12"
min="8"
step="1"
value="11"
/>
</div>

View File

@ -0,0 +1,36 @@
/* tslint:disable */
import React from 'react';
import Form, { FormComponentProps } from '../Form';
// test Form.create on component without own props
class WithoutOwnProps extends React.Component<any, any> {
state = {
foo: 'bar',
};
render() {
return <div>foo</div>;
}
}
const WithoutOwnPropsForm = Form.create()(WithoutOwnProps);
<WithoutOwnPropsForm />;
// test Form.create on component with own props
interface WithOwnPropsProps extends FormComponentProps {
name: string;
}
class WithOwnProps extends React.Component<WithOwnPropsProps, any> {
state = {
foo: 'bar',
};
render() {
return <div>foo</div>;
}
}
const WithOwnPropsForm = Form.create()(WithOwnProps);
<WithOwnPropsForm name="foo" />;

View File

@ -59,7 +59,7 @@ The following `options` are available:
| Property | Description | Type |
|-----------|------------------------------------------|------------|
| onFieldsChange | Specify a function that will be called when the value a `Form.Item` gets changed. Usage example: saving the field's value to Redux store. | Function(props, fields) |
| mapPropsToFields | Convert props to corresponding field value. Usage example: reading the values from Redux store. | Function(props): Object{ fieldName: Object{ value } } |
| mapPropsToFields | Convert props to field value. Usage example: reading the values from Redux store. | Function(props): Object{ fieldName: Object{ value } } |
| onValuesChange | A handler while value of any field is changed | (props, values) => void |
If the form has been decorated by `Form.create` then it has `this.props.form` property. `this.props.form` provides some APIs as follows:
@ -87,9 +87,9 @@ If the form has been decorated by `Form.create` then it has `this.props.form` pr
After wrapped by `getFieldDecorator`, `value`(or other property defined by `valuePropName`) `onChange`(or other property defined by `trigger`) props will be added to form controlsthe flow of form data will be handled by Form which will cause:
1. You don't need to use `onChange` to collect data, but you still can listen to `onChange`(and so on) events.
1. You shouldn't to use `onChange` to collect data, but you still can listen to `onChange`(and so on) events.
2. You can not set value of form control via `value` `defaultValue` prop, and you should set default value with `initialValue` in `getFieldDecorator` instead.
3. You don't need to call `setState` manually, please use `this.props.form.setFieldsValue` to change value programmatically.
3. You shouldn't to call `setState` manually, please use `this.props.form.setFieldsValue` to change value programmatically.
#### Special attention

View File

@ -61,7 +61,7 @@ CustomizedForm = Form.create({})(CustomizedForm);
| 参数 | 说明 | 类型 |
|-----------|------------------------------------------|------------|
| onFieldsChange | 当 `Form.Item` 子节点的值发生改变时触发,可以把对应的值转存到 Redux store | Function(props, fields) |
| mapPropsToFields | 把 props 转为对应的值,可用于把 Redux store 中的值读出 | Function(props): Object{ fieldName: Object{ value } } |
| mapPropsToFields | 把父组件的属性映射到表单项上(可用于把 Redux store 中的值读出) | Function(props): Object{ fieldName: Object{ value } } |
| onValuesChange | 任一表单域的值发生改变时的回调 | (props, values) => void |
经过 `Form.create` 包装的组件将会自带 `this.props.form` 属性,`this.props.form` 提供的 API 如下:
@ -88,9 +88,9 @@ CustomizedForm = Form.create({})(CustomizedForm);
经过 `getFieldDecorator` 包装的控件,表单控件会自动添加 `value`(或 `valuePropName` 指定的其他属性) `onChange`(或 `trigger` 指定的其他属性),数据同步将被 Form 接管,这会导致以下结果:
1. 你不再需要用 `onChange` 来做同步,但还是可以继续监听 `onChange` 等事件。
1. 你**不再需要也不应该**`onChange` 来做同步,但还是可以继续监听 `onChange` 等事件。
2. 你不能用控件的 `value` `defaultValue` 等属性来设置表单域的值,默认值可以用 `getFieldDecorator` 里的 `initialValue`
3. 你不需要`setState`,可以使用 `this.props.form.setFieldsValue` 来动态改变表单值。
3. 你不应该`setState`,可以使用 `this.props.form.setFieldsValue` 来动态改变表单值。
#### 特别注意

View File

@ -44,6 +44,7 @@ exports[`renders ./components/input-number/demo/basic.md correctly 1`] = `
class="ant-input-number-input"
max="10"
min="1"
step="1"
value="3"
/>
</div>
@ -93,6 +94,7 @@ exports[`renders ./components/input-number/demo/digit.md correctly 1`] = `
class="ant-input-number-input"
max="10"
min="0"
step="0.1"
value=""
/>
</div>
@ -145,6 +147,7 @@ exports[`renders ./components/input-number/demo/disabled.md correctly 1`] = `
disabled=""
max="10"
min="1"
step="1"
value="3"
/>
</div>
@ -209,6 +212,7 @@ exports[`renders ./components/input-number/demo/formatter.md correctly 1`] = `
class="ant-input-number-input"
max="9007199254740991"
min="-9007199254740991"
step="1"
value="$ 1,000"
/>
</div>
@ -256,6 +260,7 @@ exports[`renders ./components/input-number/demo/formatter.md correctly 1`] = `
class="ant-input-number-input"
max="100"
min="0"
step="1"
value="100%"
/>
</div>
@ -308,6 +313,7 @@ exports[`renders ./components/input-number/demo/size.md correctly 1`] = `
class="ant-input-number-input"
max="100000"
min="1"
step="1"
value="3"
/>
</div>
@ -355,6 +361,7 @@ exports[`renders ./components/input-number/demo/size.md correctly 1`] = `
class="ant-input-number-input"
max="100000"
min="1"
step="1"
value="3"
/>
</div>
@ -402,6 +409,7 @@ exports[`renders ./components/input-number/demo/size.md correctly 1`] = `
class="ant-input-number-input"
max="100000"
min="1"
step="1"
value="3"
/>
</div>

View File

@ -18,6 +18,7 @@ export interface InputNumberProps {
style?: React.CSSProperties;
className?: string;
name?: string;
id?: string;
precision?: number;
}

View File

@ -339,6 +339,7 @@ exports[`renders ./components/input/demo/group.md correctly 1`] = `
class="ant-input-number-input"
max="9007199254740991"
min="-9007199254740991"
step="1"
value=""
/>
</div>

View File

@ -14,6 +14,7 @@
&-wrapper {
display: inline-block;
vertical-align: top; // https://github.com/ant-design/ant-design/issues/6403
width: 100%;
}
}

View File

@ -169,6 +169,8 @@ export default class Sider extends React.Component<SiderProps, any> {
const divStyle = {
...style,
flex: `0 0 ${siderWidth}px`,
maxWidth: `${siderWidth}px`, // Fix width transition bug in IE11
minWidth: `${siderWidth}px`, // https://github.com/ant-design/ant-design/issues/6349
width: `${siderWidth}px`,
};
const siderCls = classNames(className, prefixCls, {

View File

@ -34,7 +34,7 @@ exports[`renders ./components/layout/demo/basic.md correctly 1`] = `
>
<div
class="ant-layout-sider"
style="flex:0 0 200px;width:200px;"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px;"
>
<div
class="ant-layout-sider-children"
@ -72,7 +72,7 @@ exports[`renders ./components/layout/demo/basic.md correctly 1`] = `
</div>
<div
class="ant-layout-sider"
style="flex:0 0 200px;width:200px;"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px;"
>
<div
class="ant-layout-sider-children"
@ -92,7 +92,7 @@ exports[`renders ./components/layout/demo/basic.md correctly 1`] = `
>
<div
class="ant-layout-sider"
style="flex:0 0 200px;width:200px;"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px;"
>
<div
class="ant-layout-sider-children"
@ -129,7 +129,7 @@ exports[`renders ./components/layout/demo/custom-trigger.md correctly 1`] = `
>
<div
class="ant-layout-sider"
style="flex:0 0 200px;width:200px;"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px;"
>
<div
class="ant-layout-sider-children"
@ -313,7 +313,7 @@ exports[`renders ./components/layout/demo/fixed-sider.md correctly 1`] = `
>
<div
class="ant-layout-sider"
style="overflow:auto;height:100vh;position:fixed;left:0;flex:0 0 200px;width:200px;"
style="overflow:auto;height:100vh;position:fixed;left:0;flex:0 0 200px;max-width:200px;min-width:200px;width:200px;"
>
<div
class="ant-layout-sider-children"
@ -578,7 +578,7 @@ exports[`renders ./components/layout/demo/responsive.md correctly 1`] = `
>
<div
class="ant-layout-sider"
style="flex:0 0 200px;width:200px;"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px;"
>
<div
class="ant-layout-sider-children"
@ -688,7 +688,7 @@ exports[`renders ./components/layout/demo/side.md correctly 1`] = `
>
<div
class="ant-layout-sider"
style="flex:0 0 200px;width:200px;"
style="flex:0 0 200px;max-width:200px;min-width:200px;width:200px;"
>
<div
class="ant-layout-sider-children"
@ -1039,7 +1039,7 @@ exports[`renders ./components/layout/demo/top-side.md correctly 1`] = `
>
<div
class="ant-layout-sider"
style="background:#fff;flex:0 0 200px;width:200px;"
style="background:#fff;flex:0 0 200px;max-width:200px;min-width:200px;width:200px;"
>
<div
class="ant-layout-sider-children"
@ -1209,7 +1209,7 @@ exports[`renders ./components/layout/demo/top-side-2.md correctly 1`] = `
>
<div
class="ant-layout-sider"
style="background:#fff;flex:0 0 200px;width:200px;"
style="background:#fff;flex:0 0 200px;max-width:200px;min-width:200px;width:200px;"
>
<div
class="ant-layout-sider-children"

View File

@ -65,6 +65,7 @@
color: @layout-trigger-color;
background: fade(@layout-trigger-background, 100);
z-index: 1;
transition: all .15s @ease-in-out;
}
&-zero-width {

View File

@ -10,35 +10,35 @@ export default {
TimePicker,
Calendar,
Table: {
filterTitle: 'Filtrar Menu',
filterConfirm: 'OK',
filterReset: 'Resetear',
emptyText: 'No Hay Datos',
selectAll: 'Seleccionar Todo',
selectInvert: 'Invertir Selección',
filterTitle: 'Filtrar menú',
filterConfirm: 'Aceptar',
filterReset: 'Reiniciar',
emptyText: 'No hay datos',
selectAll: 'Seleccionar todo',
selectInvert: 'Invertir selección',
},
Modal: {
okText: 'OK',
okText: 'Aceptar',
cancelText: 'Cancelar',
justOkText: 'OK',
justOkText: 'Aceptar',
},
Popconfirm: {
okText: 'OK',
okText: 'Aceptar',
cancelText: 'Cancelar',
},
Transfer: {
notFoundContent: 'No Encontrado',
notFoundContent: 'No encontrado',
searchPlaceholder: 'Buscar aquí',
itemUnit: 'item',
itemsUnit: 'items',
itemUnit: 'elemento',
itemsUnit: 'elementos',
},
Select: {
notFoundContent: 'No Encontrado',
notFoundContent: 'No encontrado',
},
Upload: {
uploading: 'Subiendo...',
removeFile: 'Eliminar archivo',
uploadError: 'Error de subida',
uploadError: 'Error al subir el archivo',
previewFile: 'Vista previa',
},
};

View File

@ -35,10 +35,10 @@ More layouts with navigation: [layout](/components/layout).
| defaultSelectedKeys | array with the keys of default selected menu items | string[] | |
| openKeys | array with the keys of currently opened sub menus | string[] | |
| defaultOpenKeys | array with the keys of default opened sub menus | | |
| onOpenChange | called when open/close sub menu | Function(openKeys: string[]) | noop |
| onSelect | callback of the selected item | Function({ item, key, selectedKeys }) | none |
| onDeselect | callback of the deselected item, only supported for multiple mode | Function({ item, key, selectedKeys }) | - |
| onClick | callback of the clicked menu item, params: {item, key, keyPath} | function | - |
| onOpenChange | called when open/close sub menu | function(openKeys: string[]) | noop |
| onSelect | callback of the selected item | function({ item, key, selectedKeys }) | none |
| onDeselect | callback of the deselected item, only supported for multiple mode | function({ item, key, selectedKeys }) | - |
| onClick | callback when click menu item, params: {item, key, keyPath} | function({ item, key, keyPath }) | - |
| style | style of the root node | object | |
| inlineIndent | indent px of inline menu item on each level | number | 24 |
| multiple | Allow select multiple item | boolean | false |
@ -61,7 +61,7 @@ More layouts with navigation: [layout](/components/layout).
| key | unique id of the menu item | string | |
| title | title of the sub menu | string\|ReactNode | |
| children | sub menus or sub menu items | Array<MenuItem\|SubMenu> | |
| onTitleClick | callback of the clicked sub menu title | Function({ key, domEvent }) | |
| onTitleClick | callback of the clicked sub menu title | function({ key, domEvent }) | |
### Menu.ItemGroup

View File

@ -35,10 +35,10 @@ subtitle: 导航菜单
| defaultSelectedKeys | 初始选中的菜单项 key 数组 | string[] | |
| openKeys | 当前展开的 SubMenu 菜单项 key 数组 | string[] | |
| defaultOpenKeys | 初始展开的 SubMenu 菜单项 key 数组 | | |
| onOpenChange | SubMenu 展开/关闭的回调 | Function(openKeys: string[]) | noop |
| onSelect | 被选中时调 | Function({ item, key, selectedKeys }) | 无 |
| onDeselect | 取消选中时调用,仅在 multiple 生效 | Function({ item, key, selectedKeys }) | - |
| onClick | 点击 menuitem 调用此函数,参数为 {item, key, keyPath} | function | - |
| onOpenChange | SubMenu 展开/关闭的回调 | function(openKeys: string[]) | noop |
| onSelect | 被选中时调 | function({ item, key, selectedKeys }) | 无 |
| onDeselect | 取消选中时调用,仅在 multiple 生效 | function({ item, key, selectedKeys }) | - |
| onClick | 点击 MenuItem 调用此函数 | function({ item, key, keyPath }) | - |
| style | 根节点样式 | object | |
| inlineIndent | inline 模式的菜单缩进宽度 | number | 24 |
| multiple | 是否允许多选 | boolean | false |
@ -61,7 +61,7 @@ subtitle: 导航菜单
| key | 唯一标志 | string | |
| title | 子菜单项值 | string\|ReactNode | |
| children | 子菜单的菜单项 | Array<MenuItem\|SubMenu> | |
| onTitleClick | 点击子菜单标题 | Function({ key, domEvent }) | |
| onTitleClick | 点击子菜单标题 | function({ key, domEvent }) | |
### Menu.ItemGroup

View File

@ -2,7 +2,6 @@
@import "../../style/mixins/index";
@menu-prefix-cls: ~"@{ant-prefix}-menu";
@menu-collapsed-width: 64px;
// default theme
.@{menu-prefix-cls} {

View File

@ -1,6 +1,8 @@
import notification from '..';
describe('Notification.placement', () => {
afterEach(() => notification.destroy());
function $$(className) {
return document.body.querySelectorAll(className);
}

View File

@ -1,15 +1,43 @@
import React from 'react';
import Notification from 'rc-notification';
import Icon from '../icon';
export type NotificationPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
const notificationInstance = {};
let defaultDuration = 4.5;
let defaultTop = 24;
let defaultBottom = 24;
let defaultPlacement = 'topRight';
let defaultPlacement: NotificationPlacement = 'topRight';
let defaultGetContainer;
export type notificationPlacement = 'topLeft' | 'topRight' | 'bottomLeft' | 'bottomRight';
function getPlacementStyle(placement) {
export interface ConfigProps {
top?: number;
bottom?: number;
duration?: number;
placement?: NotificationPlacement;
getContainer?: () => HTMLElement;
}
function setNotificationConfig(options: ConfigProps) {
const { duration, placement, bottom, top, getContainer } = options;
if (duration !== undefined) {
defaultDuration = duration;
}
if (placement !== undefined) {
defaultPlacement = placement;
}
if (bottom !== undefined) {
defaultBottom = bottom;
}
if (top !== undefined) {
defaultTop = top;
}
if (getContainer !== undefined) {
defaultGetContainer = getContainer;
}
}
function getPlacementStyle(placement: NotificationPlacement) {
let style;
switch (placement) {
case 'topLeft':
@ -19,6 +47,13 @@ function getPlacementStyle(placement) {
bottom: 'auto',
};
break;
case 'topRight':
style = {
right: 0,
top: defaultTop,
bottom: 'auto',
};
break;
case 'bottomLeft':
style = {
left: 0,
@ -26,23 +61,37 @@ function getPlacementStyle(placement) {
bottom: defaultBottom,
};
break;
case 'bottomRight':
default:
style = {
right: 0,
top: 'auto',
bottom: defaultBottom,
};
break;
default:
style = {
right: 0,
top: defaultTop,
bottom: 'auto',
};
}
return style;
}
function getNotificationInstance(prefixCls, placement) {
const cacheKey = `${prefixCls}-${placement}`;
if (!notificationInstance[cacheKey]) {
notificationInstance[cacheKey] = (Notification as any).newInstance({
prefixCls,
className: `${prefixCls}-${placement}`,
style: getPlacementStyle(placement),
getContainer: defaultGetContainer,
});
}
return notificationInstance[cacheKey];
}
const typeToIcon = {
success: 'check-circle-o',
info: 'info-circle-o',
error: 'cross-circle-o',
warning: 'exclamation-circle-o',
};
export interface ArgsProps {
message: React.ReactNode;
description: React.ReactNode;
@ -51,67 +100,18 @@ export interface ArgsProps {
onClose?: () => void;
duration?: number;
icon?: React.ReactNode;
placement?: notificationPlacement;
placement?: NotificationPlacement;
style?: string;
prefixCls?: string;
className?: string;
readonly type?: string;
}
export interface ConfigProps {
top?: number;
bottom?: number;
duration?: number;
placement?: notificationPlacement;
getContainer?: () => HTMLElement;
}
function getNotificationInstance(prefixCls) {
if (notificationInstance[defaultPlacement]) {
return notificationInstance[defaultPlacement];
}
notificationInstance[defaultPlacement] = (Notification as any).newInstance({
prefixCls: prefixCls,
className: `${prefixCls}-${defaultPlacement}`,
style: getPlacementStyle(defaultPlacement),
getContainer: defaultGetContainer,
});
return notificationInstance[defaultPlacement];
}
function notice(args) {
function notice(args: ArgsProps) {
const outerPrefixCls = args.prefixCls || 'ant-notification';
const prefixCls = `${outerPrefixCls}-notice`;
const duration = args.duration === undefined ? defaultDuration : args.duration;
if (args.placement !== undefined) {
defaultPlacement = args.placement;
}
let duration;
if (args.duration === undefined) {
duration = defaultDuration;
} else {
duration = args.duration;
}
let iconType = '';
switch (args.type) {
case 'success':
iconType = 'check-circle-o';
break;
case 'info':
iconType = 'info-circle-o';
break;
case 'error':
iconType = 'cross-circle-o';
break;
case 'warning':
iconType = 'exclamation-circle-o';
break;
default:
iconType = 'info-circle';
}
let iconNode;
let iconNode: React.ReactNode = null;
if (args.icon) {
iconNode = (
<span className={`${prefixCls}-icon`}>
@ -119,15 +119,20 @@ function notice(args) {
</span>
);
} else if (args.type) {
iconNode = <Icon className={`${prefixCls}-icon ${prefixCls}-icon-${args.type}`} type={iconType} />;
const iconType = typeToIcon[args.type];
iconNode = (
<Icon
className={`${prefixCls}-icon ${prefixCls}-icon-${args.type}`}
type={iconType}
/>
);
}
const autoMarginTag = (!args.description && iconNode)
? <span className={`${prefixCls}-message-single-line-auto-margin`} />
: null;
const { style, className } = args;
getNotificationInstance(outerPrefixCls).notice({
getNotificationInstance(outerPrefixCls, args.placement || defaultPlacement).notice({
content: (
<div className={iconNode ? `${prefixCls}-with-icon` : ''}>
{iconNode}
@ -143,11 +148,35 @@ function notice(args) {
closable: true,
onClose: args.onClose,
key: args.key,
style: { ...style },
className,
style: args.style || {},
className: args.className,
});
}
const api: any = {
open: notice,
close(key) {
Object.keys(notificationInstance)
.forEach(cacheKey => notificationInstance[cacheKey].removeNotice(key));
},
config: setNotificationConfig,
destroy() {
Object.keys(notificationInstance).forEach(cacheKey => {
notificationInstance[cacheKey].destroy();
delete notificationInstance[cacheKey];
});
},
};
['success', 'info', 'warning', 'error'].forEach((type) => {
api[type] = (args: ArgsProps) => api.open({
...args,
type,
});
});
api.warn = api.warning;
export interface NotificationApi {
success(args: ArgsProps): void;
error(args: ArgsProps): void;
@ -159,57 +188,4 @@ export interface NotificationApi {
config(options: ConfigProps): void;
destroy(): void;
}
const api = {
open(args: ArgsProps) {
notice(args);
},
close(key) {
if (notificationInstance[defaultPlacement]) {
notificationInstance[defaultPlacement].removeNotice(key);
}
},
config(options: ConfigProps) {
const { duration, placement, bottom, top, getContainer } = options;
if (placement !== undefined) {
defaultPlacement = placement;
}
if (bottom !== undefined) {
defaultBottom = bottom;
}
if (top !== undefined) {
defaultTop = top;
}
if (getContainer !== undefined) {
defaultGetContainer = getContainer;
}
// delete notificationInstance
if (placement !== undefined || bottom !== undefined || top !== undefined) {
const notify = notificationInstance[defaultPlacement];
if (notify) {
notify.destroy();
}
delete notificationInstance[defaultPlacement];
}
if (duration !== undefined) {
defaultDuration = duration;
}
},
destroy() {
Object.keys(notificationInstance).forEach(key => {
notificationInstance[key].destroy();
delete notificationInstance[key];
});
},
};
['success', 'info', 'warning', 'error'].forEach((type) => {
api[type] = (args: ArgsProps) => api.open({
...args,
type,
});
});
(api as any).warn = (api as any).warning;
export default api as NotificationApi;

View File

@ -187,7 +187,8 @@
}
&-disabled {
&:hover {
&:hover,
&:focus {
border-color: @border-color-base;
a {
color: @disabled-color;

View File

@ -152,17 +152,6 @@ exports[`renders ./components/progress/demo/circle-dynamic.md correctly 1`] = `
stroke-width="6"
style="stroke-dasharray:295.3097094374406px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s;"
/>
<path
class="ant-progress-circle-path"
d="M 50,50 m 0,-47
a 47,47 0 1 1 0,94
a 47,47 0 1 1 0,-94"
fill-opacity="0"
stroke="#108ee9"
stroke-linecap="round"
stroke-width="6"
style="stroke-dasharray:0px 295.3097094374406px;stroke-dashoffset:-0px;transition:stroke-dashoffset .3s ease 0s, stroke-dasharray .3s ease 0s, stroke .3s;"
/>
</svg>
<span
class="ant-progress-text"

View File

@ -37,6 +37,7 @@
&-circle-path {
stroke: @process-default-color;
animation: ~"@{ant-prefix}-progress-appear" .3s;
}
&-bg {
@ -132,6 +133,15 @@
}
}
@keyframes ~"@{ant-prefix}-progress-appear" {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes ~"@{ant-prefix}-progress-active" {
0% {
opacity: 0.1;

View File

@ -853,7 +853,7 @@ exports[`renders ./components/select/demo/tags.md correctly 1`] = `
style="display:block;user-select:none;-webkit-user-select:none;"
unselectable="unselectable"
>
标签模式
Tags Mode
</div>
<ul>
<li

View File

@ -30,7 +30,7 @@ ReactDOM.render(
<Select
mode="tags"
style={{ width: '100%' }}
placeholder="标签模式"
placeholder="Tags Mode"
onChange={handleChange}
>
{children}

View File

@ -67,8 +67,7 @@ export interface SelectContext {
};
}
export const SelectPropTypes = {
...RcSelect.propTypes,
const SelectPropTypes = {
prefixCls: PropTypes.string,
className: PropTypes.string,
size: PropTypes.oneOf(['default', 'large', 'small']),

View File

@ -53,6 +53,8 @@ title: Select
| labelInValue | 是否把每个选项的 label 包装到 value 中,会把 Select 的 value 类型从 `string` 变为 `{key: string, label: ReactNode}` 的格式 | boolean | false |
| tokenSeparators | 在 tags 和 multiple 模式下自动分词的分隔符 | string[] | |
> 注意,如果发现下拉菜单跟随页面滚动,或者需要在其他弹层中触发 Select请尝试使用 `getPopupContainer={triggerNode => triggerNode.parentNode}` 将下拉弹层渲染节点固定在触发器的父元素中。
### Option props
| 参数 | 说明 | 类型 | 默认值 |

View File

@ -488,7 +488,7 @@
&,
&:hover {
background-color: @background-color-base;
font-weight: bold;
font-weight: 600;
color: @text-color;
}
}

View File

@ -262,6 +262,7 @@ exports[`renders ./components/slider/demo/input-number.md correctly 1`] = `
class="ant-input-number-input"
max="20"
min="1"
step="1"
value="1"
/>
</div>
@ -348,6 +349,7 @@ exports[`renders ./components/slider/demo/input-number.md correctly 1`] = `
class="ant-input-number-input"
max="1"
min="0"
step="0.01"
value="0.00"
/>
</div>

View File

@ -174,6 +174,7 @@
font-size: @font-size-lg;
margin-right: 8px;
transition: background-color 0.3s ease, border-color 0.3s ease;
font-family: @font-family-no-number;
> .@{steps-prefix-cls}-icon {
line-height: 1;

View File

@ -39,7 +39,8 @@
@body-background : #fff;
// Base background color for most components
@component-background : #fff;
@font-family : "Helvetica Neue For Number", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-no-number : -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family : "Helvetica Neue For Number", @font-family-no-number;
@code-family : Consolas, Menlo, Courier, monospace;
@heading-color : fade(#000, 85%);
@text-color : fade(#000, 65%);
@ -283,6 +284,7 @@
// ---
@menu-dark-bg: @layout-header-background;
@menu-dark-submenu-bg: #333;
@menu-collapsed-width: 64px;
// Spin
// ---

View File

@ -141,7 +141,7 @@ import { Table } from 'antd';
import { TableColumnConfig } from 'antd/lib/table/Table';
interface IUser {
key: number,
key: number;
name: string;
}

View File

@ -43,7 +43,7 @@
margin-left: 4px;
font-size: @font-size-base;
cursor: pointer;
color: #aaa;
color: #999;
transition: all .3s;
width: 14px;
@ -301,7 +301,7 @@
margin-left: 4px;
display: inline-block;
width: 14px;
height: 14px;
height: 1em;
vertical-align: middle;
text-align: center;
@ -341,12 +341,10 @@
.@{iconfont-css-prefix}-caret-up,
.@{iconfont-css-prefix}-caret-down {
.iconfont-size-under-12px(8px);
line-height: 6px;
height: 6px;
color: #aaa;
&:before {
-moz-transform-origin: 53% 50%; /* fix firefox position */
}
line-height: 4px;
height: 4px;
color: #999;
transition: all .3s;
}
}
@ -521,7 +519,7 @@
}
.@{iconfont-css-prefix}-down {
color: #aaa;
color: #999;
transition: all .3s;
}
@ -534,7 +532,7 @@
box-shadow: @box-shadow-base;
.@{ant-prefix}-action-down {
color: #aaa;
color: #999;
}
}

View File

@ -97,6 +97,7 @@ exports[`renders ./components/tabs/demo/basic.md correctly 1`] = `
exports[`renders ./components/tabs/demo/card.md correctly 1`] = `
<div
class="ant-tabs ant-tabs-top ant-tabs-card ant-tabs-no-animation"
type="card"
>
<div
class="ant-tabs-bar"
@ -193,6 +194,7 @@ exports[`renders ./components/tabs/demo/card-top.md correctly 1`] = `
>
<div
class="ant-tabs ant-tabs-top ant-tabs-card ant-tabs-no-animation"
type="card"
>
<div
class="ant-tabs-bar"
@ -308,6 +310,7 @@ exports[`renders ./components/tabs/demo/custom-add-trigger.md correctly 1`] = `
</div>
<div
class="ant-tabs ant-tabs-top ant-tabs-card ant-tabs-editable-card ant-tabs-no-animation"
type="editable-card"
>
<div
class="ant-tabs-bar"
@ -479,6 +482,7 @@ exports[`renders ./components/tabs/demo/disabled.md correctly 1`] = `
<div
aria-hidden="true"
class="ant-tabs-tabpane ant-tabs-tabpane-inactive"
disabled=""
role="tabpanel"
/>
<div
@ -493,6 +497,7 @@ exports[`renders ./components/tabs/demo/disabled.md correctly 1`] = `
exports[`renders ./components/tabs/demo/editable-card.md correctly 1`] = `
<div
class="ant-tabs ant-tabs-top ant-tabs-card ant-tabs-editable-card ant-tabs-no-animation"
type="editable-card"
>
<div
class="ant-tabs-bar"

View File

@ -22,6 +22,7 @@ exports[`Tabs tabPosition remove card 1`] = `
>
<div
className="ant-tabs ant-tabs-left ant-tabs-vertical ant-tabs-line"
onChange={[Function]}
style={Object {}}
>
<ScrollableInkTabBar
@ -59,11 +60,11 @@ exports[`Tabs tabPosition remove card 1`] = `
>
<div
className="ant-tabs-nav-container"
onTransitionEnd={[Function]}
>
<span
className="ant-tabs-tab-prev ant-tabs-tab-btn-disabled"
onClick={null}
onTransitionEnd={[Function]}
unselectable="unselectable"
>
<span

View File

@ -26,7 +26,7 @@
border-bottom: @border-width-base @border-style-base @border-color-base;
margin-bottom: 16px;
outline: none;
transition: padding .45s;
transition: padding .3s @ease-in-out;
}
&-nav-container {
@ -37,7 +37,7 @@
position: relative;
white-space: nowrap;
margin-bottom: -1px;
transition: padding .45s;
transition: padding .3s @ease-in-out;
.clearfix;
&-scrolling {
@ -51,7 +51,7 @@
user-select: none;
z-index: 2;
width: 0;
height: 0;
height: 100%;
line-height: 32px;
cursor: pointer;
border: 0;
@ -59,7 +59,7 @@
position: absolute;
text-align: center;
color: @text-color-secondary;
transition: width .3s, height .3s, opacity .3s, color .3s;
transition: width .3s @ease-in-out, opacity .3s @ease-in-out, color .3s @ease-in-out;
opacity: 0;
pointer-events: none;
@ -134,7 +134,7 @@
&-nav {
box-sizing: border-box;
padding-left: 0;
transition: transform 0.5s @ease-in-out;
transition: transform 0.3s @ease-in-out;
position: relative;
margin: 0;
list-style: none;
@ -230,7 +230,11 @@
> .@{tab-prefix-cls}-bar {
border-bottom: 0;
height: 100%;
&-tab-prev, &-tab-next {
width: 32px;
height: 0;
transition: height .3s @ease-in-out, opacity .3s @ease-in-out, color .3s @ease-in-out;
}
&-tab-prev.@{tab-prefix-cls}-tab-arrow-show,
&-tab-next.@{tab-prefix-cls}-tab-arrow-show {
width: 100%;

View File

@ -12,7 +12,7 @@
border: @border-width-base @border-style-base @border-color-split;
background: @tag-default-bg;
font-size: @tag-font-size;
transition: all 0.3s @ease-in-out-circ;
transition: all 0.3s @ease-out;
opacity: 1;
margin-right: 8px;
cursor: pointer;
@ -41,7 +41,7 @@
cursor: pointer;
font-weight: bold;
margin-left: 3px;
transition: all 0.3s ease;
transition: all 0.3s @ease-out;
opacity: 0.66;
&:hover {

View File

@ -24,7 +24,7 @@ export default class Timeline extends React.Component<TimelineProps, any> {
}, className);
const items = React.Children.map(children, (ele: React.ReactElement<any>, idx) =>
React.cloneElement(ele, {
last: idx === (children as { length: number }).length - 1,
last: idx === (React.Children.count(children) - 1),
}),
);
const pendingItem = (!!pending) ? (

View File

@ -21,7 +21,7 @@
outline: 0;
&.filter-node {
> span {
font-weight: bold !important;
font-weight: 500;
}
}
ul {

View File

@ -48,7 +48,7 @@
&.filter-node {
> span {
color: @highlight-color !important;
font-weight: bold !important;
font-weight: 500 !important;
}
}
ul {

View File

@ -4,10 +4,10 @@ import Icon from '../icon';
import Tooltip from '../tooltip';
import Progress from '../progress';
import classNames from 'classnames';
import { UploadListProps } from './interface';
import { UploadListProps, UploadFile } from './interface';
// https://developer.mozilla.org/en-US/docs/Web/API/FileReader/readAsDataURL
const previewFile = (file, callback) => {
const previewFile = (file: File, callback: Function) => {
const reader = new FileReader();
reader.onloadend = () => callback(reader.result);
reader.readAsDataURL(file);
@ -25,14 +25,14 @@ export default class UploadList extends React.Component<UploadListProps, any> {
showPreviewIcon: true,
};
handleClose = (file) => {
handleClose = (file: UploadFile) => {
const onRemove = this.props.onRemove;
if (onRemove) {
onRemove(file);
}
}
handlePreview = (file, e) => {
handlePreview = (file: UploadFile, e) => {
const { onPreview } = this.props;
if (!onPreview) {
return;

View File

@ -6,7 +6,7 @@ export interface HttpRequestHeader {
[key: string]: string;
}
export interface File {
export interface UploadFile {
uid: number;
size: number;
name: string;
@ -21,8 +21,8 @@ export interface File {
}
export interface UploadChangeParam {
file: File;
fileList: Array<File>;
file: UploadFile;
fileList: Array<UploadFile>;
event?: { percent: number };
}
@ -41,20 +41,20 @@ export interface UploadLocale {
export interface UploadProps {
type?: 'drag' | 'select';
name?: string;
defaultFileList?: Array<File>;
fileList?: Array<File>;
defaultFileList?: Array<UploadFile>;
fileList?: Array<UploadFile>;
action?: string;
data?: Object | ((file: File) => any);
data?: Object | ((file: UploadFile) => any);
headers?: HttpRequestHeader;
showUploadList?: boolean | ShowUploadListInterface;
multiple?: boolean;
accept?: string;
beforeUpload?: (file: File, FileList: File[]) => boolean | PromiseLike<any>;
beforeUpload?: (file: UploadFile, FileList: UploadFile[]) => boolean | PromiseLike<any>;
onChange?: (info: UploadChangeParam) => void;
listType?: 'text' | 'picture' | 'picture-card';
className?: string;
onPreview?: (file: File) => void;
onRemove?: (file: File) => void | boolean;
onPreview?: (file: UploadFile) => void;
onRemove?: (file: UploadFile) => void | boolean;
supportServerRender?: boolean;
style?: React.CSSProperties;
disabled?: boolean;
@ -66,9 +66,9 @@ export interface UploadProps {
export interface UploadListProps {
listType?: 'text' | 'picture' | 'picture-card';
onPreview?: (file: File) => void;
onRemove?: (file: File) => void | boolean;
items?: Array<File>;
onPreview?: (file: UploadFile) => void;
onRemove?: (file: UploadFile) => void | boolean;
items?: Array<UploadFile>;
progressAttr?: Object;
prefixCls?: string;
showRemoveIcon?: boolean;

View File

@ -41,7 +41,7 @@ Following the Ant Design specification, we developed a React UI library `antd` t
## Version
- Stable: [![npm package](https://img.shields.io/npm/v/antd.svg?style=flat-square)](https://www.npmjs.org/package/antd)
- Beta: [![](https://cnpmjs.org/badge/v/antd.svg?&tag=beta&subject=npm)](https://www.npmjs.org/package/antd)
- Next: [![](https://cnpmjs.org/badge/v/antd.svg?&tag=next&subject=npm)](https://www.npmjs.org/package/antd)
You can subscribe to this feed for new version notifications: https://github.com/ant-design/ant-design/releases.atom

View File

@ -41,7 +41,7 @@ title: Ant Design of React
## 版本
- 稳定版:[![npm package](https://img.shields.io/npm/v/antd.svg?style=flat-square)](https://www.npmjs.org/package/antd)
- 开发版:[![](https://cnpmjs.org/badge/v/antd.svg?&tag=beta&subject=npm)](https://www.npmjs.org/package/antd)
- 预览版:[![](https://cnpmjs.org/badge/v/antd.svg?&tag=next&subject=npm)](https://www.npmjs.org/package/antd)
你可以订阅https://github.com/ant-design/ant-design/releases.atom 来获得稳定版发布的通知。

View File

@ -246,5 +246,6 @@ Finally, we used antd with create-react-app successfully, you can learn these pr
There are a lot of great boilerplates like create-react-app in React community. There are some source code samples of importing antd in them if you encounter some problems.
- [create-react-app-antd](https://github.com/ant-design/create-react-app-antd)
- [comerc/cra-ts-antd](https://github.com/comerc/cra-ts-antd)
- [react-boilerplate/react-boilerplate](https://github.com/ant-design/react-boilerplate)
- [kriasoft/react-starter-kit](https://github.com/ant-design/react-starter-kit)

View File

@ -26,7 +26,7 @@ We supply a series of design principles, practical patterns and high quality des
[React](http://facebook.github.io/react/) is used to encapsulate a library of Ant Design components. Any other version of frameworks to implement is also welcome.
- [Ant Design of React](/docs/react/introduce) (official implementation)
- <div class="outside-link internal"><a href="http://zorro.alibaba.net" target="_blank">Ant Design of Angular 2</a></div>
- <div class="outside-link"><a href="http://ng.ant.design" target="_blank">NG-ZORRO - Ant Design of Angular</a></div>
- <div class="outside-link"><a href="https://github.com/iview/iview/" target="_blank">iView (vue)</a></div>
- <div class="outside-link"><a href="https://github.com/FE-Driver/vue-beauty" target="_blank">vue-beauty</a></div>
- <div class="outside-link"><a href="https://github.com/aliqin/atui" target="_blank">ATUI (vue)</a></div>

View File

@ -26,7 +26,7 @@ Ant Design 是一个致力于提升『用户』和『设计者』使用体验的
我们采用 [React](http://facebook.github.io/react/) 封装了一套 Ant Design 的组件库,也欢迎社区其他框架的实现版本。
- [Ant Design of React](/docs/react/introduce)(官方实现)
- <div class="outside-link internal"><a href="http://zorro.alibaba.net" target="_blank">Ant Design of Angular 2</a></div>
- <div class="outside-link"><a href="http://ng.ant.design" target="_blank">NG-ZORRO - Ant Design of Angular</a></div>
- <div class="outside-link"><a href="https://github.com/iview/iview/" target="_blank">iView (vue)</a></div>
- <div class="outside-link"><a href="https://github.com/FE-Driver/vue-beauty" target="_blank">vue-beauty</a></div>
- <div class="outside-link"><a href="https://github.com/aliqin/atui" target="_blank">ATUI (vue)</a></div>

View File

@ -58,19 +58,19 @@
"rc-menu": "~5.0.10",
"rc-notification": "~2.0.0",
"rc-pagination": "~1.10.6",
"rc-progress": "~2.1.2",
"rc-progress": "~2.2.2",
"rc-rate": "~2.1.1",
"rc-select": "~6.8.6",
"rc-slider": "~8.2.0",
"rc-steps": "~2.5.1",
"rc-switch": "~1.5.1",
"rc-table": "~5.4.0",
"rc-tabs": "~9.0.2",
"rc-tabs": "~9.1.2",
"rc-time-picker": "~2.4.1",
"rc-tooltip": "~3.4.6",
"rc-tree": "~1.7.0",
"rc-tree-select": "~1.10.2",
"rc-upload": "~2.3.7",
"rc-upload": "~2.4.0",
"rc-util": "^4.0.4",
"react-lazy-load": "^3.0.10",
"react-slick": "~0.14.2",
@ -80,11 +80,9 @@
"devDependencies": {
"@types/react": "^15.0.38",
"@types/react-dom": "~0.14.18",
"antd-demo-jest": "^1.3.0",
"antd-tools": "~1.6.0",
"antd-tools": "~1.8.0",
"babel-cli": "^6.18.0",
"babel-eslint": "^7.1.0",
"babel-jest": "^20.0.3",
"babel-plugin-import": "^1.0.0",
"babel-plugin-transform-runtime": "^6.23.0",
"babel-preset-es2015": "^6.18.0",
@ -139,7 +137,6 @@
"stylelint": "^8.0.0",
"stylelint-config-standard": "^17.0.0",
"typescript": "~2.4.2",
"typescript-babel-jest": "^1.0.2",
"values.js": "^1.0.3",
"xhr2": "^0.1.3"
},

View File

@ -109,33 +109,43 @@
border-bottom: 1px dashed @border-color-split;
}
.collapse {
.code-expand-icon {
position: absolute;
right: 14px;
bottom: 22px;
right: 16px;
bottom: 23px;
cursor: pointer;
width: 16px;
height: 16px;
font-size: 16px;
line-height: 16px;
opacity: 0.5;
text-align: center;
transition: all 0.3s;
color: #999;
background: #fff;
user-select: none;
border-radius: 100%;
}
&.expand .collapse {
color: shade(@primary-color, 20%);
transform: rotate(-180deg);
.code-expand-icon-show,
.code-expand-icon-hide {
transition: all 0.4s;
user-select: none;
position: absolute;
left: 0;
top: 0;
}
.code-expand-icon-show {
opacity: 0.55;
pointer-events: auto;
&:hover {
opacity: 1;
}
}
.code-expand-icon.ant-tooltip-open .code-expand-icon-show {
opacity: 1;
}
.code-expand-icon-hide {
opacity: 0;
pointer-events: none;
}
.highlight-wrapper {
display: none;
overflow: auto;

View File

@ -54,6 +54,7 @@
color: #aaa;
font-size: 12px;
margin-top: -4px;
background-color: #fff;
a {
padding-left: 8px;
display: block;

View File

@ -1,3 +1,4 @@
/* eslint jsx-a11y/no-noninteractive-element-interactions: 0 */
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
@ -35,8 +36,8 @@ export default class Demo extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return (this.state.codeExpand || this.props.expand) !== (nextState.codeExpand || nextProps.expand)
|| this.state.copied !== nextState.copied
|| this.state.copyTooltipVisible !== nextState.copyTooltipVisible;
|| this.state.copied !== nextState.copied
|| this.state.copyTooltipVisible !== nextState.copyTooltipVisible;
}
componentDidMount() {
@ -55,7 +56,7 @@ export default class Demo extends React.Component {
});
}
handleCodeExapnd = () => {
handleCodeExpand = () => {
this.setState({ codeExpand: !this.state.codeExpand });
}
@ -158,9 +159,25 @@ export default class Demo extends React.Component {
<EditButton title={<FormattedMessage id="app.content.edit-page" />} filename={meta.filename} />
</div>
{introChildren}
<Icon type="down-circle-o" title="Show Code" className="collapse" onClick={this.handleCodeExapnd} />
<Tooltip title={codeExpand ? 'Hide Code' : 'Show Code'}>
<span className="code-expand-icon">
<img
alt="expand code"
src="https://gw.alipayobjects.com/zos/rmsportal/wSAkBuJFbdxsosKKpqyq.svg"
className={codeExpand ? 'code-expand-icon-hide' : 'code-expand-icon-show'}
onClick={this.handleCodeExpand}
/>
<img
alt="expand code"
src="https://gw.alipayobjects.com/zos/rmsportal/OpROPHYqWmrMDBFMZtKF.svg"
className={codeExpand ? 'code-expand-icon-show' : 'code-expand-icon-hide'}
onClick={this.handleCodeExpand}
/>
</span>
</Tooltip>
</section>
<section className={highlightClass}
<section
className={highlightClass}
key="code"
>
<div className="highlight">

View File

@ -61,20 +61,9 @@ export default class MainContent extends React.Component {
if (!location.hash) {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
} else {
if (this.timer) {
clearTimeout(this.timer);
}
this.timer = setTimeout(() => {
document.getElementById(decodeURI(location.hash.replace('#', ''))).scrollIntoView();
}, 10);
}
}
componentWillUnmount() {
clearTimeout(this.timer);
}
handleMenuOpenChange = (openKeys) => {
this.setState({ openKeys });
}

View File

@ -69,16 +69,16 @@ class Footer extends React.Component {
</li>
<li>
<h2><Icon type="link" /> <FormattedMessage id="app.footer.links" /></h2>
<div>
<a href="https://design.alipay.com/">
<FormattedMessage id="app.footer.design-platform" />
</a>
</div>
<div>
<a href="http://mobile.ant.design">Ant Design Mobile</a>
<span> - </span>
<FormattedMessage id="app.footer.mobile" />
</div>
<div>
<a href="http://ng.ant.design">NG-ZORRO</a>
<span> - </span>
Ant Design of Angular
</div>
<div>
<a href="http://scaffold.ant.design">Scaffolds</a>
<span> - </span>

View File

@ -152,6 +152,7 @@ export default class Header extends React.Component {
dropdownMatchSelectWidth={false}
defaultValue={antdVersion}
onChange={this.handleVersionChange}
getPopupContainer={trigger => trigger.parentNode}
>
{versionOptions}
</Select>,