mirror of
https://github.com/ant-design/ant-design.git
synced 2025-01-18 22:36:31 +08:00
Merge from master
This commit is contained in:
commit
d4171badfd
@ -1,5 +1,6 @@
|
||||
components/**/*.js
|
||||
components/**/*.jsx
|
||||
components/*/__tests__/type.tsx
|
||||
!.eslintrc.js
|
||||
!components/*/__tests__/*
|
||||
!components/*/__tests__/**/*.js
|
||||
!components/*/demo/*
|
||||
|
13
.jest.js
13
.jest.js
@ -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: [
|
||||
|
@ -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',
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
||||
|
17
README.md
17
README.md
@ -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! :)
|
||||
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
@ -15,7 +15,7 @@
|
||||
}
|
||||
|
||||
& > span:last-child {
|
||||
font-weight: bold;
|
||||
font-weight: 500;
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
|
@ -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 (
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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>
|
||||
);
|
||||
|
@ -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 {
|
||||
|
13
components/carousel/__tests__/index.test.js
Normal file
13
components/carousel/__tests__/index.test.js
Normal 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');
|
||||
});
|
||||
});
|
@ -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() {
|
||||
|
@ -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 | - |
|
||||
|
@ -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 | - |
|
||||
|
@ -174,7 +174,7 @@
|
||||
&,
|
||||
&:hover {
|
||||
background: @background-color-base;
|
||||
font-weight: bold;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
&-expand {
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -29,7 +29,7 @@ title: Dropdown
|
||||
|
||||
> 注意: Menu.Item 必须设置唯一的 key 属性。
|
||||
|
||||
> 如果希望去掉菜单选中的背景效果,可以指定 `<Menu selectedKey={[]}>`.
|
||||
> 如果希望去掉菜单选中的背景效果,可以指定 `<Menu selectedKeys={[]}>`.
|
||||
|
||||
### Dropdown.Button
|
||||
|
||||
|
@ -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> {
|
||||
|
@ -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>
|
||||
|
36
components/form/__tests__/type.tsx
Normal file
36
components/form/__tests__/type.tsx
Normal 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" />;
|
@ -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 controls,the 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
|
||||
|
||||
|
@ -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` 来动态改变表单值。
|
||||
|
||||
#### 特别注意
|
||||
|
||||
|
@ -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>
|
||||
|
@ -18,6 +18,7 @@ export interface InputNumberProps {
|
||||
style?: React.CSSProperties;
|
||||
className?: string;
|
||||
name?: string;
|
||||
id?: string;
|
||||
precision?: number;
|
||||
}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -14,6 +14,7 @@
|
||||
&-wrapper {
|
||||
display: inline-block;
|
||||
vertical-align: top; // https://github.com/ant-design/ant-design/issues/6403
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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, {
|
||||
|
@ -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"
|
||||
|
@ -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 {
|
||||
|
@ -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',
|
||||
},
|
||||
};
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -2,7 +2,6 @@
|
||||
@import "../../style/mixins/index";
|
||||
|
||||
@menu-prefix-cls: ~"@{ant-prefix}-menu";
|
||||
@menu-collapsed-width: 64px;
|
||||
|
||||
// default theme
|
||||
.@{menu-prefix-cls} {
|
||||
|
@ -1,6 +1,8 @@
|
||||
import notification from '..';
|
||||
|
||||
describe('Notification.placement', () => {
|
||||
afterEach(() => notification.destroy());
|
||||
|
||||
function $$(className) {
|
||||
return document.body.querySelectorAll(className);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -187,7 +187,8 @@
|
||||
}
|
||||
|
||||
&-disabled {
|
||||
&:hover {
|
||||
&:hover,
|
||||
&:focus {
|
||||
border-color: @border-color-base;
|
||||
a {
|
||||
color: @disabled-color;
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -30,7 +30,7 @@ ReactDOM.render(
|
||||
<Select
|
||||
mode="tags"
|
||||
style={{ width: '100%' }}
|
||||
placeholder="标签模式"
|
||||
placeholder="Tags Mode"
|
||||
onChange={handleChange}
|
||||
>
|
||||
{children}
|
||||
|
@ -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']),
|
||||
|
@ -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
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
|
@ -488,7 +488,7 @@
|
||||
&,
|
||||
&:hover {
|
||||
background-color: @background-color-base;
|
||||
font-weight: bold;
|
||||
font-weight: 600;
|
||||
color: @text-color;
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
// ---
|
||||
|
@ -141,7 +141,7 @@ import { Table } from 'antd';
|
||||
import { TableColumnConfig } from 'antd/lib/table/Table';
|
||||
|
||||
interface IUser {
|
||||
key: number,
|
||||
key: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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%;
|
||||
|
@ -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 {
|
||||
|
@ -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) ? (
|
||||
|
@ -21,7 +21,7 @@
|
||||
outline: 0;
|
||||
&.filter-node {
|
||||
> span {
|
||||
font-weight: bold !important;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
ul {
|
||||
|
@ -48,7 +48,7 @@
|
||||
&.filter-node {
|
||||
> span {
|
||||
color: @highlight-color !important;
|
||||
font-weight: bold !important;
|
||||
font-weight: 500 !important;
|
||||
}
|
||||
}
|
||||
ul {
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 来获得稳定版发布的通知。
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
11
package.json
11
package.json
@ -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"
|
||||
},
|
||||
|
@ -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;
|
||||
|
@ -54,6 +54,7 @@
|
||||
color: #aaa;
|
||||
font-size: 12px;
|
||||
margin-top: -4px;
|
||||
background-color: #fff;
|
||||
a {
|
||||
padding-left: 8px;
|
||||
display: block;
|
||||
|
@ -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">
|
||||
|
@ -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 });
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -152,6 +152,7 @@ export default class Header extends React.Component {
|
||||
dropdownMatchSelectWidth={false}
|
||||
defaultValue={antdVersion}
|
||||
onChange={this.handleVersionChange}
|
||||
getPopupContainer={trigger => trigger.parentNode}
|
||||
>
|
||||
{versionOptions}
|
||||
</Select>,
|
||||
|
Loading…
Reference in New Issue
Block a user