Merge branch 'master' of github.com:ant-design/ant-design

This commit is contained in:
afc163 2016-11-07 14:02:16 +08:00
commit 52e649a9fb
21 changed files with 543 additions and 14 deletions

View File

@ -9,6 +9,12 @@ If you want to read change logs before `2.0.0`, please visit [GitHub](https://gi
---
## 2.3.1
`2016-11-07`
* Add missing `dist/antd.css` back.
## 2.3.0
`2016-11-04`

View File

@ -9,6 +9,12 @@ timeline: true
---
## 2.3.1
`2016-11-07`
* 修正上个版本缺少 `dist/antd.css` 的问题。
## 2.3.0
`2016-11-04`

View File

@ -0,0 +1,72 @@
import React from 'react';
import classnames from 'classnames';
import AnchorHelper, { scrollTo } from './anchorHelper';
export interface AnchorLinkProps {
href: string;
onClick: (href: string) => void;
active?: boolean;
prefixCls?: string;
children?: any;
title?: Element;
bounds: number;
target?: () => HTMLElement | Window;
}
export default class AnchorLink extends React.Component<AnchorLinkProps, any> {
static contextTypes = {
anchorHelper: React.PropTypes.any,
};
static childContextTypes = {
anchorHelper: React.PropTypes.any,
};
static defaultProps = {
href: '#',
prefixCls: 'ant-anchor',
};
context: {
anchorHelper: AnchorHelper;
};
constructor(props, context) {
super(props, context);
}
getChildContext() {
return {
anchorHelper: this.context.anchorHelper,
};
}
renderAnchorLink = (child) => {
const { href } = child.props;
if (href) {
this.context.anchorHelper.addLink(href);
return React.cloneElement(child, {
onClick: this.context.anchorHelper.scrollTo,
prefixCls: this.props.prefixCls,
});
}
return child;
}
render() {
const { prefixCls, href, children, onClick, title, bounds } = this.props;
const { anchorHelper } = this.context;
const active = anchorHelper && anchorHelper.getCurrentAnchor(bounds) === href;
const cls = classnames({
[`${prefixCls}-link`]: true,
[`${prefixCls}-link-active`]: active,
});
const scrollToFn = anchorHelper ? anchorHelper.scrollTo : scrollTo;
return <div className={cls}>
<span
ref={(component) => component && active && anchorHelper ? anchorHelper.setActiveAnchor(component) : null}
className={`${prefixCls}-link-title`}
onClick={() => onClick ? onClick(href) : scrollToFn(href)}
>{title}</span>
{React.Children.map(children, this.renderAnchorLink)}
</div>;
}
}

View File

@ -0,0 +1,100 @@
import getScroll from '../_util/getScroll';
import getRequestAnimationFrame from '../_util/getRequestAnimationFrame';
export const reqAnimFrame = getRequestAnimationFrame();
export const easeInOutCubic = (t, b, c, d) => {
const cc = c - b;
t /= d / 2;
if (t < 1) {
return cc / 2 * t * t * t + b;
}
return cc / 2 * ((t -= 2) * t * t + 2) + b;
};
export function getDefaultTarget() {
return typeof window !== 'undefined' ?
window : null;
}
export function getOffsetTop(element): number {
if (!element) {
return 0;
}
if (!element.getClientRects().length) {
return 0;
}
const rect = element.getBoundingClientRect();
if ( rect.width || rect.height ) {
const doc = element.ownerDocument;
const docElem = doc.documentElement;
return rect.top - docElem.clientTop;
}
return rect.top;
}
export function scrollTo(href, target = getDefaultTarget) {
const scrollTop = getScroll(target(), true);
const offsetTop = getOffsetTop(document.querySelector(href));
const targetScrollTop = scrollTop + offsetTop;
const startTime = Date.now();
const frameFunc = () => {
const timestamp = Date.now();
const time = timestamp - startTime;
document.body.scrollTop = easeInOutCubic(time, scrollTop, targetScrollTop, 450);
if (time < 450) {
reqAnimFrame(frameFunc);
}
};
reqAnimFrame(frameFunc);
history.pushState(null, undefined, href);
}
class AnchorHelper {
private links: Array<string>;
private currentAnchor: HTMLElement | null;
constructor() {
this.links = [];
this.currentAnchor = null;
}
addLink(link) {
if (this.links.indexOf(link) === -1) {
this.links.push(link);
}
}
getCurrentActiveAnchor(): HTMLElement | null {
return this.currentAnchor;
}
setActiveAnchor(component) {
this.currentAnchor = component;
}
getCurrentAnchor(bounds = 5) {
let activeAnchor = '';
this.links.forEach(section => {
const target = document.querySelector(section);
if (target) {
const top = getOffsetTop(target);
const bottom = top + target.clientHeight;
if ((top <= bounds) && (bottom >= -bounds)) {
activeAnchor = section;
}
}
});
return activeAnchor;
}
scrollTo(href, target = getDefaultTarget) {
scrollTo(href, target);
}
}
export default AnchorHelper;

View File

@ -0,0 +1,26 @@
---
order: 0
title:
zh-CN: 基本
en-US: Basic
---
## zh-CN
最简单的用法。
## en-US
The simplest usage.
```jsx
import { Anchor } from 'antd';
const { Link } = Anchor;
ReactDOM.render(
<Anchor>
<Link href="#components-anchor-demo-basic" title="Basic" />
<Link href="#components-anchor-demo-independ" title="Independent AnchorLink" />
</Anchor>
, mountNode);
```

View File

@ -0,0 +1,23 @@
---
order: 2
title:
zh-CN: 独立使用 AnchorLink
en-US: Independent AnchorLink
---
## zh-CN
独立使用 AnchorLink
## en-US
Independent AnchorLink
```jsx
import { Anchor } from 'antd';
const { Link } = Anchor;
ReactDOM.render(
<Link href="#components-anchor-demo-basic" title="Basic" />
, mountNode);
```

View File

@ -0,0 +1,28 @@
---
order: 1
title:
zh-CN: 嵌套的 AnchorLink
en-US: Mixed AnchorLink
---
## zh-CN
最简单的用法。
## en-US
The simplest usage.
```jsx
import { Anchor } from 'antd';
const { Link } = Anchor;
ReactDOM.render(
<Anchor offsetTop={100}>
<Link href="#components-anchor-demo-basic" title="Bacis">
<Link href="#components-anchor-demo-mix" title="Mixed AnchorLink" />
</Link>
<Link href="#components-anchor-demo-independ" title="Independent AnchorLink" />
</Anchor>
, mountNode);
```

View File

@ -0,0 +1,30 @@
---
category: Components
type: Other
cols: 1
title: Anchor
---
A hyperlink to a location on same page.
## When To Use
For displaying anchor hyperlink on page, and jump between then.
## API
### Anchor Props
| Property | Description | Type | Default |
|--------------|-----------------------|----------|--------------|
| offsetTop | Pixels to offset from top when calculating position of scroll | Number | 0 |
| offsetBottom | Pixels to offset from bottom when calculating position of scroll | Number | - |
| bounds | Bounding distance of anchor area | Number | 5(px) |
### Link Props
| Property | Description | Type | Default |
|-------------|----------------|--------------------|--------------|
| href | target of hyperlink | String | |
| title | content of hyperlink | String | |

107
components/anchor/index.tsx Normal file
View File

@ -0,0 +1,107 @@
import React from 'react';
import className from 'classnames';
import addEventListener from 'rc-util/lib/Dom/addEventListener';
import AnchorLink from './AnchorLink';
import Affix from '../affix';
import AnchorHelper, { getDefaultTarget } from './anchorHelper';
export interface AnchorProps {
target: () => HTMLElement | Window;
children: React.ReactNode;
prefixCls?: string;
offsetTop?: number;
bounds?: number;
}
export default class Anchor extends React.Component<AnchorProps, any> {
static Link = AnchorLink;
static defaultProps = {
prefixCls: 'ant-anchor',
};
static childContextTypes = {
anchorHelper: React.PropTypes.any,
};
refs: {
ink?: any;
};
private scrollEvent: any;
private anchorHelper: AnchorHelper;
constructor(props) {
super(props);
this.state = {
activeAnchor: null,
};
this.anchorHelper = new AnchorHelper();
}
handleScroll = () => {
this.setState({
activeAnchor: this.anchorHelper.getCurrentAnchor(this.props.bounds),
});
}
getChildContext() {
return {
anchorHelper: this.anchorHelper,
};
}
componentDidMount() {
this.handleScroll();
this.updateInk();
this.scrollEvent = addEventListener((this.props.target || getDefaultTarget)(), 'scroll', this.handleScroll);
}
componentWillUnmount() {
if (this.scrollEvent) {
this.scrollEvent.remove();
}
}
componentDidUpdate() {
this.updateInk();
}
updateInk = () => {
const activeAnchor = this.anchorHelper.getCurrentActiveAnchor();
if (activeAnchor) {
this.refs.ink.style.top = `${activeAnchor.offsetTop + activeAnchor.clientHeight / 2 - 4.5}px`;
}
}
renderAnchorLink = (child) => {
const { href } = child.props;
if (href) {
this.anchorHelper.addLink(href);
return React.cloneElement(child, {
onClick: this.anchorHelper.scrollTo,
prefixCls: this.props.prefixCls,
bounds: this.props.bounds,
});
}
return child;
}
render() {
const { prefixCls, offsetTop } = this.props;
const { activeAnchor } = this.state;
const inkClass = className({
[`${prefixCls}-ink-ball`]: true,
visible: !!activeAnchor,
});
return <Affix offsetTop={offsetTop}>
<div className={`${prefixCls}-wrapper`}>
<div className={prefixCls}>
<div className={`${prefixCls}-ink`} >
<span className={inkClass} ref="ink"/>
</div>
{React.Children.map(this.props.children, this.renderAnchorLink)}
</div>
</div>
</Affix>;
}
}

View File

@ -0,0 +1,31 @@
---
category: Components
subtitle: 锚点
cols: 1
type: Other
title: Anchor
---
用于跳转到页面指定位置
## 何时使用
需要展现当前页面上可供跳转的锚点链接,以及快速在锚点之间跳转。
## API
### Anchor Props
| 成员 | 说明 | 类型 | 默认值 |
|-------------|----------------|--------------------|--------------|
| offsetTop | 距离窗口顶部达到指定偏移量后触发 | Number | |
| offsetBottom | 距离窗口底部达到指定偏移量后触发 | Number | |
| bounds | 锚点区域边界 | Number | 5(px) |
### Link Props
| 成员 | 说明 | 类型 | 默认值 |
|-------------|----------------|--------------------|--------------|
| href | 锚点链接 | String | |
| title | 文字内容 | String | |

View File

@ -0,0 +1,59 @@
@import "../../style/themes/default";
.@{ant-prefix} {
&-anchor {
position: relative;
&-wrapper {
padding: 6px;
background-color: white;
}
}
&-anchor-ink {
position: absolute;
width: 9px;
height: 100%;
left: 0;
top: 0;
&:before {
content: ' ';
position: relative;
width: 2px;
height: 100%;
display: block;
background-color: #ccc;
margin: 0 auto;
}
&-ball {
display: none;
position: absolute;
width: 9px;
height: 9px;
border-radius: 9px;
border: 3px solid @primary-color;
background-color: white;
transition: top .3s ease-in-out;
&.visible {
display: inline-block;
}
}
}
&-anchor-link {
padding-left: 16px;
&-title {
display: inline-block;
position: relative;
}
&-active > &-title,
&-title:hover {
cursor: pointer;
color: @primary-color;
}
& > & {
font-size: 12px;
}
}
}

View File

@ -0,0 +1,2 @@
import '../../style/index.less';
import './index.less';

View File

@ -70,7 +70,7 @@ If the form has been decorated by `Form.create` then it has `this.props.form` pr
| validateFieldsAndScroll | This function is similar to `validateFields`, but after validation, if the target field is not in visible area of form, form will be automatically scrolled to the target field area. | same as `validateFields` |
| getFieldError | Get the error of a field. | Function(name) |
| isFieldValidating | Check if the specified field is being validated. | Function(name) |
| resetFields | Reset the specified fields' value and status. If you don't specify a parameter, all the fields will be reset. | Function([names: string[]]) |
| resetFields | Reset the specified fields' value(to `initialValue`) and status. If you don't specify a parameter, all the fields will be reset. | Function([names: string[]]) |
| getFieldDecorator | Two-way binding for form, please read below for details. | |
### this.props.form.getFieldDecorator(id, options)

View File

@ -72,7 +72,7 @@ CustomizedForm = Form.create({})(CustomizedForm);
| validateFieldsAndScroll | 与 `validateFields` 相似,但校验完后,如果校验不通过的菜单域不在可见范围内,则自动滚动进可见范围 | 参考 `validateFields` |
| getFieldError | 获取某个输入控件的 Error | Function(name) |
| isFieldValidating | 判断一个输入控件是否在校验状态 | Function(name) |
| resetFields | 重置一组输入控件的值与状态,如不传入参数,则重置所有组件 | Function([names: string[]]) |
| resetFields | 重置一组输入控件的值(为 `initialValue`与状态,如不传入参数,则重置所有组件 | Function([names: string[]]) |
| getFieldDecorator | 用于和表单进行双向绑定,详见下方描述 | |
### this.props.form.getFieldDecorator(id, options)

View File

@ -9,6 +9,8 @@ please use https://www.npmjs.com/package/babel-plugin-import to reduce app bundl
export { default as Affix } from './affix';
export { default as Anchor } from './anchor';
export { default as AutoComplete } from './auto-complete';
export { default as Alert } from './alert';

View File

@ -29,19 +29,26 @@ const Sider = React.createClass({
};
},
handleClick(e) {
console.log('click ', e);
console.log('Clicked: ', e);
this.setState({ current: e.key });
},
onOpenChange(openKeys) {
const latestOpenKey = openKeys.find(key => !(this.state.openKeys.indexOf(key) > -1));
this.setState({ openKeys: this.getKeyPath(latestOpenKey) });
const state = this.state;
const latestOpenKey = openKeys.find(key => !(state.openKeys.indexOf(key) > -1));
const latestCloseKey = state.openKeys.find(key => !(openKeys.indexOf(key) > -1));
let nextOpenKeys = [];
if (latestOpenKey) {
nextOpenKeys = this.getAncestorKeys(latestOpenKey).concat(latestOpenKey);
}
if (latestCloseKey) {
nextOpenKeys = this.getAncestorKeys(latestCloseKey);
}
this.setState({ openKeys: nextOpenKeys });
},
getKeyPath(key) {
getAncestorKeys(key) {
const map = {
sub1: ['sub1'],
sub2: ['sub2'],
sub3: ['sub2', 'sub3'],
sub4: ['sub4'],
sub3: ['sub2'],
};
return map[key] || [];
},

View File

@ -132,7 +132,7 @@
@container-lg : (1140px + @grid-gutter-width);
// z-index list
@zindex-affix : 10;
@zindex-affix : 11;
@zindex-back-top : 10;
@zindex-modal-mask : 1000;
@zindex-modal : 1000;

View File

@ -131,7 +131,7 @@ const ProductList = ({ onDelete, products }) => {
);
};
ProductList.proptypes = {
ProductList.propTypes = {
onDelete: PropTypes.func.isRequired,
products: PropTypes.array.isRequired,
};

View File

@ -82,7 +82,7 @@ const ExtendPalettes = React.createClass({
]
},
{
'title': 'Magenta #E9259',
'title': 'Magenta #E9259E',
'description': '玫红色是较为正面的色彩,含有鼓励、友好、活力的意义。但考虑到洋红色的特性,建议作为辅助色来使用。',
'colors': [
"#F8C5ED", "#F5A6D3", "#F387C0",

View File

@ -1 +1,31 @@
/* eslint no-console:0 */
// this file is not used if use https://github.com/ant-design/babel-plugin-import
function camelCase(name) {
return name.charAt(0).toUpperCase() +
name.slice(1).replace(/-(\w)/g, (m, n) => {
return n.toUpperCase();
});
}
const req = require.context('./components', true, /^\.\/[^_][\w-]+\/(style\/)index\.tsx?$/);
console.log(req.keys());
req.keys().forEach((mod) => {
let v = req(mod);
if (v && v.default) {
v = v.default;
}
const match = mod.match(/^\.\/([^_][\w-]+)\/index\.tsx?$/);
if (match && match[1]) {
if (match[1] === 'message' || match[1] === 'notification') {
// message & notification should not be capitalized
exports[match[1]] = v;
} else {
exports[camelCase(match[1])] = v;
}
}
});
module.exports = require('./components');

View File

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "2.3.0",
"version": "2.3.1",
"title": "Ant Design",
"description": "An enterprise-class UI design language and React-based implementation",
"homepage": "http://ant.design/",