Merge branch 'spa-new-design-language' into develop-1.0.0

This commit is contained in:
Benjy Cui 2016-03-18 12:08:19 +08:00
commit a760e74734
103 changed files with 2054 additions and 419 deletions

View File

@ -2,6 +2,6 @@ First of all, thanks for your contribution! :-)
Please makes sure these boxes are checked before submitting your PR, thank you!
[ ] Run `npm run lint` and fix those errors before submitting in order to keep consistent code style.
[ ] Rebase before creating a PR to keep commit history clear.
[ ] Add some descriptions and refer relative issues for you PR.
* [ ] Run `npm run lint` and fix those errors before submitting in order to keep consistent code style.
* [ ] Rebase before creating a PR to keep commit history clear.
* [ ] Add some descriptions and refer relative issues for you PR.

View File

@ -4,6 +4,46 @@
---
## 0.12.11
`2016-03-16`
- 全新的设计文档 `语言` 部分。
- 修复 Popconfirm `onConfirm``onCancel` 时没有触发 `onVisibleChange` 的问题。
- TreeSelect 组件补充 `showCheckedStrategy` 属性,支持回填数据的不同展示方式。
- 补充 Modal `align` 属性的文档。
- 修复 Menu 弹出菜单 `z-index` 丢失的问题。
- Progress 的默认颜色固定,不再随着主色变化。
- 优化 Button 点击动画在 Chrome 下的效果。
- 修复一个 Affix 的 `z-index` 太低的问题。
- 修复 Table 树形数据的二级节点列前无法选择的问题。[#1212](https://github.com/ant-design/ant-design/issues/1212)
- 修复 Table 修改 `pageSize` 没有触发 `onChange` 的问题。[#1206](https://github.com/ant-design/ant-design/issues/1206)
- 修复 Table 指定 `rowKey` 时导致 `rowSelection.onChange``selectedRows` 参数为空的问题。
## 0.12.10
- 修复 0.12.9 版本 npm 包打包错误的问题。
## 0.12.9
`2016-03-11`
- Transfer
- 可以定义 `notFoundContent `
- 修复 `searchPlaceholder` 使用了 `placeholder` 的值的问题。
- 修复 Popconfirm、Popover、Tooltip 的箭头位置未指向元素的问题。
- 修正 Badge 在搜狗等旧版 webkit 浏览器下无法使用的问题。
- 调整 Tabs 样式。
- 修复 Table 中的 Pagination 默认配置问题。
- 调整 Form.Item 在 inline 模式下的 `margin-bottom`。[#1141](https://github.com/ant-design/ant-design/issues/1141)
- 修复 DatePicker `style` 设置错误的问题。
- 优化 Popconfirm、Button 样式。
- Dropdown 增加默认的 mouseEnterDelay 延迟以优化体验。
- 修复 Dialog 样式问题。
- 修复 Upload 上传中的状态问题。[#1159](https://github.com/ant-design/ant-design/issues/1159)
- 优化 Menu、Tabs 在 Chorme 下的渲染问题。
- Form 默认阻止 submit 事件。
## 0.12.8
`2016-03-06`

View File

@ -1,6 +1,6 @@
MIT LICENSE
Copyright (c) 2015 Alipay.com, https://www.alipay.com/
Copyright (c) 2015-present Alipay.com, https://www.alipay.com/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View File

@ -9,7 +9,8 @@ export default React.createClass({
return {
prefixCls: 'ant-alert',
showIcon: false,
onClose() {}
onClose() {},
type: 'info',
};
},
getInitialState() {

View File

@ -17,7 +17,7 @@
| 参数 | 说明 | 类型 | 默认值 |
|----------- |--------------------------------------------------------- | ---------- |-------|
| type | 必选参数,指定警告提示的样式,有四种选择`success`、`info`、`warn`、`error` | String | |
| type | 必选参数,指定警告提示的样式,有四种选择`success`、`info`、`warn`、`error` | String | `info` |
| closable | 可选参数,默认不显示关闭按钮 | Boolean | 无 |
| closeText | 可选参数,自定义关闭按钮 | React.Node | 无 |
| message | 必选参数,警告提示内容 | React.Node | 无 |

View File

@ -76,6 +76,7 @@ class AntScrollNumber extends React.Component {
className: `${this.props.prefixCls}-only`,
style: {
transition: removeTransition && 'none',
WebkitTransform: `translate3d(0, ${-position * height}px, 0)`,
transform: `translate3d(0, ${-position * height}px, 0)`,
height,
},

View File

@ -24,5 +24,5 @@ export default class ButtonGroup extends React.Component {
}
}
ButtonGroup.propTypes = {
size: React.PropTypes.string,
size: React.PropTypes.oneOf(['large', 'small']),
};

View File

@ -2,7 +2,7 @@ import React from 'react';
import classNames from 'classnames';
import { findDOMNode } from 'react-dom';
const rxTwoCNChar = /^[\u4e00-\u9fa5]{2,2}$/;
const rxTwoCNChar = /^[\u4e00-\u9fa5]{2}$/;
const isTwoCNChar = rxTwoCNChar.test.bind(rxTwoCNChar);
function isString(str) {
return typeof str === 'string';
@ -73,10 +73,10 @@ export default class Button extends React.Component {
}
Button.propTypes = {
type: React.PropTypes.string,
shape: React.PropTypes.string,
size: React.PropTypes.string,
htmlType: React.PropTypes.string,
type: React.PropTypes.oneOf(['primary', 'ghost', 'dashed']),
shape: React.PropTypes.oneOf(['circle', 'circle-outline']),
size: React.PropTypes.oneOf(['large', 'small']),
htmlType: React.PropTypes.oneOf(['submit', 'button', 'reset']),
onClick: React.PropTypes.func,
loading: React.PropTypes.bool,
className: React.PropTypes.string,

View File

@ -6,7 +6,7 @@
通过设置 `type``primary` `ghost` 可分别创建主按钮、幽灵按钮,若不设置 `type` 值则为次按钮。不同的样式可以用来区别其重要程度。
主按钮和次按钮可独立使用,需要强引导用主按钮。幽灵按钮用于和主按钮组合。
主按钮和次按钮可独立使用,需要强引导用主按钮。幽灵按钮用于和主按钮组合。主按钮在同一个操作区域最多出现一次。
---

View File

@ -36,3 +36,5 @@
| size | 输入框大小,可选 `large` `default` `small` | string | `default` |
| disabled | 禁用 | boolean | false |
| allowClear | 是否支持清除 | boolean | true |
| expandTrigger | 次级菜单的展开方式,可选 'click' 和 'hover' | string | 'click' |
| changeOnSelect | 当此项为 true 时,点选每级菜单选项值都会发生变化,具体见上面的演示 | boolean | false |

View File

@ -115,7 +115,7 @@ function createPicker(TheCalendar, defaultFormat) {
pickerClass += ' ant-calendar-picker-open';
}
return (
<span className={pickerClass}>
<span className={pickerClass} style={this.props.style}>
<DatePicker
transitionName={this.props.transitionName}
disabled={this.props.disabled}
@ -138,7 +138,6 @@ function createPicker(TheCalendar, defaultFormat) {
onChange={this.handleInputChange}
value={value && this.getFormatter().format(value)}
placeholder={placeholder}
style={this.props.style}
className={`ant-calendar-picker-input ant-input${sizeClass}`} />
<span className="ant-calendar-picker-icon" />
</span>

View File

@ -16,4 +16,6 @@ export default class Dropdown extends React.Component {
Dropdown.defaultProps = {
transitionName: 'slide-up',
prefixCls: 'ant-dropdown',
mouseEnterDelay: 0.15,
mouseLeaveDelay: 0.1,
};

View File

@ -35,6 +35,9 @@ Form.propTypes = {
Form.defaultProps = {
prefixCls: 'ant-form',
onSubmit(e) {
e.preventDefault();
},
};
Form.childContextTypes = {

View File

@ -85,6 +85,8 @@ CustomizedForm = Form.create({})(CustomizedForm);
#### this.props.form.getFieldProps(id, options)
`getFieldProps` 返回的属性包括 `id`、`value`(或你设置的其它 `valuePropName`)、`ref`、`onChange`(或者你设置的其它 `trigger` `validateTrigger`),所以不应再设置同样的属性,以免冲突。如果对其返回值的细节有兴趣,可以 `console.log` 出来查看。
| 参数 | 说明 | 类型 | 可选值 |默认值 |
|-----------|------------------------------------------|------------|-------|--------|
| options.id | 必填输入控件唯一标志 | string | | |

View File

@ -30,6 +30,10 @@
<i class="anticon anticon-${type}"></i>
```
## 本地部署
图标组件使用 [iconfont.cn](http://iconfont.cn),默认公网可访问。如需本地部署,可参考 [示例](https://github.com/ant-design/antd-init/tree/master/examples/local-iconfont)。
## 图标列表
> 点击图标复制代码。

View File

@ -17,9 +17,9 @@
```html
<Menu>
<MenuItem>菜单项</MenuItem>
<Menu.Item>菜单项</Menu.Item>
<SubMenu title="子菜单">
<MenuItem>子菜单项</MenuItem>
<Menu.Item>子菜单项</Menu.Item>
</SubMenu>
</Menu>
```

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { PropTypes } from 'react';
import Dialog from 'rc-dialog';
import { Dom } from 'rc-util';
import Button from '../button';
@ -8,7 +8,7 @@ function noop() {}
let mousePosition;
let mousePositionEventBinded;
let AntModal = React.createClass({
const AntModal = React.createClass({
getDefaultProps() {
return {
prefixCls: 'ant-modal',
@ -26,6 +26,21 @@ let AntModal = React.createClass({
antLocale: React.PropTypes.object,
},
propTypes: {
prefixCls: PropTypes.string,
onOk: PropTypes.func,
onCancel: PropTypes.func,
okText: PropTypes.node,
cancelText: PropTypes.node,
width: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
confirmLoading: PropTypes.bool,
visible: PropTypes.bool,
align: PropTypes.object,
footer: PropTypes.node,
title: PropTypes.node,
closable: PropTypes.bool,
},
handleCancel(e) {
this.props.onCancel(e);
},

View File

@ -30,7 +30,8 @@
| footer | 底部内容 | React.Element | 确定取消按钮 |
| okText | 确认按钮文字 | String | 确定 |
| cancelText | 取消按钮文字 | String | 取消 |
| maskClosable | 点击蒙层是否允许关闭 | Boolean | true |
| maskClosable | 点击蒙层是否允许关闭 | Boolean | true |
| align | 浮层自定义位置 | Object, [dom-align](https://github.com/yiminghe/dom-align) | 距离顶部 100px |
### Modal.xxx()

View File

@ -2,7 +2,7 @@
- order: 1
位置有个方向。
位置有十二个方向。
---

View File

@ -2,7 +2,9 @@ import React from 'react';
import Tooltip from 'rc-tooltip';
import Icon from '../icon';
import Button from '../button';
import getPlacements from '../popover/placements';
const placements = getPlacements();
const prefixCls = 'ant-popover';
const noop = function () {};
const transitionNames = {
@ -55,12 +57,12 @@ export default React.createClass({
},
onVisibleChange(visible) {
this.setVisible(visible);
this.props.onVisibleChange(visible);
},
setVisible(visible) {
if (!('visible' in this.props)) {
this.setState({ visible });
}
this.props.onVisibleChange(visible);
},
render() {
const { title, placement, overlayStyle, trigger, ...restProps } = this.props;
@ -71,11 +73,11 @@ export default React.createClass({
}
const overlay = (
<div>
<div className={`${prefixCls}-content`}>
<p className={`${prefixCls}-message`}>
<div className={`${prefixCls}-inner-content`}>
<div className={`${prefixCls}-message`}>
<Icon type="exclamation-circle" />
{title}
</p>
<div className={`${prefixCls}-message-title`}>{title}</div>
</div>
<div className={`${prefixCls}-buttons`}>
<Button onClick={this.cancel} type="ghost" size="small">{cancelText || '取消'}</Button>
<Button onClick={this.confirm} type="primary" size="small">{okText || '确定'}</Button>
@ -87,7 +89,9 @@ export default React.createClass({
const transitionName = transitionNames[placement];
return (
<Tooltip {...restProps} placement={placement}
<Tooltip {...restProps}
placement={placement}
builtinPlacements={placements}
overlayStyle={overlayStyle}
prefixCls={prefixCls}
onVisibleChange={this.onVisibleChange}

View File

@ -19,7 +19,7 @@
| 参数 | 说明 | 类型 | 默认值 |
|-----------|------------------------------------------|---------------|--------|
| placement | 气泡框位置,可选 `top/left/right/bottom` | string | top |
| placement | 气泡框位置,可选 `top/left/right/bottom` `topLeft/topRight/bottomLeft/bottomRight` `leftTop/leftBottom/rightTop/rightBottom` | string | top |
| title | 确认框的描述 | string | 无 |
| onConfirm | 点击确认的回调 | function | 无 |
| onCancel | 卡片内容 | function | 无 |

View File

@ -1,6 +1,8 @@
import React from 'react';
import Tooltip from 'rc-tooltip';
import getPlacements from './placements';
const placements = getPlacements();
const prefixCls = 'ant-popover';
const Popover = React.createClass({
@ -33,6 +35,7 @@ const Popover = React.createClass({
return (
<Tooltip transitionName={transitionName}
builtinPlacements={placements}
ref="tooltip"
{...this.props}
overlay={this.getOverlay()}>
@ -49,7 +52,7 @@ const Popover = React.createClass({
return (
<div>
{this.props.title && <div className={`${prefixCls}-title`}>{this.props.title}</div>}
<div className={`${prefixCls}-content`}>
<div className={`${prefixCls}-inner-content`}>
{this.props.overlay}
</div>
</div>

View File

@ -0,0 +1,84 @@
const autoAdjustOverflow = {
adjustX: 1,
adjustY: 1,
};
const targetOffset = [0, 0];
export default function getPlacements(config = {}) {
const { arrowWidth = 5, horizontalArrowShift = 16, verticalArrowShift = 12 } = config;
return {
left: {
points: ['cr', 'cl'],
overflow: autoAdjustOverflow,
offset: [-4, 0],
targetOffset,
},
right: {
points: ['cl', 'cr'],
overflow: autoAdjustOverflow,
offset: [4, 0],
targetOffset,
},
top: {
points: ['bc', 'tc'],
overflow: autoAdjustOverflow,
offset: [0, -4],
targetOffset,
},
bottom: {
points: ['tc', 'bc'],
overflow: autoAdjustOverflow,
offset: [0, 4],
targetOffset,
},
topLeft: {
points: ['bl', 'tc'],
overflow: autoAdjustOverflow,
offset: [-(horizontalArrowShift + arrowWidth), -4],
targetOffset,
},
leftTop: {
points: ['tr', 'cl'],
overflow: autoAdjustOverflow,
offset: [-4, -(verticalArrowShift + arrowWidth)],
targetOffset,
},
topRight: {
points: ['br', 'tc'],
overflow: autoAdjustOverflow,
offset: [horizontalArrowShift + arrowWidth, -4],
targetOffset,
},
rightTop: {
points: ['tl', 'cr'],
overflow: autoAdjustOverflow,
offset: [4, -(verticalArrowShift + arrowWidth)],
targetOffset,
},
bottomRight: {
points: ['tr', 'bc'],
overflow: autoAdjustOverflow,
offset: [horizontalArrowShift + arrowWidth, 4],
targetOffset,
},
rightBottom: {
points: ['bl', 'cr'],
overflow: autoAdjustOverflow,
offset: [4, verticalArrowShift + arrowWidth],
targetOffset,
},
bottomLeft: {
points: ['tl', 'bc'],
overflow: autoAdjustOverflow,
offset: [-(horizontalArrowShift + arrowWidth), 4],
targetOffset,
},
leftBottom: {
points: ['br', 'cl'],
overflow: autoAdjustOverflow,
offset: [-4, verticalArrowShift + arrowWidth],
targetOffset,
},
};
}

View File

@ -16,15 +16,16 @@
| 参数 | 类型 | 默认值 |说明 |
|------------|----------------|-------------|--------------|
| range | Boolean | false | 双滑块模式
| min | Number | 0 | 最小值
| max | Number | 100 | 最大值
| step | Number or null | 1 | 步长,取值必须大于 0并且可被 (max - min) 整除。当 `marks` 不为空对象时,可以设置 `step``null`,此时 Slider 的可选值仅有 marks 标出来的部分。
| marks | Object {Number: String} | {} | 分段标记key 的类型必须为 `Number` 且取值在闭区间 [min, max] 内
| marks | Object {Number: String} | {} | 刻度标记key 的类型必须为 `Number` 且取值在闭区间 [min, max] 内
| dots | Boolean | false | 是否只能拖拽到刻度上
| value | Number or [Number, Number]| | 设置当前取值。当 `range``false` 时,使用 `Number`,否则用 `[Number, Number]`
| defaultValue | Number or [Number, Number]| 0 or [0, 0] | 设置初始取值。当 `range``false` 时,使用 `Number`,否则用 `[Number, Number]`
| included | Boolean | true | `marks` 不为空对象时有效,值为 true 时表示值为包含关系false 表示并列
| disabled | Boolean | false | 值为 `true` 时,滑块为禁用状态
| allowCross | Boolean | true | 当 `range``true` 时,该属性可以设置是否允许两个滑块交换位置。
| onChange | Function | NOOP | 当 Slider 的值发生改变时,会触发 onChange 事件,并把改变后的值作为参数传入。
| onAfterChange | Function | NOOP | 与 `onmouseup` 触发时机一致,把当前值作为参数传入。
| tipFormatter | Function or null | IDENTITY | Slider 会把当前值传给 `tipFormatter`,并在 Tooltip 中显示 `tipFormatter` 的返回值,若为 null则隐藏 Tooltip。

View File

@ -4,6 +4,8 @@
表格支持树形数据的展示,可以通过设置 `indentSize` 以控制每一层的缩进宽度。
> 注:暂不支持父子数据递归关联选择。
---
````jsx
@ -77,8 +79,21 @@ const data = [{
address: '我是b',
}];
// 通过 rowSelection 对象表明需要行选择
const rowSelection = {
onChange(selectedRowKeys, selectedRows) {
console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
},
onSelect(record, selected, selectedRows) {
console.log(record, selected, selectedRows);
},
onSelectAll(selected, selectedRows, changeRows) {
console.log(selected, selectedRows, changeRows);
}
};
ReactDOM.render(
<Table columns={columns} dataSource={data} indentSize={20} />,
<Table columns={columns} rowSelection={rowSelection} dataSource={data} />,
mountNode
);
````

View File

@ -33,7 +33,7 @@ for (let i = 0; i < 46; i++) {
const App = React.createClass({
getInitialState() {
return {
selectedRowKeys: [],
selectedRowKeys: [], // 这里配置默认勾选列
loading: false,
};
},

View File

@ -12,9 +12,7 @@ import { Table } from 'antd';
const columns = [{
title: '姓名',
dataIndex: 'name',
render(text) {
return <a href="#">{text}</a>;
}
render: text => <a href="#">{text}</a>,
}, {
title: '年龄',
dataIndex: 'age'
@ -43,19 +41,9 @@ const data = [{
const rowSelection = {
getCheckboxProps(record) {
return {
defaultChecked: record.name === '李大嘴', // 配置默认勾选的列
disabled: record.name === '胡彦祖' // 配置无法勾选的列
};
},
onChange(selectedRowKeys) {
console.log(`selectedRowKeys changed: ${selectedRowKeys}`);
},
onSelect(record, selected, selectedRows) {
console.log(record, selected, selectedRows);
},
onSelectAll(selected, selectedRows) {
console.log(selected, selectedRows);
},
};
ReactDOM.render(<Table rowSelection={rowSelection} columns={columns} dataSource={data} />

View File

@ -96,6 +96,7 @@ let FilterMenu = React.createClass({
let menus = (
<div className="ant-table-filter-dropdown">
<Menu multiple={multiple}
onClick={this.handleMenuItemClick}
prefixCls="ant-dropdown-menu"
onSelect={this.setSelectedKeys}
onDeselect={this.setSelectedKeys}

View File

@ -8,6 +8,7 @@ import Icon from '../icon';
import objectAssign from 'object-assign';
import Spin from '../spin';
import classNames from 'classnames';
import { flatArray } from './util';
function noop() {
}
@ -82,7 +83,7 @@ let AntTable = React.createClass({
if (!this.props.rowSelection || !this.props.rowSelection.getCheckboxProps) {
return [];
}
return this.getCurrentPageData()
return this.getFlatCurrentPageData()
.filter(item => this.props.rowSelection.getCheckboxProps(item).defaultChecked)
.map((record, rowIndex) => this.getRecordKey(record, rowIndex));
},
@ -98,7 +99,7 @@ let AntTable = React.createClass({
componentWillReceiveProps(nextProps) {
if (('pagination' in nextProps) && nextProps.pagination !== false) {
this.setState({
pagination: objectAssign({}, this.state.pagination, nextProps.pagination)
pagination: objectAssign({}, defaultPagination, this.state.pagination, nextProps.pagination)
});
}
// dataSource
@ -122,8 +123,10 @@ let AntTable = React.createClass({
this.setState({ selectedRowKeys });
}
if (this.props.rowSelection && this.props.rowSelection.onChange) {
const data = this.getCurrentPageData();
const selectedRows = data.filter(row => selectedRowKeys.indexOf(row.key) >= 0);
const data = this.getFlatCurrentPageData();
const selectedRows = data.filter(
(row, i) => selectedRowKeys.indexOf(this.getRecordKey(row, i)) >= 0
);
this.props.rowSelection.onChange(selectedRowKeys, selectedRows);
}
},
@ -164,9 +167,7 @@ let AntTable = React.createClass({
sorter,
};
this.setState(newState);
this.props.onChange.apply(this, this.prepareParamsArguments(
objectAssign({}, this.state, newState)
));
this.props.onChange(...this.prepareParamsArguments({ ...this.state, ...newState }));
},
handleFilter(column, nextFilters) {
@ -186,9 +187,7 @@ let AntTable = React.createClass({
};
this.setState(newState);
this.setSelectedRowKeys([]);
this.props.onChange.apply(this, this.prepareParamsArguments(
objectAssign({}, this.state, newState)
));
this.props.onChange(...this.prepareParamsArguments({ ...this.state, ...newState }));
},
handleSelect(record, rowIndex, e) {
@ -208,7 +207,7 @@ let AntTable = React.createClass({
});
this.setSelectedRowKeys(selectedRowKeys);
if (this.props.rowSelection.onSelect) {
let data = this.getCurrentPageData();
let data = this.getFlatCurrentPageData();
let selectedRows = data.filter((row, i) => {
return selectedRowKeys.indexOf(this.getRecordKey(row, i)) >= 0;
});
@ -228,7 +227,7 @@ let AntTable = React.createClass({
});
this.setSelectedRowKeys(selectedRowKeys);
if (this.props.rowSelection.onSelect) {
let data = this.getCurrentPageData();
let data = this.getFlatCurrentPageData();
let selectedRows = data.filter((row, i) => {
return selectedRowKeys.indexOf(this.getRecordKey(row, i)) >= 0;
});
@ -238,7 +237,7 @@ let AntTable = React.createClass({
handleSelectAllRow(e) {
const checked = e.target.checked;
const data = this.getCurrentPageData();
const data = this.getFlatCurrentPageData();
const defaultSelection = this.state.selectionDirty ? [] : this.getDefaultSelection();
const selectedRowKeys = this.state.selectedRowKeys.concat(defaultSelection);
const changableRowKeys = data.filter(item =>
@ -290,9 +289,7 @@ let AntTable = React.createClass({
pagination
};
this.setState(newState);
this.props.onChange.apply(this, this.prepareParamsArguments(
objectAssign({}, this.state, newState)
));
this.props.onChange(...this.prepareParamsArguments({ ...this.state, ...newState }));
},
onRadioChange(ev) {
@ -350,7 +347,7 @@ let AntTable = React.createClass({
renderRowSelection() {
let columns = this.props.columns.concat();
if (this.props.rowSelection) {
let data = this.getCurrentPageData().filter((item) => {
let data = this.getFlatCurrentPageData().filter((item) => {
if (this.props.rowSelection.getCheckboxProps) {
return !this.props.rowSelection.getCheckboxProps(item).disabled;
}
@ -471,11 +468,12 @@ let AntTable = React.createClass({
handleShowSizeChange(current, pageSize) {
const pagination = this.state.pagination;
pagination.onShowSizeChange(current, pageSize);
let nextPagination = objectAssign(pagination, {
pageSize,
});
const nextPagination = { ...pagination, pageSize, current };
this.setState({ pagination: nextPagination });
this.props.onChange(...this.prepareParamsArguments({
...this.state,
pagination: nextPagination,
}));
},
renderPagination() {
@ -516,8 +514,8 @@ let AntTable = React.createClass({
return this.props.columns.filter(c => this.getColumnKey(c) === myKey)[0];
},
getCurrentPageData(dataSource) {
let data = this.getLocalData(dataSource);
getCurrentPageData() {
let data = this.getLocalData();
let current;
let pageSize;
let state = this.state;
@ -541,9 +539,13 @@ let AntTable = React.createClass({
return data;
},
getLocalData(dataSource) {
getFlatCurrentPageData() {
return flatArray(this.getCurrentPageData());
},
getLocalData() {
let state = this.state;
let data = dataSource || this.props.dataSource;
let data = this.props.dataSource || [];
//
if (state.sortOrder && state.sorter) {
data = data.slice(0);

15
components/table/util.js Normal file
View File

@ -0,0 +1,15 @@
export function flatArray(data = [], childrenName = 'children') {
const result = [];
const loop = (array) => {
array.forEach(item => {
const newItem = { ...item };
delete newItem[childrenName];
result.push(newItem);
if (item[childrenName] && item[childrenName].length > 0) {
loop(item[childrenName]);
}
});
};
loop(data);
return result;
}

View File

@ -30,6 +30,7 @@ Ant Design 依次提供了三级选项卡,分别用于不同的场景。
| onTabClick | tab 被点击的回调 | Function | 无 |
| tabBarExtraContent | tab bar 上额外的元素 | React Node | 无 |
| type | 页签的基本样式,可选 `line`、`card` `editable-card` 类型 | String | 'line' |
| size | 大小,提供 `default``small` 两种大小 | String | 'default' |
| tabPosition | 页签位置,可选值有 `top` `right` `bottom` `left` | String | 'top' |
| onEdit | 新增和删除页签的回调,在 `type="editable-card"` 时有效 | Function(targetKey, action) | 无 |

View File

@ -1,5 +1,10 @@
import React from 'react';
import Tooltip from 'rc-tooltip';
import getPlacements from '../popover/placements';
const placements = getPlacements({
verticalArrowShift: 8,
});
export default React.createClass({
getDefaultProps() {
@ -42,6 +47,7 @@ export default React.createClass({
return (
<Tooltip transitionName={transitionName}
builtinPlacements={placements}
overlay={this.props.title}
visible={visible}
onVisibleChange={this.onVisibleChange}

View File

@ -8,6 +8,7 @@
````jsx
import { TreeSelect } from 'antd';
const SHOW_PARENT = TreeSelect.SHOW_PARENT;
const treeData = [{
label: '节点一',
@ -54,6 +55,7 @@ const Demo = React.createClass({
onChange: this.onChange,
multiple: true,
treeCheckable: true,
showCheckedStrategy: SHOW_PARENT,
searchPlaceholder: '请选择',
style: {
width: 300,

View File

@ -1,5 +1,5 @@
import React from 'react';
import TreeSelect, { TreeNode } from 'rc-tree-select';
import TreeSelect, { TreeNode, SHOW_ALL, SHOW_PARENT, SHOW_CHILD } from 'rc-tree-select';
import classNames from 'classnames';
const AntTreeSelect = React.createClass({
@ -42,4 +42,7 @@ const AntTreeSelect = React.createClass({
});
AntTreeSelect.TreeNode = TreeNode;
AntTreeSelect.SHOW_ALL = SHOW_ALL;
AntTreeSelect.SHOW_PARENT = SHOW_PARENT;
AntTreeSelect.SHOW_CHILD = SHOW_CHILD;
export default AntTreeSelect;

View File

@ -34,6 +34,7 @@
| size | 选择框大小,可选 `large` `small` | String | default |
| showSearch | 在下拉中显示搜索框 | boolean | false |
| disabled | 是否禁用 | boolean | false |
| showCheckedStrategy | `TreeSelect.SHOW_ALL`: 显示所有选中节点(包括父节点). `TreeSelect.SHOW_PARENT`: 只显示父节点(当父节点下所有子节点都选中时). 默认只显示子节点. | enum{TreeSelect.SHOW_ALL, TreeSelect.SHOW_PARENT, TreeSelect.SHOW_CHILD } | TreeSelect.SHOW_CHILD |
| treeDefaultExpandAll | 默认展开所有树节点 | bool | false |
| treeCheckable | 显示checkbox | bool | false |
| filterTreeNode | 是否根据输入项进行筛选返回值true | function(treeNode) | - |

View File

@ -142,7 +142,7 @@ const AntUpload = React.createClass({
targetItem.percent = e.percent;
this.onChange({
event: e,
file,
file: targetItem,
fileList: this.state.fileList
});
},

View File

@ -1,7 +1,7 @@
# Upload
- category: Components
- chinese: 文件上传
- chinese: 上传
- type: 表单
---

View File

@ -3,10 +3,10 @@
- order: 6
- chinese: 高级搜索
---
借助『高级搜索』,用户可以缩小复杂列表/表格等的展示范围。
---
## 常规型
### 交互
@ -53,4 +53,4 @@
字段型一般会出现在主搜索框底部,适合搜索条件和值都比较少的场景中。
## 案例(敬请期待)
## <span class="waiting">案例(敬请期待)</span>

View File

@ -3,10 +3,10 @@
- order: 5
- chinese: 表格:复杂数据
---
表格也用于展示复杂和高度结构化数据。
---
## 案例
### 多列数据

View File

@ -3,8 +3,6 @@
- order: 2
- chinese: 表单
---
作为获取用户输入的重要交互方式,表单也承担将问题和答案进行配对的角色。
设计者进行表单设计时,应当注意这几点:
@ -23,6 +21,8 @@
4. 不要提出不必要的问题。
---
## 内容
<img class="preview-img" align="right" alt="结构示例" src="https://os.alipayobjects.com/rmsportal/mLkQbODgVsdGUTe.png">
@ -106,7 +106,7 @@
### 字数校验框
<img class="preview-img" align="right" alt="字数校验框示例" src="https://os.alipayobjects.com/rmsportal/ziTMevqClLTYagX.png">
<img class="preview-img" align="right" alt="字数校验框示例" src="https://os.alipayobjects.com/rmsportal/JxzQIRfMCtMjuaH.png">
用于统计当前输入长度,以及是否超过系统阈值。

View File

@ -3,8 +3,6 @@
- order: 3
- chinese: 列表
---
列表是非常常见的界面元素,有多种使用场景:
- 获取概览
@ -13,6 +11,8 @@
- 排序与过滤
- 重新安排、添加、删除或重新分类列表项
---
## 交互
### 显示详情信息
@ -98,4 +98,4 @@
<br />
## 案例(敬请期待)
## <span class="waiting">案例(敬请期待)</span>

View File

@ -3,14 +3,14 @@
- order: 1
- chinese: 导航
---
在广义上,任何告知用户他在哪里,他能去什么地方以及如何到达那里的方式,都可以称之为导航。而我们将中后台常见的导航方式进行提炼和封装,帮助设计者快速构建清晰和流畅的系统。当设计者使用导航或者自定义一些导航结构时,请注意:
1. 尽可能提供标示、上下文线索以及网站地图,避免用户迷路;
2. 保持导航样式和行为一致或者减少导航数量,降低用户学习成本;
3. 尽可能减少页面间的跳转eg一个常见任务需要多个页面跳转时请减少至一至两次让用户移动距离保持简短。
---
## 常见导航
<Table style="font-size:12px;float:right;width:600px;margin-left:60px;margin-bottom:100px;">

View File

@ -3,10 +3,10 @@
- order: 4
- chinese: 表格
---
表格可被视为一种列表。它经常和其他界面元素一起协同,用于展示和操作结构化数据,并经常用于详情信息的入口。
---
## 内容
<img class="preview-img" align="right" alt="结构示例" src="https://os.alipayobjects.com/rmsportal/zFqqEqKKAylKkxv.png">
@ -154,4 +154,4 @@
数值右对齐(带小数则按小数点对齐),其余左对齐。
## 案例(敬请期待)
## <span class="waiting">案例(敬请期待)</span>

View File

@ -5,9 +5,9 @@
---
Ant Design 是面向中台的 UI 设计语言。
Ant Design 是面向中台的 UI 设计语言。
从 2015 年 4 月起Ant Design 在蚂蚁金服中后台产品线迅速推广,对接多条业务线,覆盖系统 40 个以上。定位于中台业务的 Ant Design 兼顾专业和非专业的设计人员,具有学习成本低、上手速度快、实现效果好等特点,并且提供从界面设计到前端开发的全链路生态,可以大大提升设计和开发的效率。
从 2015 年 4 月起Ant Design 在蚂蚁金服中后台产品线迅速推广,对接多条业务线,覆盖系统 40 个以上。定位于中台业务的 Ant Design 兼顾专业和非专业的设计人员,具有学习成本低、上手速度快、实现效果好等特点,并且提供从界面设计到前端开发的全链路生态,可以大大提升设计和开发的效率。
Ant Design 目前在外部也有 [许多产品实践](https://github.com/ant-design/ant-design/issues/477),如果你的公司和产品从中受益,欢迎留言。

View File

@ -2,10 +2,10 @@
- order: 1
---
Ant Design React 致力于提供给程序员**愉悦**的开发体验。
---
## 第一个例子
最简单的试用方式参照以下 CodePen 演示,也推荐 Fork 本例来进行 `Bug Report`,注意不要在实际项目中这样使用。
@ -118,7 +118,7 @@ Ant Design React 支持所有的现代浏览器和 IE8+。
<!-- 引入样式 -->
<link rel="stylesheet" href="/index.css">
<!-- Polyfills -->
<script src="https://as.alipayobjects.com/g/component/??console-polyfill/0.2.2/index.js,es5-shim/4.1.14/es5-shim.min.js,es5-shim/4.1.14/es5-sham.min.js,html5shiv/3.7.2/html5shiv.min.js,media-match/2.0.2/media.match.min.js"></script>
<script src="https://as.alipayobjects.com/g/component/??console-polyfill/0.2.2/index.js,es5-shim/4.5.7/es5-shim.min.js,es5-shim/4.5.7/es5-sham.min.js,html5shiv/3.7.2/html5shiv.min.js,media-match/2.0.2/media.match.min.js"></script>
</head>
<body>
</body>
@ -129,10 +129,6 @@ Ant Design React 支持所有的现代浏览器和 IE8+。
</html>
```
另外,由于 babel 对 IE8 的支持不佳,你可能会遇到类似 [#28](https://github.com/ant-tool/atool-build/issues/28) 和 [#858](https://github.com/ant-design/ant-design/issues/858) 的 default 报错的问题。
[antd-init](http://github.com/ant-design/antd-init) 脚手架已经解决了这个问题,你也可以参照这个 [webpack 配置](https://github.com/ant-design/antd-init/blob/8c4a55d205c82a6ad87814bbf997696051713d58/boilerplate/webpack.config.js#L10-L14)。
> 更多 IE8 下使用 React 的相关问题可以参考https://github.com/xcatliu/react-ie8
## 自行构建

View File

@ -2,8 +2,6 @@
- order: 0
---
这里是 Ant Design 的 React 实现,开发和服务于企业级后台产品。
<div class="pic-plus">
@ -23,6 +21,7 @@
}
</style>
---
## 特性
@ -77,7 +76,10 @@ import 'antd/lib/index.css'; // or 'antd/style/index.less'
## 谁在使用
- 蚂蚁金服
- 阿里巴巴
- 口碑
- 新美大
- 滴滴
> 如果你的公司和产品使用了 Ant Design欢迎到 [这里](https://github.com/ant-design/ant-design/issues/477) 留言。

View File

@ -4,13 +4,15 @@
---
这里只列出升级中的不兼容改动,其他改动见 [Changelog](/changelog)。
## 0.11 => 0.12
---
### 使用 Form 提供的校验功能代替 Validation
Validation 已经被废弃,并会在以后的版本完全移除,所以建议尽快使用 Form 自带的校验功能替换 Validation。具体使用方式可以查阅文档和例子([#1](http://ant.design/components/form/#demo-validate-basic) [#2](http://ant.design/components/form/#demo-validate-other) [#3](http://ant.design/components/form/#demo-validate-customized))
Validation 已经被废弃,并会在以后的版本完全移除,所以建议尽快使用 Form 自带的校验功能替换 Validation。具体使用方式可以查阅文档和例子[#1](http://ant.design/components/form/#demo-validate-basic) [#2](http://ant.design/components/form/#demo-validate-other) [#3](http://ant.design/components/form/#demo-validate-customized)
### Progress `format` 属性的值改为函数

37
docs/spec/alignment.md Normal file
View File

@ -0,0 +1,37 @@
# 对齐
- category: 十大原则
- order: 2
- subtitle: Alignment
正如『格式塔学派』中的连续律Law of Continuity所描述的在知觉过程中人们往往倾向于使知觉对象的直线继续成为直线使曲线继续成为曲线。在界面设计中将元素进行对齐既符合用户的认知特性也能引导视觉流向让用户更流畅地接收信息。
> ** 格式塔学派德语Gestalttheorie** :是心理学重要流派之一,兴起于 20 世纪初的德国,又称为完形心理学;主张人脑的运作原理是整体的,『整体不同于其部件的总和』。——摘自『维基百科』
---
## 文案类对齐
<img class="preview-img good" align="right" alt="推荐示例" description="标题和正文左对齐,使用了一个视觉起点。" src="https://os.alipayobjects.com/rmsportal/xvmiAZAIxrEcqdP.png">
<img class="preview-img bad" align="right" alt="不推荐示例" description="标题和正文使用了两个视觉起点,不推荐该种对齐方式,除非刻意强调两者区别。" src="https://os.alipayobjects.com/rmsportal/qvycImsTiDGVgLJ.png">
如果页面的字段或段落较短、较散时,需要确定一个统一的视觉起点。
---
## 表单类对齐
<img class="preview-img" noPadding align="right" alt="冒号对齐示例" src="https://os.alipayobjects.com/rmsportal/DmEbaUsrpJkRyUh.png">
冒号对齐(右对齐)能让内容锁定在一定范围内,让用户眼球顺着冒号的视觉流,就能找到所有填写项,从而提高填写效率。
更多对齐方式,请查看[『模式/表单/规格/对齐方式』](../pattern/form#对齐方式)。
---
## 数字类对齐
<img class="preview-img good" align="right" alt="正确示例" src="https://os.alipayobjects.com/rmsportal/hCSQTEmahFyQcWk.png">
<img class="preview-img bad" align="right" alt="错误示例" src="https://os.alipayobjects.com/rmsportal/FDjScmPlWFPxkxL.png">
为了快速对比数值大小,建议所有数值取相同有效位数,并且右对齐。

View File

@ -1,6 +1,6 @@
# Colors
- category: 基础
- category: 设计基础
- order: 2
- chinese: 色彩
@ -10,7 +10,7 @@
色彩在界面设计中的使用应同时具备品牌识别性以及界面设计功能性。众所周知色彩是相当感性的东西,设计中对色彩的运用首要应考虑到品牌层面的表达,另外很重要的一点是色彩的运用应达到信息传递,动作指引,交互反馈,或是强化和凸现某一个元素的目的。任何颜色的选取和使用应该是有意义的。众所周知色彩是相当感性的东西,设计中对色彩的运用首要应考虑到品牌层面的表达,另外很重要的一点是色彩的运用应达到信息传递,动作指引,交互反馈,或是强化和凸现某一个元素的目的。任何颜色的选取和使用应该是有意义的。
## ANTD Color
## Ant Design Colors
Ant Design 的色板由 9 种基本色彩组成,每种基本色又衍生出九宫格色板,在此基础上还可以通过黑白叠加的方式实现色彩明暗的效果。

48
docs/spec/contrast.md Normal file
View File

@ -0,0 +1,48 @@
# 对比
- category: 十大原则
- order: 3
- subtitle: Contrast
对比是增加视觉效果最有效方法之一,同时也能在不同元素之间建立一种有组织的层次结构,让用户快速识别关键信息。
> 注:要实现有效的对比,对比就必须强烈,切不可畏畏缩缩。
---
## 主次关系对比
<img class="preview-img good" align="right" alt="正确示例" src="https://os.alipayobjects.com/rmsportal/RruKZUSYEwauGdF.png">
<img class="preview-img bad" align="right" alt="错误示例" src="https://os.alipayobjects.com/rmsportal/TOupLSPNQkBTmYw.png">
为了让用户能在操作上(类似表单、弹出框等场景)快速做出判断, 来突出其中一项相对更重要或者更高频的操作。
> 注意:突出的方法,不局限于强化重点项,也可以是弱化其他项。
<br>
<img class="preview-img" align="right" alt="不区分主次的示例" decription="『通过』和『驳回』都使用次按钮,系统保持中立。" src="https://os.alipayobjects.com/rmsportal/xskurfmyKPumFSv.png">
在一些需要用户慎重决策的场景中,系统应该保持中立,不能替用户或者诱导用户做出判断。
---
## 总分关系对比
<img class="preview-img" align="right" alt="总分关系示例 1" src="https://os.alipayobjects.com/rmsportal/HEDJpTyufnfXUOP.png">
<img class="preview-img" align="right" alt="总分关系示例 2" src="https://os.alipayobjects.com/rmsportal/bafqoUWFgXjsuSG.png">
通过调整排版、字体、大小等方式来突出层次感,区分总分关系,使得页面更具张力和节奏感。
---
## 状态关系对比
<img class="preview-img" align="right" alt="静态对比示例" description="用不同颜色点,来表明不同状态。" src="https://os.alipayobjects.com/rmsportal/UHjarNwxrXndznP.png">
<img class="preview-img" align="right" alt="动态对比示例" description="鼠标悬停时,该项和其他项呈现出明显不同的视觉效果,响应用户操作。" src="https://os.alipayobjects.com/rmsportal/DCAtXAEaFnAXEmG.png">
通过改变颜色、增加辅助形状等方法来实现状态关系的对比,以便用户更好的区分信息。
常见类型有『静态对比』、『动态对比』。

65
docs/spec/direct.md Normal file
View File

@ -0,0 +1,65 @@
# 直截了当
- category: 十大原则
- order: 5
- subtitle: Make it Direct
正如 Alan Cooper 所言『需要在哪里输出就要允许在哪里输入』。这就是直接操作的原理。eg不要为了编辑内容而打开另一个页面应该直接在上下文中实现编辑。
---
## 页内编辑
<img class="preview-img" align="right" alt="单击编辑示例" description="状态一:普通的浏览模式,不区分可编辑行和不可编辑行;<br>状态二鼠标悬停时『指针』变为『手型』编辑区域底色变黄出现『Tooltips』提示单击编辑<br>状态三:鼠标点击后,出现『输入框』、『确定』、『取消』表单元素,同时光标定位在『输入框』中。" src="https://os.alipayobjects.com/rmsportal/PmVuUUKeamHdveT.png">
单字段行内编辑
当『易读性』远比『易编辑性』重要时,可以使用『单击编辑』。
<br>
<img class="preview-img" align="right" alt="文字链/图标编辑示例" description="状态一:在可编辑行附近出现文字链/图标;<br>状态二:鼠标点击『编辑』后,出现『输入框』、『确定』、『取消』表单元素,同时光标定位在『输入框』中。" src="https://os.alipayobjects.com/rmsportal/ZmRlahliUbCurhu.png">
当『易读性』为主,同时又要突出操作行的『易编辑性』时,可使用『文字链/图标编辑』。
<br>
<img class="preview-img" align="right" alt="多字段行内编辑示例" description="编辑模式在不破坏整体性的前提下,可扩大空间,以便放下『输入框』等表单元素;其中,在 Table 中进行编辑模式切换时,需要保证每列的不跳动。" src="https://os.alipayobjects.com/rmsportal/hGXGErepBnrwqzj.png">
多字段行内编辑
>注:在『多字段行内编辑』的情况下,显示的内容和编辑时所需的字段会存在比较大的差异,所以更需要『巧用过渡』原则中的[『解释刚刚发生了什么』](../spec/transition#解释刚刚发生了什么)来消除这种视觉影响。
<br>
更多有关『页内编辑』的模式,可查看[『模式/表格/交互』](../pattern/table#模块编辑)中的内容。
<br>
---
## 利用拖放
<img class="preview-img" align="right" alt="拖放列表示例" description="状态一:鼠标悬停该行时,出现可移动的『图标』;<br>状态二:鼠标悬停在该『图标』时,指针变为『手型』,点击即可进行拖动;<br>状态三:拖动到可放置区块,出现蓝色描边,告知用户该区块可放置该对象。" src="https://os.alipayobjects.com/rmsportal/DjMFcqSxZrulbGF.png">
拖放列表
只能限制在一个维度(上/下或者左/右)进行拖放。
<br>
<img class="preview-img" align="right" alt="拖放图片/文件示例" src="https://os.alipayobjects.com/rmsportal/KVhqdSoLUjXPXuN.png">
拖放图片/文件
<br>
<span class="waiting">拖放对象(敬请期待)</span>
<span class="waiting">拖放多个对象(敬请期待)</span>
<br>
---
## <span class="waiting">直接选择(敬请期待)</span>

View File

@ -15,7 +15,7 @@
当某个东西往下掉时,首先是越掉越快,撞到地上后回弹,最终才又碰触地板。
### 质量和重量
## 质量和重量
在物理世界里,是以力量附加到物体对象里,加上自身的质量才完成一段动画。力量的持续时间决定物体的加速,减速与改变方向。

108
docs/spec/feature.md Normal file
View File

@ -0,0 +1,108 @@
# 三大特性
- order: 1
与众不同的是Ant Design 不但追求『用户』的使用体验,还追求『设计者』的使用体验,真真正正贯彻和践行『以人为本』的设计理念。
<div style="margin-left:-40px;margin-right:-40px;overflow:hidden;">
<div class="col-8 features">
<img src="https://os.alipayobjects.com/rmsportal/OVirOHTeAdzDBuQ.png">
<h5>微小</h5>
<div>致力于微小而美好的改变,力求在细节上精益求精,不仅让业务产品更加实用和可靠,而且还能让『用户』感到小惊喜。</div>
</div>
<div class="col-8 features">
<img src="https://os.alipayobjects.com/rmsportal/iJbUiLYpuPBXUhV.png">
<h5>确定</h5>
<div>制定通俗而科学的设计原则、运用面向对象的方法、使用一致的文档沟通机制,给予研发团队一种高确定性、低熵值的研发状态。</div>
</div>
<div class="col-8 features">
<img src="https://os.alipayobjects.com/rmsportal/uSOjjlCRjRIhtIY.png">
<h5>幸福</h5>
<div>不苛求简单,但是力求让『用户』和『设计者』流畅的完成目标,并带着成功和满足离开。</div>
</div>
</div>
<style>
.features {
padding: 0 40px;
font-size: 12px;
}
.features h5 {
font-size: 14px;
margin-top: 16px;
}
@media only screen and (min-width: 320px) and (max-width: 767px) {
.features {
width: 100%;
text-align: center;
margin-bottom: 20px;;
}
.features img {
width: 80%;
}
}
</style>
---
## 微小
### 微创新
<img class="preview-img" align="right" alt="数值输入框示例" description="鼠标『悬停』时,可点击区域会放大。" src="https://os.alipayobjects.com/rmsportal/GGXdyrOtvUtOKXe.png">
<img class="preview-img" align="right" alt="分页示例" description="鼠标点击省略符,可以实现批量切换。" src="https://os.alipayobjects.com/rmsportal/UEYPnVhQsOjytSa.png">
<img class="preview-img" align="right" alt="字数校验框示例" description="使用颜色和下划线标注超出的文案,系统即时反应,以便用户进行调整。" src="https://os.alipayobjects.com/rmsportal/JxzQIRfMCtMjuaH.png">
『不同』不一定『更好』,但是『更好』一定『不同』。不断追求细节上的『更好』,使得我们的组件和同类产品都不一样,自然而然的『不同』。
### 集成创新
<img class="preview-img" align="right" alt="填空示例" description="组合了标签和输入项,可以帮助用户理解当前的状况,以及需要提供什么数据。" src="https://os.alipayobjects.com/rmsportal/RGFMJRSgCAVCKOl.png">
<img class="preview-img" align="right" alt="带图表的表格" description="组合了 Table 和 Chart ,鼠标『悬停』时展现更多详情内容。" src="https://os.alipayobjects.com/rmsportal/hjHOMRIbvIUUBXS.png">
选择合适的组件进行组合和集成,形成优势互补的创新过程,来满足多变的业务需求。
---
## 确定
### 面向对象的方法
<img class="preview-img" align="right" alt="色值换算工具示例" description="定义『原色』后,用『加黑』和『加白』的方式快速、科学的得出 Normal、Hover 等多个『状态色』。" src="https://os.alipayobjects.com/rmsportal/MqsXoBBSDmoEDqn.png">
<img class="preview-img" align="right" alt="排版规则示例" description="运用『亲密性』原则,只需定义 n 的值,就可以得出确定的间距。" src="https://os.alipayobjects.com/rmsportal/WNEbRORxzEvvFKy.png">
<img class="preview-img" noPadding align="right" alt="操作反馈 - 正确示例" description="将可被通用的文案抽象成『确定』、『操作』等通用术语,集中进行调用和维护。虽然『用户』体验 -1 分,但是『设计者』体验 +5 分。" good src="https://os.alipayobjects.com/rmsportal/rtbYGKfPOpWRJID.png">
<img class="preview-img" noPadding align="right" alt="操作反馈 - 错误示例" bad description="这是体验更好的反馈方式,但是对『设计者』来说是灾难。因为这些『删除』文案只能通过人肉维护,难免产生遗漏和错别字,增大了系统的不确定性,这在多人合作和需求变更时尤为明显。" src="https://os.alipayobjects.com/rmsportal/OWLtvGCGmqawyPt.png">
探索设计规律,并将其抽象成『对象』,增强界面设计的灵活性和可维护性,同时也减少『设计者』的主观干扰,从而降低系统的不确定性。
### 通俗而科学的设计原则
详见[『十大原则』](./principle)。
---
## 幸福
### 用户的幸福
<img class="preview-img" noPadding align="right" alt="用户的幸福示例" description="想了解更多内容可阅读唐纳德•A•诺曼所著的 《设计心理学 3》。" src="https://os.alipayobjects.com/rmsportal/sBjNEGgHEpNfqTs.png">
漂亮的组件、精致的排版、流畅的动画等的元素,使用户在『本能层次』中产生积极反应;
良好的功能、性能和可用性,使用户在『行为层次』中产生积极反应;
自我形象、个人满足和美好记忆,使用户在『反思层次』中体验思想和情感的交融。
### 设计者的幸福
<img class="preview-img" noPadding align="right" alt="设计者的幸福示例" description="Ant Design 无法保证业务产品能否成功,但是能帮助业务产品『正确的成功』或者『正确的失败』。" src="https://os.alipayobjects.com/rmsportal/eMcdBWuZxRbvlvW.png">
从『无』到『有』时,提供一整套设计解决方案,帮助『设计者』将商业想法快速形成产品并推向市场,快速、低成本试错。
从『有』到『优』时,提供一系列自定义建议,帮助『设计者』塑造产品个性并提升整体体验,服务海量用户。

View File

@ -1,12 +1,12 @@
# 字体
- category: 基础
- category: 设计基础
- order: 0
---
跨平台的字体设定,力求在各个操作系统下都有最佳展示效果。
---
## 字体家族
- 中文字体族:

View File

@ -2,20 +2,23 @@
- order: 0
<div style="text-align:center;background:#FBFBFB;margin:40px 0;">
<img align="middle" width="600" src="https://os.alipayobjects.com/rmsportal/mgesTPFxodmIwpi.png">
</div>
在中台产品的研发过程中,会出现不同的设计规范和实现方式,但其中往往存在很多类似的页面和组件,给设计师和工程师带来很多困扰和重复建设,大大降低了产品的研发效率。我们(蚂蚁金服体验技术部)经过大量的项目实践和总结,沉淀出一个中台设计语言 Ant Design。旨在统一中台项目的前端 UI 设计,屏蔽不必要的设计差异和实现成本,解放设计和前端的研发资源。
Ant Design 是一个致力于提升『用户』和『设计者』使用体验的中台设计语言。它模糊了产品经理、交互设计师、视觉设计师、前端工程师、开发工程师等角色边界,将进行 UE 设计和 UI 设计人员统称为『设计者』,利用统一的规范进行设计赋能,全面提高中台产品体验和研发效率。
---
Ant Design 是一个 UI 设计语言,是一套提炼和应用于企业级中后台产品的交互语言和视觉体系。
<img width="300" src="https://t.alipayobjects.com/images/rmsweb/T1B9hfXcdvXXXXXXXX.svg">
Ant Design 源自蚂蚁金服体验技术部的后台产品开发。在中后台产品设计中,通常有很多类似的页面和控件,不同的产品会出现不同的规范和实现,给设计师和工程师带来很多困扰和重复建设,降低企业后台的整体研发效率。我们的设计师和前端工程师经过大量的项目实践和总结,希望能沉淀出一套企业级的交互视觉规范,统一中后台项目的前端 UI 设计,屏蔽各种不必要的设计差异和前端实现成本,解放设计和前端开发资源。
整套设计规范还在持续整理和完善中。
## 谁在使用
- 蚂蚁金服
- 阿里巴巴
- 口碑
- 新美大
- 滴滴
> 如果你的公司和产品使用了 Ant Design欢迎到 [这里](https://github.com/ant-design/ant-design/issues/477) 留言。

82
docs/spec/invitation.md Normal file
View File

@ -0,0 +1,82 @@
# 提供邀请
- category: 十大原则
- order: 8
- subtitle: Provide Invitation
很多富交互模式eg『拖放』、『行内编辑』、『上下文工具』都有一个共同问题就是缺少易发现性。所以『提供邀请』是成功完成人机交互的关键所在。
邀请就是引导用户进入下一个交互层次的提醒和暗示通常包括意符eg实时的提示信息和可供性以表明在下一个界面可以做什么。当可供性中可感知的部分Perceived Affordance表现为意符时人机交互的过程往往更加自然、顺畅。
> ** 意符Signifiers** 一种额外的提示告诉用户可以采取什么行为以及应该怎么操作必须是可感知eg视觉、听觉、触觉等。——摘自《设计心理学 1 》
> ** 可供性Affordance** :也被翻译成『示能』,由 James J. Gibson 提出,定义为物品的特性与决定物品用途的主体能力之间的关系;其中部分可感知(此部分定义为 Perceived Affordance部分不可感知。——摘自《设计心理学 1 》
---
## 静态邀请
指通过可视化技术在页面上提供引导交互的邀请。
<br>
<img class="preview-img" align="right" alt="文本邀请示例" src="https://os.alipayobjects.com/rmsportal/pWnlJpbkCPIaKdP.png">
<img class="preview-img" align="right" alt="白板式邀请示例" src="https://os.alipayobjects.com/rmsportal/DkOYgfJHDuzhyBg.png">
<img class="preview-img" align="right" alt="未完成邀请示例" src="https://os.alipayobjects.com/rmsportal/cojQlWfINmsVDGd.png">
引导操作邀请:一般以静态说明形式出现在页面上,不过它们在视觉上也可以表现出多种不同样式。
常见类型:『文本邀请』、『白板式邀请』、『未完成邀请』。
<br>
<img class="preview-img" align="right" alt="漫游探索邀请示例 1" description="在用户首次登陆时出现少量『探索点』,当用户点击『我知道了』,能快速切换到下一个探索点。" src="https://os.alipayobjects.com/rmsportal/TGnzYViseCoFBYL.png">
<img class="preview-img" align="right" alt="漫游探索邀请示例 2" src="https://os.alipayobjects.com/rmsportal/KQabdaTbolVuMld.png">
漫游探索邀请:是向用户介绍新功能的好方法,尤其是对于那些设计优良的界面。但是它不是『创口贴』,仅通过它不能解决界面交互的真正问题。
>注:保持漫游过程简单,让用户容易退出和重新启动;保持内容简明扼要,与功能密切相关。
<br>
---
## 动态邀请
指以响应用户在特定位置执行特定操作的方式,提供特定的邀请。
<br>
<img class="preview-img" align="right" alt="悬停邀请示例 1" description="鼠标『悬停』整个卡片时,可被点击部分变为蓝色的『文字链』。" src="https://os.alipayobjects.com/rmsportal/gzfDJLcETyTOfFg.png">
<img class="preview-img" align="right" alt="悬停邀请示例 2" description="鼠标『悬停』时,出现『选择此模板』的按钮。" src="https://os.alipayobjects.com/rmsportal/tdJWZFIDWYuMVIe.png">
悬停邀请:在鼠标悬停期间提供邀请。
<br>
<img class="preview-img" align="right" alt="推论邀请示例" description="用户点击『赞』后,同时系统分析(既然用户喜欢这篇文章,那么可能对这一类文章都有兴趣)并提供开启『精打细算』的邀请。" src="https://os.alipayobjects.com/rmsportal/SyurwytfcvpbNLG.png">
推论邀请:用于交互期间,合理推断用户可能产生的需求。
<br>
<img class="preview-img" align="right" alt="更多内容邀请示例" description="在 Modal 中会出现前后切换的箭头。" src="https://os.alipayobjects.com/rmsportal/sOqYOydwQjLHqph.png">
更多内容邀请:用于邀请用户查看更多内容。
<br>
<br>
<span class="waiting">预期功能邀请 (敬请期待)</span>
<br>
<span class="waiting">拖放邀请 (敬请期待)</span>

View File

@ -1,7 +1,7 @@
# Layout
- template: component
- category: 基础
- category: 设计基础
- order: 4
- cols: 1
- chinese: 常用布局

76
docs/spec/lightweight.md Normal file
View File

@ -0,0 +1,76 @@
# 简化交互
- category: 十大原则
- order: 6
- subtitle: Keep it Lightweight
根据费茨法则Fitts's Law所描述的如果用户鼠标移动距离越少、对象相对目标越大那么用户越容易操作。通过运用上下文工具放在内容中的操作工具使内容和操作融合从而简化交互。
> ** 费茨法则 ** :到达目标的时间是到达目标的距离与目标大小的函数,具体:<img src="https://os.alipayobjects.com/rmsportal/wAcbQmeqTWDqsnu.png" width="150" />。其中1.设备当前位置和目标位置的距离D2.目标的大小W。距离越长所用时间越长目标越大所用时间越短。
---
## 实时可见工具
<img class="preview-img" align="right" alt="实时可见工具示例 --摘自知乎" description="状态一:在文案中出现一个相对明显的点击区域;<br>状态二:鼠标悬停时,鼠标『指针』变为『手型』,底色发生变化,邀请用户点击。<br>状态三:鼠标点击后,和未点击前有明显的区分。" src="https://os.alipayobjects.com/rmsportal/sfytaOSssRrdYFg.png">
如果某个操作非常重要,就应该把它放在界面中,并实时可见。
<br>
---
## 悬停即现工具
<img class="preview-img" align="right" alt="悬停即现工具示例" description="鼠标悬停时,出现操作项。" src="https://os.alipayobjects.com/rmsportal/AUiWMlbxCvpBFyA.png">
如果某个操作不那么重要,或者使用『实时可见工具』过于啰嗦会影响用户阅读时,可以在悬停在该对象上时展示操作项。
<br>
---
## 开关显示工具
<img class="preview-img" align="right" alt="开关显示工具示例" description="用户点击『修改』后Table 中『文本』变成『输入框』,开启编辑功能。" src="https://os.alipayobjects.com/rmsportal/uGWcpAFgWdynxBy.png">
如果某些操作只需要在特定模式时显示,可以通过开关来实现。
<br>
---
## 交互中的工具
<img class="preview-img" align="right" alt="推荐示例" description="鼠标悬停时,出现 Tooltips 进行提示,用户点击内容直接复制。" src="https://os.alipayobjects.com/rmsportal/STvIHSgnVAHOVHl.png" good>
<img class="preview-img" align="right" alt="推荐示例" description="鼠标滑选/双击时,系统自动复制该部分内容。通过大胆猜测用户的行为,并帮助完成,给用户小惊喜。" src="https://os.alipayobjects.com/rmsportal/aRihOoBCQHGATBA.png" good>
<img class="preview-img" align="right" alt="不推荐示例" description="在可复制内容的附近出现『图标』,点击后复制。" src="https://os.alipayobjects.com/rmsportal/MfbnQfAJhQfIODY.png" bad>
如果操作不重要或者可以通过其他途径完成时,可以将工具放置在用户的操作流程中,减少界面元素,降低认知负担,给用户小惊喜。
此处也可以运用[『提供邀请』](../spec/invitation) 相关的知识点。
<br>
---
## 可视区域 ≠ 可点击区域
<img class="preview-img" align="right" alt="文字链热区示例" description="当悬浮在 ID 所在的文字链单元格时,鼠标『指针』随即变为『手型』,单击即可跳转。" src="https://os.alipayobjects.com/rmsportal/bCrBxGPJiDvkyOH.png">
在使用 Table 时,文字链的点击范围受到文字长短影响,可以设置整个单元格为热区,以便用户触发。
<br>
<img class="preview-img" align="right" alt="按钮热区示例" description="鼠标移入按钮附近,即可激活 Hover 状态。" src="https://os.alipayobjects.com/rmsportal/dSehXwUuXDFDhJO.png">
当需要增强按钮的响应性时,可以通过增加用户点击热区的范围,而不是增大按钮形状,从而增强响应性,又不缺失美感。
>注:在移动端尤其适用。

View File

@ -14,7 +14,6 @@ const Select = antd.Select;
const Option = Select.Option;
const OptGroup = Select.OptGroup;
let motions = [];
motions = motions.concat([[{
name: '淡入',

View File

@ -1,77 +0,0 @@
# Page Transition
- category: 动画
- order: 1
- chinese: 互动转换
---
## 响应互动
响应交互一般是指我们在浏览页面时,点击元素时动画给我们视觉上的反馈,每个交互动效都能给我们带来不同视觉效果。
比如:按钮上的 hover 或 click 效果,随着你的鼠标事件而改变自身或增加元素在按钮上,或者折叠面板和弹出框,点击后给你呈现新加入的信息元素。
### 按钮反馈
<div class="video-player">
</div>
## 转换动画
### 视觉连贯性三元素
- Adding:  新加入的信息元素应被告知如何使用,从页面转变的信息元素需被重新识别。
- Receding:  与当前页无关的信息元素应采用适当方式移除。
- Normal: 指那些从转场开始到结束都没有发生变化的信息元素。
### 可折叠面板
对于信息元素内容区域的延伸,显示信息元素和进一步内容对象之间的直接连接。
- 被展开的信息区域内容按照一定的路径依次进场。
<div class="video-player">
</div>
### 弹出框动效
从一个触发点触发一个弹出框时,弹框从所触发区域弹出,且触发区域视觉上基本保持不变。这样让触发区域和弹出区域有所关联,提高用户对新内容的认知。
<div class="video-player">
</div>
### 页面转场
从内容A到内容B的转变过程时能有效的吸引用户注意力突出视觉中心提高整体视觉效果。
- 大页面转场可采用左出右入的形式。
- 小的信息元素排布或块状较多的情况下,根据一定的路径层次依次进场,区分维度层级,来凸显量级,来指引用户的视觉轨迹。
<div class="video-player">
</div>
> 参考我们的进场组件案例。查看[进场动画组件(QueueAnim)](/components/queue-anim/)
```__react
import scripts from '../../site/component/Motion/page-transition';
class ExecuteJS extends React.Component {
componentDidMount() {
scripts();
}
render() {
return null;
}
}
ReactDOM.render(<ExecuteJS key="execute" />, mountNode);
```

45
docs/spec/principle.md Normal file
View File

@ -0,0 +1,45 @@
# 引言
- category: 十大原则
- order: 0
- subtitle: Introduction
『好设计比差设计更难发现』,因为好设计是如此的自然,帮助用户轻松的完成目标,以至于用户根本意识不到好设计的存在。
我们借鉴了《写给大家看的设计书》、《Web 界面设计》对设计原则的总结和推理,并结合我们团队的实践和理解,制定了以下十大原则,为『设计者』提供解决具体问题的准则和启示。
> 注:设计原则是对具象设计的抽象和总结,然而产品是一个整体,用户对整个产品的认知也是从全局到局部,所以忽略全局,只在局部套用原则是不可取的。对于这些原则,『设计者』应当理性地学会它,而后勇敢地抛弃它。
---
<div class="resource-cards">
<a target="_blank" href="http://book.douban.com/subject/3323633/" class="resource-card">
<img src="https://os.alipayobjects.com/rmsportal/SNdJVyZaZwdwJmr.png">
<span class="resource-card-content">
<span class="resource-card-title">写给大家看的设计书</span>
<span class="resource-card-description">作者: Robin Williams</span>
<span class="resource-card-description">出版社: 人民邮电出版社</span>
</span>
</a>
<a target="_blank" href="http://book.douban.com/subject/3821157/" class="resource-card">
<img src="https://os.alipayobjects.com/rmsportal/CoojVXLtoWrUSmI.png">
<span class="resource-card-content">
<span class="resource-card-title">Web 界面设计</span>
<span class="resource-card-description">作者: Bill Scott / Theresa Neil</span>
<span class="resource-card-description">出版社: 电子工业出版社</span>
</span>
</a>
</div>
#### Ant Design 十大设计原则
- [亲密性 Proximity](./proximity)
- [对齐 Alignment](./alignment)
- [对比 Contrast](./contrast)
- [重复 Repetition](./repetition)
- [直截了当 Make it Direct](./direct)
- [简化交互 Keep it Lightweight](./lightweight)
- [足不出户 Stay in the Page](./stay)
- [提供邀请 Provide Invitation](./invitation)
- [巧用过渡 Use Transition](./transition)
- [即时反应 React Immediately](./reaction)

37
docs/spec/proximity.md Normal file
View File

@ -0,0 +1,37 @@
# 亲密性
- category: 十大原则
- order: 1
- subtitle: Proximity
如果信息之间关联性越高,它们之间的距离就应该越接近,也越像一个视觉单元;反之,则它们的距离就应该越远,也越像多个视觉单元。亲密性的根本目的是实现组织性,让用户对页面结构和信息层次一目了然。
---
## 纵向间距关系
<img class="preview-img" align="right" alt="纵向间距示例" description="在 Ant Design 中这三种规格分别为8px小号间距、16px中号间距、24px大号间距。" src="https://os.alipayobjects.com/rmsportal/blBCqHsUJhKxxAU.png">
通过『小号间距』、『中号间距』、『大号间距』这三种规格来划分信息层次。
<br>
<img class="preview-img" align="right" alt="增加元素示例" description="通过增加『分割线』来拉开层次。" src="https://os.alipayobjects.com/rmsportal/EWpTfSlQzueWlbp.png">
在这三种规格不适用的情况下,可以通过加减『基础间距』的倍数,或者增加元素来拉开信息层次。
> 注:在 Ant Design 中,`y=8+8*n`。其中,`n>=0`y 是纵向间距8 是『基础间距』。
---
## 横向间距关系
<img class="preview-img" align="right" alt="组合排布示例" src="https://os.alipayobjects.com/rmsportal/LdomydjSKKlFhiv.png">
为了适用不同尺寸的屏幕,在横向采用栅格布局来排布组件,从而保证布局的灵活性。
<br>
<img class="preview-img" align="right" alt="复选框内示例" src="https://os.alipayobjects.com/rmsportal/DxzQXtIEnFcFxGY.png">
在一个组件内部,元素的横向间距也应该有所不同。

76
docs/spec/reaction.md Normal file
View File

@ -0,0 +1,76 @@
# 即时反应
- category: 十大原则
- order: 10
- subtitle: React Immediately
『提供邀请』的强大体现在`交互之前`给出反馈,解决易发现性问题;『巧用过渡』的有用体现在它能够在`交互期间`为用户提供视觉反馈;『即时反应』的重要性体现在`交互之后`立即给出反馈。
就像『牛顿第三定律』所描述作用力和反作用一样,用户进行了操作或者内部数据发生了变化,系统就应该立即有一个对应的反馈,同时输入量级越大、重要性越高,那么反馈量级越大、重要性越高。
虽然反馈太多(准确的说,错误的反馈太多)是一个问题,但是反馈太少甚至没有反馈的系统,则让人感觉迟钝和笨拙,用户体验更差。
> ** 牛顿第三定律 ** :当两个物体互相作用时,彼此施加于对方的力,其大小相等、方向相反。——摘自《维基百科》
---
## 查询模式
<img class="preview-img" align="right" alt="确定类目示例" description="用户所查询的关键词,只会在『话题』、『问题』、『文章』这 3 种类目中出现。" src="https://os.alipayobjects.com/rmsportal/fgQfkNakHrUiAun.png">
<img class="preview-img" align="right" alt="不确定类目示例" description="用户所查询的关键词,其所属的类目数量不确定,可能 4 个,可能 5 个,可能更多。" src="https://os.alipayobjects.com/rmsportal/hUfCsXwnOsVlskl.png">
自动完成:用户输入时,下拉列表会随着输入的关键词显示匹配项。
根据查询结果分类的多少,可以分为『确定类目』、『不确定类目』两种类型。
<br>
<img class="preview-img" align="right" alt="实时搜索示例" description="用户输入一个搜索值,系统随即显示查询结果。" src="https://os.alipayobjects.com/rmsportal/OyJCVmOigyXKWCf.png">
实时搜索:随着用户输入,实时显示搜索结果。『自动完成』、『实时建议』的近亲。
<br>
微调搜索:随着用户调整搜索条件,实时调整搜索结构。具体可见:[『模式/高级搜索』](../pattern/advanced-search)。
<br>
---
## 反馈模式
<img class="preview-img" align="right" alt="实时预览示例" description="根据用户的输入,提供关于密码强度和有效性的实时反馈。" src="https://os.alipayobjects.com/rmsportal/jecYhRgfbHleGDJ.png">
实时预览:在用户提交输入之前,让他先行了解系统将如何处理他的输入。
>注:解决错误最好的办法,就是不让错误发生。而『实时预览』就是有效避免错误的好设计。
<br>
渐进式展现:在必要的时候提供必要的提示,而不是一股脑儿显示所有提示,导致界面混乱,增加认知负担。案例详见[『足不出户/渐进式展现』](../spec/stay#流程处理)。
<br>
<img class="preview-img" align="right" alt="按钮加载示例" src="https://os.alipayobjects.com/rmsportal/FBAZGqfeUnDlUtw.png">
<img class="preview-img" align="right" alt="表格加载示例" src="https://os.alipayobjects.com/rmsportal/FPXsINbTgsuSStI.png">
<img class="preview-img" align="right" alt="富列表加载示例" src="https://os.alipayobjects.com/rmsportal/WJqeUHzthTXaHnW.png">
<img class="preview-img" align="right" alt="页面加载示例" src="https://os.alipayobjects.com/rmsportal/qPWjexSmFfCiLVJ.png">
进度指示:当一个操作需要一定时间完成时,就需要即时告知进度,保持与用户的沟通。
常见的进度指示:『按钮加载』、『表格加载』、『富列表加载』、『页面加载』。可根据操作的量级和重要性,展示不同类型的进度指示。
<br>
<img class="preview-img" align="right" alt="点击刷新示例" src="https://os.alipayobjects.com/rmsportal/DdmWqoqIFSCSAvq.png">
点击刷新:告知用户有新内容,并提供按钮等工具帮助用户查看新内容。
<br>
<img class="preview-img" align="right" alt="定时示例" description="新增的列表项『高亮』,持续几秒后恢复正常。" src="https://os.alipayobjects.com/rmsportal/guiuShsfpJzxZQx.png">
定时刷新:无需用户介入,定时展示新内容。

19
docs/spec/repetition.md Normal file
View File

@ -0,0 +1,19 @@
# 重复
- category: 十大原则
- order: 4
- subtitle: Repetition
相同的元素在整个界面中不断重复,不仅可以有效降低用户的学习成本,也可以帮助用户识别出这些元素之间的关联性。
---
## 重复元素
<img class="preview-img" align="right" alt="线框重复示例" src="https://os.alipayobjects.com/rmsportal/SREcKOUMmiWPQNO.png">
<img class="preview-img" align="right" alt="设计要素重复示例" src="https://os.alipayobjects.com/rmsportal/ZjFUWyPHGzyQJYD.png">
<img class="preview-img" align="right" alt="文案格式重复示例" src="https://os.alipayobjects.com/rmsportal/mveDxAdjucdJDll.png">
重复元素可以是一条粗线、一种线框,某种相同的颜色、设计要素、设计风格,某种格式、空间关系等。

99
docs/spec/stay.md Normal file
View File

@ -0,0 +1,99 @@
# 足不出户
- category: 十大原则
- order: 6
- subtitle: Stay on the Page
能在这个页面解决的问题就不要去其它页面解决因为任何页面刷新和跳转都会引起变化盲视Change Blindness导致用户心流Flow被打断。频繁的页面刷新和跳转就像在看戏时演员说完一行台词就安排一次谢幕一样。
> ** 变换盲视Change Blindness** :指视觉场景中的某些变化并未被观察者注意到的心理现象。产生这种现象的原因包括场景中的障碍物,眼球运动、地点的变化,或者是缺乏注意力等。——摘自《维基百科》
> ** 心流Flow** :也有别名以化境 (Zone) 表示,亦有人翻译为神驰状态,定义是一种将个人精神力完全投注在某种活动上的感觉;心流产生时同时会有高度的兴奋及充实感。——摘自《维基百科》
---
## 覆盖层
<img class="preview-img" align="right" alt="推荐示例" description="用户点击『删除』后,直接操作;出现 Message 告知用户操作成功,并提供用户『撤消』的按钮;用户进行下一个操作或者 1 分钟内不进行任何操作, Message 消失,用户无法再『撤消』。" src="https://os.alipayobjects.com/rmsportal/woHOTIZeXCYmtkv.png" good>
<img class="preview-img" align="right" alt="推荐示例" description="特例:在执行某些无法『撤消』的操作时,可以点击『删除』后,出现 Popconfirm 进行二次确认,在当前页面完成任务。" src="https://os.alipayobjects.com/rmsportal/hDlhNscVtHdvvgu.png" good>
<img class="preview-img" align="right" alt="不推荐示例" description="滥用 Modal 进行二次确认,就像『狼来了』一样,既打断用户心流(无法将上下文带到弹出框中),也无法避免失误的发生。" src="https://os.alipayobjects.com/rmsportal/JEcWKBYlMcYIowX.png" bad>
二次确认覆盖层:避免滥用 Modal 进行二次确认,应该勇敢的让用户去尝试,给用户机会『撤消』即可。
<br>
<img class="preview-img" align="right" alt="详情覆盖层示例" description="通过『点击』图标查看更多详情信息。" src="https://os.alipayobjects.com/rmsportal/WIhhhXExyQBsZwj.png">
详情覆盖层:一般在列表中,通过用户『悬停』/『点击』某个区块,在当前页加载该条列表项的更多详情信息。
> 注:使用『悬停』激活时,当鼠标移入时,需要设置 0.5 秒左右的延迟触发;当鼠标移出时,立刻关闭覆盖层
<br>
<img class="preview-img" align="right" alt="输入覆盖层示例" description="鼠标『点击』图标触发;鼠标『点击』悬浮层以外的其他区块后,直接保存输入结果并退出。" src="https://os.alipayobjects.com/rmsportal/YehbrRkldqWsezo.png">
输入覆盖层:在覆盖层上,让用户直接进行少量字段的输入。
<br>
---
## 嵌入层
<img class="preview-img" align="right" alt="列表嵌入层示例" src="https://os.alipayobjects.com/rmsportal/bHCqDMqXhZvKbve.png">
列表嵌入层:在列表中,显示某条列表项的详情信息,保持上下文不中断。
<br>
<span class="waiting">详情嵌入层 (敬请期待)</span>
<br>
<img class="preview-img" align="right" alt="标签页示例" src="https://os.alipayobjects.com/rmsportal/MsVyvEIJtlxZWBL.png">
标签页:将多个平级的信息进行整理和分类了,一次只显示一组信息。
<br>
---
## 虚拟页面
在交互过程中,『覆盖层』可以在当前页面上方显示附加内容和交互链接;『嵌入层』可以在页面内部实现同样效果;而『虚拟页面』不局限机械时代的『页面』,可以利用信息时代的特点构建一种新型『页面』。
无限加载和分页器,详见[『模式/列表/显示长列表』](../pattern/list#显示长列表)
走马灯,详见[『模式/列表/显示图片』](../pattern/list#显示图片)
<br>
<span class="waiting">伸缩式用户界面(敬请期待)</span>
<br>
---
## 流程处理
长期以来Web 实现流程的方式就是把每个步骤放在一个单独的页面上。虽然这种做法是分解问题最简单的方式,但并不是最佳解决方案。对于某些『流程处理』而言,让用户始终待在同一个页面上则更有必要。
<br>
<img class="preview-img" align="right" alt="渐进式展现示例" src="https://os.alipayobjects.com/rmsportal/xpynnwXnfCpGHvn.png">
渐进式展现:基于用户的操作/某种特定规则,渐进式展现不同的操作选项。
<br>
<img class="preview-img" align="right" alt="配置程序示例" src="https://os.alipayobjects.com/rmsportal/EBVLFAwHHjiXtIJ.png">
配置程序:通过提供一系列的配置项,帮助用户完成任务或者产品组装。
<br>
<img class="preview-img" align="right" alt="弹出框覆盖层示例" src="https://os.alipayobjects.com/rmsportal/xcYosQncDPuFxhS.png">
弹出框覆盖层:虽然弹出框的出现会打断用户的心流,但是有时候在弹出框中使用『步骤条』来管理复杂流程也是可行的。

74
docs/spec/transition.md Normal file
View File

@ -0,0 +1,74 @@
# 巧用过渡
- category: 十大原则
- order: 9
- subtitle: Use Transition
人脑灰质Gray Matter会对动态的事物eg移动、形变、色变等保持敏感。在界面中适当的加入一些过渡效果能让界面保持生动同时也能增强用户和界面的沟通。
- Adding: 新加入的信息元素应被告知如何使用,从页面转变的信息元素需被重新识别。
- Receding: 与当前页无关的信息元素应采用适当方式移除。
- Normal: 指那些从转场开始到结束都没有发生变化的信息元素。
---
## 在视图变化时保持上下文
<video class="transition-video-player" alt="滑入与滑出示例" src="https://os.alipayobjects.com/rmsportal/EejaUGsyExkXyXr.mp4" />
滑入与滑出:可以有效构建虚拟空间。
<br>
<video class="transition-video-player" alt="传送带示例" src="https://os.alipayobjects.com/rmsportal/GIutPgZMTyfFfrH.mp4" />
传送带:可极大地扩展虚拟空间。
<br>
<video class="transition-video-player" alt="折叠窗口示例" src="https://os.alipayobjects.com/rmsportal/ERKhqHlcHiCDSQu.mp4" />
折叠窗口:在视图切换时,有助于保持上下文,同时也能拓展虚拟空间。
<br>
<span class="waiting">视图定位 (敬请期待)</span>
<br>
---
## 解释刚刚发生了什么
<video class="transition-video-player" alt="对象增加示例" description="新增一条对象时,该行『高亮』告知用户这是新增项;几秒后『高亮』消失,以免过度干扰用户。" src="https://os.alipayobjects.com/rmsportal/FqkQMyFqNqielOw.mp4" />
对象增加:在列表/表格中,新增了一个对象。
<br>
<video class="transition-video-player" alt="对象删除示例" src="https://os.alipayobjects.com/rmsportal/pnNkNIMoowmGUQy.mp4" />
对象删除:在列表/表格中,删除了一个对象。
<br>
<video class="transition-video-player" alt="对象更改示例" description="状态一:用户更改了『详情』中的值;<br>状态二:用户点击『保存』后,详情所在的网格出现『黄底』,表明该对象发生了更改;<br>状态三:底色持续几秒后,恢复正常。" src="https://os.alipayobjects.com/rmsportal/XrUIWmsmOlEnZGc.mp4" />
对象更改:在列表/表格中,更改了一个对象。
<br>
<video class="transition-video-player" alt="对象呼出示例" src="https://os.alipayobjects.com/rmsportal/gSNilqbiXOufDXF.mp4" />
对象呼出:点击页面中元素,呼出一个新对象。
---
## 改善感知性能
当无法有效提升『实际性能』时,可以考虑适当转移用户的注意力,来缩短某项操作的感知时间,改善感知性能。
<br>
<span class="waiting">图片(敬请期待)</span>

View File

@ -1,13 +1,13 @@
# Typography
- category: 基础
- category: 设计基础
- order: 1
- chinese: 排版
---
良好的排版规范能大大提升用户的视觉体验。
---
## 行高和段落
考虑到阅读的舒适度和节奏感,句子和段落间需要合适的间距。行距決定了段落中各行文字的垂直距离,通过字体本身行高来控制,我们行高默认为字号的 1.5 倍。段落间距決定了段落上下的间距,一般为字号的一倍宽。

View File

@ -1,6 +1,6 @@
{
"name": "antd",
"version": "0.12.8",
"version": "0.12.11",
"title": "Ant Design",
"description": "一个 UI 设计语言",
"homepage": "http://ant.design/",
@ -58,11 +58,11 @@
"rc-steps": "~1.4.1",
"rc-switch": "~1.3.2",
"rc-table": "~3.11.1",
"rc-tabs": "~5.7.0",
"rc-tabs": "~5.8.0",
"rc-time-picker": "~1.1.0",
"rc-tooltip": "~3.3.1",
"rc-tree": "~1.1.0",
"rc-tree-select": "~1.2.2",
"rc-tree-select": "~1.4.1",
"rc-trigger": "~1.2.0",
"rc-upload": "~1.8.0",
"rc-util": "~3.1.2",
@ -71,8 +71,9 @@
"warning": "~2.1.0"
},
"devDependencies": {
"antd-md-loader": "0.1.0-beta.9",
"antd-md-loader": "0.1.0-beta.11",
"atool-build": "^0.5.0",
"autoprefixer": "^6.3.3",
"babel-cli": "^6.2.0",
"babel-core": "^6.2.1",
"babel-jest": "^6.0.1",
@ -97,8 +98,8 @@
"eslint-plugin-react": "^4.0.0",
"eslint-tinker": "^0.3.1",
"extract-text-webpack-plugin": "^1.0.1",
"gh-pages": "^0.9.0",
"gsap": "^1.18.2",
"gh-pages": "^0.11.0",
"history": "^1.17.0",
"instantclick": "^3.1.0",
"jest-cli": "~0.8.0",
@ -107,11 +108,11 @@
"jsonp": "^0.2.0",
"less": "~2.6.0",
"less-loader": "^2.2.0",
"lesshint-antd": "^1.2.1",
"lesshint": "^1.2.1",
"lodash": "^4.1.0",
"mark-twain": "^0.2.0-beta.4",
"mkdirp": "~0.5.1",
"nico-jsx": "~0.8.2",
"nico-jsx": "~0.9.0",
"postcss-loader": "^0.8.0",
"pre-commit": "1.x",
"querystring": "^0.2.0",
@ -125,6 +126,7 @@
"react-github-button": "^0.1.1",
"react-router": "^2.0.0",
"react-stateless-wrapper": "~1.0.2",
"react-sublime-video": "0.1.0-beta",
"recast": "^0.11.2",
"reqwest": "~2.0.5",
"semver": "^5.1.0",

505
scripts/demo.js Normal file
View File

@ -0,0 +1,505 @@
require('../style/index.less');
require('../site/static/style.less');
require('../site/static/tomorrow.less');
window['css-animation'] = require('css-animation');
window['react-router'] = require('react-router');
window['rc-form'] = require('rc-form');
window.CopyToClipboard = require('react-copy-to-clipboard');
var antd = require('../index');
var React = require('react');
var ReactDOM = require('react-dom');
var semver = require('semver');
window.antd = antd;
window.React = React;
window.ReactDOM = ReactDOM;
window['object-assign'] = require('object-assign');
window['classnames'] = require('classnames');
window['reqwest'] = require('reqwest');
window['jsonp'] = require('jsonp');
window['querystring'] = require('querystring');
window['Values'] = require('values.js');
window['InstantClick'] = require('instantclick');
require('./home')();
function camelize(str) {
return str.replace(/(?:^|[-_])(\w)/g, function (_, c) {
return c ? c.toUpperCase() : '';
});
}
window.require = function (path) {
var result = window;
var namespaces = path.split('/');
namespaces.forEach(function (key, i) {
if (i === 2) {
key = camelize(key);
}
if (key !== 'lib') {
if (result[key]) {
result = result[key];
} else {
throw 'There should not have modules here: ' + path;
}
}
});
return result;
};
antd.DatePicker.locale = {
en_US: require('../components/date-picker/locale/en_US'),
zh_CN: require('../components/date-picker/locale/zh_CN'),
};
antd.Calendar.locale = {
en_US: require('../components/calendar/locale/en_US'),
zh_CN: require('../components/calendar/locale/zh_CN'),
};
antd.Pagination.locale = {
en_US: require('../components/pagination/locale/en_US'),
zh_CN: require('../components/pagination/locale/zh_CN'),
};
InstantClickChangeFns.push(function () {
// auto complete for components
var Select = antd.Select;
var Option = Select.Option;
// 获取搜索数据
var searchData = window.ANT_COMPONENTS.sort(function (a, b) {
return a.title.localeCompare(b.title);
});
var AutoComplete = React.createClass({
getOptions() {
return searchData.map(function (s) {
return <Option sData={s} key={s.title} text={'跳转到 ' + s.title}>
<strong>{s.title}</strong>
&nbsp;
<span className="ant-component-decs">{s.desc}</span>
</Option>;
});
},
handleSelect(value) {
location.href = rootUrl + '/components/' + value.replace(/([a-z])([A-Z])/g, function (m, m1, m2) {
return m1 + '-' + m2;
}).toLowerCase() + '/';
},
filterOption(input, option) {
return option.props.sData.title.toLowerCase().indexOf(input.toLowerCase()) !== -1 || option.props.sData.desc.indexOf(input) !== -1;
},
render() {
return <Select combobox style={{width: '100%'}}
onSelect={this.handleSelect}
optionLabelProp="text"
dropdownClassName="autoComplete"
searchPlaceholder="搜索组件..."
filterOption={this.filterOption}>{this.getOptions()}</Select>;
}
});
ReactDOM.render(<AutoComplete/>, document.getElementById('autoComplete'));
});
InstantClickChangeFns.push(function () {
var Select = antd.Select;
var Option = Select.Option;
var versionsHistory = {
'0.9.x': '09x.ant.design',
'0.10.x': '010x.ant.design',
'0.11.x': '011x.ant.design',
};
versionsHistory[antdVersion.latest] =
versionsHistory[antdVersion.latest] || 'ant.design';
var versions = Object.keys(versionsHistory).sort(function (a, b) {
return semver.lt(a.replace('.x', '.0'), b.replace('.x', '.0'));
});
var options = versions.map(function (version) {
var link = versionsHistory[version];
return <Option key={version} value={version}>{version}</Option>;
});
function onChange(value) {
if (versionsHistory[value]) {
location.href = location.href.replace(location.host, versionsHistory[value]);
}
}
ReactDOM.render(
<Select defaultValue={antdVersion.latest} size="small"
dropdownMatchSelectWidth={false}
onChange={onChange}>{options}</Select>
, document.getElementById('versions-select'));
});
window.BrowserDemo = React.createClass({
render() {
return (
<article className="window-frame focus">
<header className="top-bar">
<div className="controls">
<div className="control close"></div>
<div className="control minify"></div>
<div className="control expand"></div>
</div>
<input className="address-bar" defaultValue="http://www.example.com"/>
</header>
<section className="window-content">
{this.props.children}
</section>
</article>
);
}
});
const { Modal, Carousel } = antd;
const PriviewImg = React.createClass({
getInitialState() {
return {
visible: false,
current: 0,
};
},
showImageModal() {
this.setState({
visible: true
});
},
handleCancel() {
this.setState({
visible: false
});
},
handleImgChange(current) {
this.setState({current});
},
render() {
const goodCls = this.props.good ? 'good' : '';
const badCls = this.props.bad ? 'bad' : '';
const imgsPack = this.props.imgsPack || [{
src: this.props.src,
alt: this.props.alt,
}];
const imgStyle = {};
if (this.props.noPadding) {
imgStyle.padding = '0';
imgStyle.background = 'none';
}
const current = this.state.current;
const arrows = imgsPack.length > 1;
const createMarkup = () => {
return {__html: this.props.description}
};
let node = <img src={this.props.src} onClick={this.showImageModal} style={imgStyle} alt="Sample Picture" />;
if (this.props.type === 'video') {
node = (
<video preload loop style={imgStyle}>
<source src={this.props.src} type="video/mp4" />
</video>
);
}
return (
<div className="preview-image-box" style={{ width: this.props.width }}>
<div className={`preview-image-wrapper ${this.props.type} ${goodCls} ${badCls}`}>
{node}
</div>
<div className="preview-image-title">{this.props.alt}</div>
<div className="preview-image-description" dangerouslySetInnerHTML={createMarkup()}/>
<Modal className="image-modal" width="960" visible={this.state.visible} onCancel={this.handleCancel} footer=""
title="">
<Carousel afterChange={this.handleImgChange} adaptiveHeight arrows={arrows}>
{
imgsPack.map((img, i) =>
<div key={i}>
<div className="image-modal-container">
<img src={img.src}/>
</div>
</div>
)
}
</Carousel>
<div className="preview-image-title">{imgsPack[current].alt}</div>
</Modal>
</div>
);
}
});
InstantClickChangeFns.push(function () {
const previewImageBoxes = $('.preview-img').parent();
previewImageBoxes.each(function (i, box) {
box = $(box);
let priviewImgs = [];
const priviewImgNodes = box.find('.preview-img');
// 判断是否要做成图片集合
// 指定了封面图片就是
let coverImg;
priviewImgNodes.each(function (i, img) {
if (img.hasAttribute('as-cover')) {
coverImg = img;
return false;
}
});
if (coverImg) {
const imgs = [];
priviewImgNodes.each((i, img) => imgs.push(img));
priviewImgs = <PriviewImg src={coverImg.src} alt={coverImg.alt} imgsPack={imgs}/>;
} else {
priviewImgNodes.each(function (i, img) {
priviewImgs.push(
<PriviewImg key={i} src={img.src} width={100.0/priviewImgNodes.length + '%'} alt={img.alt}
noPadding={img.hasAttribute('noPadding')}
description={img.getAttribute('description')}
type={img.getAttribute('type')}
good={!!img.hasAttribute('good')} bad={!!img.hasAttribute('bad')}/>
);
});
}
// 计算宽度
let width = '';
if (priviewImgs.length === 1) {
width = priviewImgNodes[0].getAttribute('width') || '';
} else if (coverImg) {
width = coverImg.getAttribute('width');
}
if (width && width.indexOf('%') < 0 && width !== 'auto') {
width += 'px';
}
let mountNode = $('<div class="preview-image-boxes cleafix ' + (coverImg ? 'pack' : '') + '" style="width: ' + width + '"></div>')[0];
box.replaceWith(mountNode);
ReactDOM.render(<span>{priviewImgs}</span>, mountNode);
});
});
InstantClickChangeFns.push(function() {
// fix hash id link
if (window.location.href.indexOf('#') > 0) {
setTimeout(function() {
window.location.href = window.location.href;
}, 30);
}
$('.component-demos .icon-all').off('click');
$('.component-demos .icon-all').on('click', function() {
if ($(this).hasClass('expand')) {
$(this).removeClass('expand');
$('.code-box .highlight').animate({
height: 'hide',
opacity: 0
}, 150);
} else {
$(this).addClass('expand');
$('.code-box .highlight').animate({
height: 'show',
opacity: 1
}, 150);
}
});
$('.code-box').each(function(i, item) {
item = $(item);
item.find('.highlight').appendTo(item);
});
$('.code-boxes').off('click');
$('.code-boxes').on('click', '.collapse', function() {
var highlightBox = $(this).parent().parent().find('.highlight');
var codeVisible = highlightBox.is(':visible');
highlightBox.animate({
height: codeVisible ? 'hide' : 'show',
opacity: codeVisible ? 0 : 1
}, 150);
if (codeVisible) {
$(this).parent().parent().removeClass('expand');
} else {
$(this).parent().parent().addClass('expand');
}
});
function hashChange() {
$('.demos-anchor a').removeClass('current');
$('.demos-anchor a[href="' + decodeURI(location.hash) + '"]').addClass('current');
}
hashChange();
// 高亮侧边演示菜单
$(window).off('hashchange');
$(window).on('hashchange', hashChange);
// 移动 API 文档到演示下方
$('.markdown #api').nextAll().andSelf().appendTo('.api-container');
// 滚动时固定锚点、高亮当前项
if ($('.demos-anchor')[0]) {
var doc = $(document);
var tocTop = $('.toc').offset().top;
function onScroll() {
var top = doc.scrollTop();
if (top >= tocTop) {
$('.toc').addClass('sticky');
} else {
$('.toc').removeClass('sticky');
}
}
onScroll();
$(window).off('scroll');
$(window).on('scroll', onScroll);
}
// 添加上一页下一页
if ($('.aside-container li > a').length > 0) {
var links = $('.aside-container li > a');
var currentLinkIndex = -1;
links.each(function(i, item) {
if ($(item).parent().hasClass('current')) {
currentLinkIndex = i;
}
});
var prevNextNavNode = $('<div class="prev-next-nav"></div>');
var prevLink = links[currentLinkIndex - 1];
var nextLink = links[currentLinkIndex + 1];
if (prevLink) {
var prevLinkNavNode = $('<a class="prev-page" href="' + prevLink.href + '">' + prevLink.innerHTML + '</a>');
if (prevLink.className.indexOf('nav-link-disabled') >= 0) {
prevLinkNavNode.attr('disabled', true);
}
prevNextNavNode.append(prevLinkNavNode);
} else {
prevNextNavNode.append('<span class="prev-page"></span>');
}
if (nextLink) {
var nextLinkNavNode = $('<a class="next-page" href="' + nextLink.href + '">' + nextLink.innerHTML + '</a>');
if (nextLink.className.indexOf('nav-link-disabled') >= 0) {
nextLinkNavNode.attr('disabled', true);
}
prevNextNavNode.append(nextLinkNavNode);
} else {
prevNextNavNode.append('<span class="next-page"></span>');
}
prevNextNavNode.appendTo('.main-container');
}
var navMenu = $('.nav');
$('.nav-phone-icon').click(function() {
navMenu.removeClass('nav-hide').addClass('nav-show');
});
$('body').on('click touchstart', function (e) {
if (e.target !== $('.nav-phone-icon')[0] &&
!navMenu[0].contains(e.target) &&
navMenu.hasClass('nav-show')) {
navMenu.removeClass('nav-show').addClass('nav-hide');
}
});
$.easing['jswing'] = $.easing['swing'];
$.extend($.easing,{
easeInCirc: function (x, t, b, c, d) {
return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
},
easeOutCirc: function (x, t, b, c, d) {
return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
},
easeInOutCirc: function (x, t, b, c, d) {
if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
}
});
var navFunc = {
navStrArr: [],
init: function() {
if (this.navBar) {
return;
}
this.navBox = $(".nav");
this.navBar = this.navBox.find(".bar");
this.navList = this.navBox.find("ul li");
this.navNum = $(".current").index();
this.navBarAnim();
this.highlightCurrentNav();
$(window).bind("resize", this.highlightCurrentNav);
this.navBar.show();
},
highlightCurrentNav: function(target) {
target = target || this.navList.eq(this.navNum);
this.navBar && this.navBar.css({
left: target.position().left,
width: target.outerWidth()
});
},
navBarAnim: function() {
var self = this, delay;
self.navList.bind("mouseenter", function(e) {
clearTimeout(delay);
self.highlightCurrentNav($(e.currentTarget));
});
self.navList.bind("mouseleave", function(e) {
delay = setTimeout(function() {
self.highlightCurrentNav();
}, 500);
});
}
};
navFunc.init();
var listFunc = {
num: 0,
init: function() {
this.listBox = $(".aside-container>ul");
if (!this.listBox.length) {
return;
}
this.getUrlNum();
this.addTitleEvent();
},
getUrlNum: function() {
var self = this,
url = location.href,
str = "";
for (var i = 0; i < self.listBox.find("a").length; i++) {
var m = self.listBox.find("a").eq(i);
if (m.attr("href") == "./" || url.indexOf(m.attr("href")) >= 0) {
self.num = m.parent().parent().parent().index();
}
}
},
addTitleEvent: function() {
var self = this;
var title = self.listBox.find("h4");
title.bind("click", function(e) {
var parent = $(this).parent(),
list=parent.find("ul");
if (parent.attr("open")) {
parent.removeAttr("open");
if (parent.index() == self.num) {
$(this).addClass("current");
}
list.animate({marginTop:-list.height()},400,"easeInOutCirc",function (){
list.css({"display":"none"})
})
} else {
parent.attr("open", true);
if (parent.index() == self.num) {
$(this).removeClass("current");
}
list.css({"display":"block","margin-top":-list.height()});
list.animate({marginTop:0},400,"easeInOutCirc")
}
});
}
};
listFunc.init();
});
antd.version = require('../package.json').version;
module.exports = antd;

View File

@ -99,7 +99,7 @@ module.exports = function() {
<QueueAnim className="text-wrapper" delay={300} key="text" duration={550} leaveReverse
hideProps={{child: null}}>
<h2 key="h2">最佳实践</h2>
<p key="p" style={{maxWidth: 310}}>近一年的中台设计实践积累了大量的优秀案例</p>
<p key="p" style={{maxWidth: 310}}>近一年的中台设计实践积累了大量的优秀案例</p>
<div key="button"><Button type="primary" size="large"
onClick={()=>{window.location.href='/docs/practice/cases'}}>了解更多<Icon
type="right"/></Button></div>
@ -119,7 +119,7 @@ module.exports = function() {
leaveReverse
hideProps={{child: null}}>
<h2 key="h2">设计模式</h2>
<p key="p" style={{maxWidth: 260}}>总结中台设计中反复出现的问题并提供相应的解决方案</p>
<p key="p" style={{maxWidth: 260}}>总结中台设计中反复出现的问题并提供相应的解决方案</p>
<div key="button"><Button type="primary" size="large"
onClick={()=>{window.location.href='/docs/pattern/navigation'}}>了解更多<Icon
type="right"/></Button>
@ -162,7 +162,7 @@ module.exports = function() {
<QueueAnim className="text-wrapper-bottom" delay={300} key="text" duration={550} leaveReverse type="bottom"
hideProps={{child: null}}>
<h2 key="h2">微小·确定·幸福</h2>
<p key="p">这是一致力于提升用户设计者使用体验的中台设计语言</p>
<p key="p">这是一致力于提升用户设计者使用体验的中台设计语言</p>
</QueueAnim>
<TweenOne key="image" className="image4 bottom-wrapper" vars={{y: 0, opacity: 1, duration: 550, delay: 550}}
style={{transform: 'translateY(50px)', opacity: 0}} hideProps={{type: 'reverse'}}/>

View File

@ -1,5 +1,22 @@
html {
text-rendering: optimizeLegibility;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
html,
body {
height: 100%;
}
body {
font-family: "Helvetica Neue",Helvetica,"PingFang SC","Hiragino Sans GB","Microsoft YaHei","微软雅黑",SimSun,sans-serif;
line-height: 1.5;
color: #666;
font-size: 14px;
background: #ECECEC;
transition: background 1s cubic-bezier(0.075, 0.82, 0.165, 1);
overflow-x: hidden;
}
.main-wrapper {
@ -25,6 +42,10 @@ body {
.sidebar {
padding-bottom: 50px;
&.ant-menu-inline > .ant-menu-item {
font-size: 14px;
}
a[disabled] {
color: #ccc;
}

View File

@ -13,15 +13,20 @@
}
}
.demo-list-left,
.demo-list-right {
width: 49%;
.code-boxes-col-1-1 {
width: 80%;
}
.demo-list-left {
margin-right: 1%;
.code-boxes-col-2-1 {
width: 48%;
display: inline-block;
vertical-align: top;
padding-right: 8px;
}
.demo-list-right {
margin-left: 1%;
.code-boxes-col-2-1:last-child {
padding-right: 0;
padding-left: 8px;
}
.code-box {
@ -127,6 +132,7 @@
margin: 0.5em 0;
padding-right: 25px;
width: 100%;
word-break: break-word;
}
.code-box .collapse {
@ -145,6 +151,7 @@
transition: all 0.3s ease;
color: #999;
background: #fff;
user-select: none;
}
.code-box.expand .collapse {

View File

@ -6,6 +6,7 @@ footer {
position: relative;
z-index: 1;
color: #666;
box-shadow: 0 1000px 0 1000px #fff;
}
footer ul {
@ -32,4 +33,8 @@ footer ul li > div {
footer ul li > a {
margin: 5px 2px 0 0;
}
.versions-selector {
width: 75px;
}

View File

@ -4,8 +4,8 @@
line-height: 1.8;
}
.markdown > * {
// width: 100%!important;
.highlight {
line-height: 1.5;
}
.markdown img {
@ -18,6 +18,12 @@
font-weight: 500;
line-height: 40px;
margin-bottom: 24px;
.subtitle {
font-size: 80%;
font-weight: normal;
font-family: "Helvetica Neue",Helvetica;
}
}
.markdown h2,
@ -137,6 +143,7 @@
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
font-style: italic;
}
.markdown blockquote p {
@ -149,6 +156,10 @@
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,

View File

@ -25,6 +25,11 @@
}
.video-player{
position: relative;
max-width: 800px;
position: relative;
max-width: 800px;
&-right {
width: 616px;
float: right;
}
}

View File

@ -1,15 +1,20 @@
.preview-image-boxes {
float: right;
margin: 0 0 110px 60px;
margin: 0 0 70px 28px;
width: 616px;
clear: both;
&-with-popup {
&-with-carousel {
width: 420px;
.preview-image-box img {
padding: 0;
}
}
}
.preview-image-boxes + .preview-image-boxes {
margin-top: -75px;
margin-top: -35px;
}
.preview-image-box {
@ -27,6 +32,22 @@
position: relative;
}
.preview-image-wrapper.video {
padding: 0;
background: 0;
display: block;
}
.preview-image-wrapper video {
width: 100%;
display: block;
+ svg {
position: absolute;
top: 0;
left: 0;
}
}
.preview-image-wrapper.good:after {
content: '';
width: 100%;
@ -88,8 +109,31 @@
.image-modal {
text-align: center;
&-container {
position: relative;
text-align: center;
}
}
.image-modal-single.slick-slider {
padding-bottom: 0;
}
.ant-carousel .slick-slider img {
display: inline;
max-width: 100%;
}
.no-padding {
padding: 0!important;
}
.transition-video-player {
float: right;
padding: 0;
width: 600px;
.preview-image-wrapper {
padding: 0;
}
}

View File

@ -1,6 +1,6 @@
.toc {
font-size: 14px;
margin-bottom: 20px;
margin: 36px 0 24px;
background: #fbfbfb;
border-left: 2px solid #eee;
}
@ -40,16 +40,15 @@
}
.toc-affix {
z-index: 9;
position: relative;
float: right;
}
.demos-anchor {
color: #aaa;
position: absolute;
margin-right: 24px;
top: 24px;
right: 0;
z-index: 100;
top: 0;
right: -18px;
background: #fff;
font-size: 12px;

View File

@ -1,4 +1,5 @@
import React from 'react';
import classNames from 'classnames';
import { Modal, Carousel } from '../../../';
function isGood(className) {
@ -8,6 +9,31 @@ function isBad(className) {
return /\bbad\b/i.test(className);
}
function PreviewImageBox({ cover, coverMeta, imgs, style, previewVisible,
comparable, onClick, onCancel }) {
const onlyOneImg = comparable || imgs.length === 1;
return (
<div className="preview-image-box"
style={style}
onClick={onClick}>
<div className={`preview-image-wrapper ${coverMeta.isGood && 'good'} ${coverMeta.isBad && 'bad'}`}>
<img className={coverMeta.className} src={coverMeta.src} alt="Sample Picture" />
</div>
<div className="preview-image-title">{coverMeta.alt}</div>
<div className="preview-image-description"
dangerouslySetInnerHTML={{ __html: coverMeta.description }} />
<Modal className="image-modal" width="960" visible={previewVisible} title={null} footer={null}
onCancel={onCancel}>
<Carousel className={`${onlyOneImg ? 'image-modal-single' : ''}`} adaptiveHeight>
{ comparable ? cover : imgs }
</Carousel>
<div className="preview-image-title">{coverMeta.alt}</div>
</Modal>
</div>
);
}
export default class ImagePreview extends React.Component {
constructor(props) {
super(props);
@ -30,7 +56,7 @@ export default class ImagePreview extends React.Component {
}
render() {
const { className, imgs } = this.props;
const { imgs } = this.props;
const imgsMeta = imgs.map((img) => {
const span = document.createElement('span');
span.innerHTML = img;
@ -48,60 +74,48 @@ export default class ImagePreview extends React.Component {
};
});
const cover = imgsMeta[0];
const imagesList = imgsMeta.map((meta, index) => {
return <img {...meta} key={index} />;
return (
<div key={index}>
<div className="image-modal-container">
<img {...meta} />
</div>
</div>
);
});
const comparable = imgs.length === 2 &&
(imgsMeta[0].isGood || imgsMeta[0].isBad) &&
(imgsMeta[1].isGood || imgsMeta[1].isBad);
const style = comparable ? { width: '50%' } : null;
return (
<div className={className}>
<div className="preview-image-box"
style={style}
onClick={this.handleClick.bind(this, 'left')}>
<div className={`preview-image-wrapper ${cover.isGood && 'good'} ${cover.isBad && 'bad'}`}>
<img className={cover.className} src={cover.src} alt="Sample Picture" />
</div>
<div className="preview-image-title">{cover.alt}</div>
<div className="preview-image-description">
{cover.description}
</div>
<Modal className="image-modal" visible={this.state.leftVisible} title={null} footer={null}
onCancel={this.handleCancel.bind(this)}>
<Carousel>
{ comparable ? imagesList[0] : imagesList }
</Carousel>
{
comparable || imagesList.length === 1 ?
<div className="preview-image-title">{cover.alt}</div> :
null
}
</Modal>
</div>
const hasCarousel = imgs.length > 1 && !comparable;
const previewClassName = classNames({
'preview-image-boxes': true,
clearfix: true,
'preview-image-boxes-with-carousel': hasCarousel,
});
return (
<div className={previewClassName}>
<PreviewImageBox style={style}
comparable={comparable}
previewVisible={this.state.leftVisible}
cover={imagesList[0]}
coverMeta={imgsMeta[0]}
imgs={imagesList}
onClick={this.handleClick.bind(this, 'left')}
onCancel={this.handleCancel.bind(this)}
/>
{
comparable ?
<div className="preview-image-box"
style={style}
onClick={this.handleClick.bind(this, 'right')}>
<div className={`preview-image-wrapper ${imgsMeta[1].isGood && 'good'} ${imgsMeta[1].isBad && 'bad'}`}>
<img className={imgsMeta[1].className} src={imgsMeta[1].src} alt="Sample Picture" />
</div>
<div className="preview-image-title">{imgsMeta[1].alt}</div>
<div className="preview-image-description">
{imgsMeta[1].description}
</div>
<Modal className="image-modal" visible={this.state.rightVisible} title={null} footer={null}
onCancel={this.handleCancel.bind(this)}>
<Carousel>
{ comparable ? imagesList[1] : imagesList }
</Carousel>
<div className="preview-image-title">{imagesList[1].alt}</div>
</Modal>
</div> : null
<PreviewImageBox style={style}
comparable
previewVisible={this.state.rightVisible}
cover={imagesList[1]}
coverMeta={imgsMeta[1]}
imgs={imagesList}
onClick={this.handleClick.bind(this, 'right')}
onCancel={this.handleCancel.bind(this)}
/> : null
}
</div>
);

View File

@ -0,0 +1,24 @@
import React from 'react';
import SublimeVideo from 'react-sublime-video';
export default class VideoPlayer extends React.Component {
render() {
const video = this.props.video;
const span = document.createElement('span');
span.innerHTML = video;
const attributes = span.children[0].attributes;
const { alt, description, src } = attributes;
const videoClassName = attributes.class.nodeValue;
return (
<div className={`preview-image-box ${videoClassName}`}>
<div className={'preview-image-wrapper'}>
<SublimeVideo src={src && src.nodeValue} type="video/mp4" />
</div>
<div className="preview-image-title">{alt && alt.nodeValue}</div>
<div className="preview-image-description"
dangerouslySetInnerHTML={{ __html: description && description.nodeValue }} />
</div>
);
}
}

View File

@ -1,7 +1,7 @@
import React from 'react';
import { Link } from 'react-router';
import classNames from 'classnames';
import ImagePreview from './ImagePreview';
import VideoPlayer from './VideoPlayer';
import * as utils from '../utils';
export default class Article extends React.Component {
@ -9,6 +9,7 @@ export default class Article extends React.Component {
super(props);
this.imgToPreview = this.imgToPreview.bind(this);
this.enhanceVideo = this.enhanceVideo.bind(this);
}
isPreviewImg(string) {
@ -21,13 +22,19 @@ export default class Article extends React.Component {
}
const imgs = node.children.split(/\r|\n/);
const hasPopup = imgs.length > 1;
const previewClassName = classNames({
'preview-image-boxes': true,
clearfix: true,
'preview-image-boxes-with-popup': hasPopup,
});
return <ImagePreview className={previewClassName} imgs={imgs} />;
return <ImagePreview imgs={imgs} />;
}
isVideo(string) {
return /^<video\s/i.test(string);
}
enhanceVideo(node) {
if (!this.isVideo(node.children)) {
return node;
}
return <VideoPlayer video={node.children} />;
}
render() {
@ -37,18 +44,29 @@ export default class Article extends React.Component {
}).map((node) => {
return (
<li key={node.children}>
<Link to={{ pathname: location.pathname, query: { scrollTo: node.children } }}>
{ node.children }
</Link>
<Link to={{ pathname: location.pathname, query: { scrollTo: node.children } }}
dangerouslySetInnerHTML={{ __html: node.children }} />
</li>
);
});
content.description = content.description.map(this.imgToPreview);
content.description = content.description
.map(this.imgToPreview)
.map(this.enhanceVideo);
return (
<article className="markdown">
<h1>{ content.meta.chinese || content.meta.english }</h1>
<h1>
{ content.meta.chinese || content.meta.english }
{
!content.meta.subtitle ? null :
<span className="subtitle">{ content.meta.subtitle }</span>
}
</h1>
{
!content.intro ? null :
content.intro.map(utils.objectToComponent.bind(null, location.pathname))
}
{
jumper.length > 0 ?
<section className="toc"><ul>{ jumper }</ul></section> :

View File

@ -87,10 +87,18 @@ export default class ComponentDoc extends React.Component {
</h2>
</section>
<Row>
<Col span={ isSingleCol ? '24' : '12' } className={ isSingleCol ? '' : 'demo-list-left'}>
<Col span={ isSingleCol ? '24' : '12' }
className={ isSingleCol ?
'code-boxes-col-1-1' :
'code-boxes-col-2-1'
}
>
{ leftChildren }
</Col>
{ isSingleCol ? null : <Col className="demo-list-right" span="12">{ rightChildren }</Col> }
{
isSingleCol ? null :
<Col className="code-boxes-col-2-1" span="12">{ rightChildren }</Col>
}
</Row>
<section className="markdown">
{ (doc.api || []).map(utils.objectToComponent.bind(null, location.pathname)) }

View File

@ -1,8 +1,28 @@
import React from 'react';
import { Select } from '../../../';
import { version as antdVersion } from '../../../package.json';
import { docVersions } from '../../website.config';
const Option = Select.Option;
export default class Footer extends React.Component {
constructor(props) {
super(props);
this.handleVersionChange = this.handleVersionChange.bind(this);
}
handleVersionChange(url) {
window.location.href = url;
}
render() {
const options = Object.keys(docVersions).map((version, index) => {
return (
<Option value={docVersions[version]} key={index}>
{ version }
</Option>
);
});
return (
<footer id="footer">
<ul>
@ -38,9 +58,9 @@ export default class Footer extends React.Component {
<div>©2015 蚂蚁金服体验技术部出品</div>
<div>
文档版本
<Select defaultValue="0.10.4" size="small">
<Option value="0.10.4">0.10.4</Option>
<Option value="0.9.2">0.9.2</Option>
<Select className="versions-selector" size="small"
placeholder={antdVersion} onChange={this.handleVersionChange}>
{ options }
</Select>
</div>
</li>

View File

@ -846,9 +846,7 @@ nm.start = function (self) {
module.exports = newMotion;
var motionVideo = {
video: ['https://t.alipayobjects.com/images/rmsweb/T1yHhhXfxkXXXXXXXX.webm', 'https://t.alipayobjects.com/images/rmsweb/T12I8gXexdXXXXXXXX.webm', 'https://t.alipayobjects.com/images/rmsweb/T1br0gXghtXXXXXXXX.webm', 'https://t.alipayobjects.com/images/rmsweb/T14q0hXbBdXXXXXXXX.webm'],
videoMp4: ['https://t.alipayobjects.com/images/rmsweb/T15IXhXlXbXXXXXXXX.mp4', 'https://t.alipayobjects.com/images/rmsweb/T1e0hgXcpdXXXXXXXX.mp4', 'https://t.alipayobjects.com/images/rmsweb/T1lcRgXb4gXXXXXXXX.mp4', 'https://t.alipayobjects.com/images/T1qWNhXkpeXXXXXXXX.mp4'],
init: function () {
init: function (videoList, videoMp4List) {
var self = this;
$('.video-player').each((i, videoBox) => {
@ -860,9 +858,9 @@ var motionVideo = {
$videoBox.append(svg.node);
var video = $videoBox.find('video');
if (video[0].canPlayType('video/webm; codecs="vp8.0, vorbis"')) {
$('<source src="' + self.video[i] + '" type="video/webm">').appendTo(video);
$('<source src="' + videoList[i] + '" type="video/webm">').appendTo(video);
} else {
$('<source src="' + self.videoMp4[i] + '" type="video/mp4">').appendTo(video);
$('<source src="' + videoMp4List[i] + '" type="video/mp4">').appendTo(video);
}
video.css({
'width': '100%'

View File

@ -1,5 +0,0 @@
import Motion from './motion';
module.exports = function () {
Motion.motionVideo.init();
};

View File

@ -44,7 +44,7 @@ export function objectToComponent(pathname, object, index) {
key: index,
id: children,
}, [
object.children,
<span dangerouslySetInnerHTML={{ __html: object.children }} />,
<Link to={{ pathname, query: { scrollTo: object.children } }} className="anchor" key="anchor">#</Link>,
]);
}

View File

@ -341,6 +341,7 @@ footer {
position: relative;
z-index: 1;
color: #666;
box-shadow: 0 1000px 0 1000px #fff;
}
footer ul {
@ -474,6 +475,7 @@ footer ul li > a {
overflow: hidden;
padding: 24px 0 0;
margin-bottom: 24px;
min-height: 400px;
position: relative;
}
@ -482,7 +484,8 @@ footer ul li > a {
margin-left: 219px;
padding: 0 40px 120px;
background: #fff;
min-height: 500px;
min-height: 400px;
min-height: 80vh;
overflow: hidden;
}
@ -625,6 +628,7 @@ footer ul li > a {
border-left: 4px solid #e9e9e9;
padding-left: 0.8em;
margin: 1em 0;
font-style: italic;
}
.markdown blockquote p {
@ -637,6 +641,10 @@ footer ul li > a {
margin-left: 8px;
}
.markdown .waiting {
color: #ccc;
}
.markdown h1:hover .anchor,
.markdown h2:hover .anchor,
.markdown h3:hover .anchor,
@ -698,9 +706,15 @@ footer ul li > a {
margin-left: 1em;
}
.subtitle {
font-size: 80%;
font-weight: normal;
font-family: "Helvetica Neue", Helvetica;
}
.toc {
font-size: 14px;
margin-bottom: 20px;
margin: 36px 0 24px;
background: #fbfbfb;
border-left: 2px solid #eee;
}
@ -1173,12 +1187,13 @@ a.entry-link:hover .anticon-smile {
.preview-image-boxes {
float: right;
margin: 0 0 110px 60px;
margin: 0 0 70px 28px;
width: 616px;
clear: both;
}
.preview-image-boxes + .preview-image-boxes {
margin-top: -75px;
margin-top: -35px;
}
.preview-image-box {
@ -1196,6 +1211,22 @@ a.entry-link:hover .anticon-smile {
position: relative;
}
.preview-image-wrapper.video {
padding: 0;
background: 0;
display: block;
}
.preview-image-wrapper video {
width: 100%;
display: block;
+ svg {
position: absolute;
top: 0;
left: 0;
}
}
.preview-image-wrapper.good:after {
content: '';
width: 100%;

View File

@ -0,0 +1,20 @@
{% extends "page.html" %}
{% block content %}
<section class="main-container">
<article class="markdown">
<h1>
{{ post.title }} {{ post.meta.chinese }}{{ post.meta.subtitle }}
{%- if post.meta.API %}
<a class="api-link" href="http://{{ post.meta.API }}" target="_blank">
<i class="anticon anticon-link"></i>
API 使用说明
</a>
{%- endif %}
</h1>
{{ post.html|add_anchor }}
</article>
{%- include "demos.html" %}
<div class="api-container markdown"></div>
</section>
{% endblock %}

View File

@ -13,7 +13,7 @@
<link rel="shortcut icon" href="https://t.alipayobjects.com/images/T1QUBfXo4fXXXXXXXX.png" type="image/x-icon">
{% block styles %}{% endblock %}
<link rel="stylesheet" href="{{static_url('../dist/demo.css')}}?20160114">
<script src="https://as.alipayobjects.com/g/component/??console-polyfill/0.2.2/index.js,es5-shim/4.1.14/es5-shim.min.js,es5-shim/4.1.14/es5-sham.min.js,html5shiv/3.7.2/html5shiv.min.js,media-match/2.0.2/media.match.min.js,jquery/1.11.3/jquery.min.js,bluebird/3.1.1/bluebird.min.js"></script>
<script src="https://as.alipayobjects.com/g/component/??console-polyfill/0.2.2/index.js,es5-shim/4.5.7/es5-shim.min.js,es5-shim/4.5.7/es5-sham.min.js,html5shiv/3.7.2/html5shiv.min.js,media-match/2.0.2/media.match.min.js,jquery/1.11.3/jquery.min.js,bluebird/3.1.1/bluebird.min.js"></script>
<script>
(function() {
window.ANT_COMPONENTS = [];

26
site/templates/page.html Normal file
View File

@ -0,0 +1,26 @@
{% extends "layout.html" %}
{% block title %}
{%- if post.title !== config.site.name %}
{{post.title}} {{ post.meta.chinese }} - {{config.site.name}}
{%- else %}
{{ config.site.name }} - {{ config.site.description }}
{%- endif %}
{% endblock %}
{% block description %}{% if post.summay %}{{post.summary}}{% endif %}{% endblock %}
{% block aside %}
{%- include "aside.html" %}
{% endblock %}
{% block content %}
<section class="main-container">
<article class="markdown">
<h1>{{ post.title }} <span class="subtitle">{{ post.meta.subtitle }}</span></h1>
{{ post.meta.description }}
<div class="toc">{{ post.toc }}</div>
{{ post.html|add_anchor }}
</article>
</section>
{% endblock %}

View File

@ -2,8 +2,9 @@ export default {
categoryOrder: {
组件: 0,
基础: 0,
动画: 1,
十大原则: 0,
设计基础: 1,
动画: 2,
},
typeOrder: {
基本: 0,
@ -20,4 +21,10 @@ export default {
'docs/react/upgrade-notes': 'components/upgrade-notes',
CHANGELOG: 'components/changelog',
},
docVersions: {
'0.9.x': 'http://09x.ant.design/',
'0.10.x': 'http://010x.ant.design/',
'0.11.x': 'http://011x.ant.design/',
}
};

View File

@ -5,6 +5,7 @@
position: relative;
display: inline-block;
line-height: 1;
vertical-align: middle;
&-count {
position: absolute;

View File

@ -46,10 +46,6 @@
.btn-circle(@btn-prefix-cls);
}
&-circle-outline {
.btn-circle-outline;
}
&:after {
font-family: anticon;
content: "\e6a1";
@ -101,22 +97,24 @@
&-clicked:before {
content: '';
position: absolute;
top: -6px;
left: -6px;
bottom: -6px;
right: -6px;
top: -1px;
left: -1px;
bottom: -1px;
right: -1px;
border-radius: inherit;
z-index: -1;
background: inherit;
opacity: 1;
transform: scale3d(0.5, 0.5, 1);
animation: buttonEffect 0.48s ease forwards;
border: 0 solid @primary-color;
opacity: 0.4;
animation: buttonEffect 0.32s ease forwards;
}
}
@keyframes buttonEffect {
to {
opacity: 0;
transform: scale3d(1, 1, 1);
top: -5px;
left: -5px;
bottom: -5px;
right: -5px;
border-width: 5px;
}
}

View File

@ -58,6 +58,7 @@
line-height: 12px;
top: 18px;
right: 18px;
z-index: 1;
&:before {
content: "\e62d";

View File

@ -9,7 +9,7 @@
background-color: rgba(55, 55, 55, 0.6);
height: 100%;
z-index: 1000;
filter: alpha(opacity=50);
filter: ~"alpha(opacity=50)";
&-hidden {
display: none;

View File

@ -242,6 +242,12 @@ form {
.@{css-prefix}form-item {
display: inline-block;
margin-right: 10px;
margin-bottom: 0;
&-with-help {
margin-bottom: 24px;
}
> div {
display: inline-block;
}

View File

@ -45,6 +45,7 @@
&-item-active,
&-submenu-title:hover {
transform: translateZ(0);
background-color: tint(@primary-color, 90%);
}
@ -56,10 +57,13 @@
&-horizontal > &-item-active,
&-horizontal > &-submenu &-submenu-title:hover {
background-color: transparent;
transform: translateZ(0);
}
&-item-selected {
color: @primary-color;
// fix chrome render bug
transform: translateZ(0);
}
&-inline,
@ -78,6 +82,7 @@
.@{menu-prefix-cls}-selected,
.@{menu-prefix-cls}-item-selected {
border-right: 2px solid @primary-color;
transform: translateZ(0);
}
}
@ -87,6 +92,7 @@
position: absolute;
min-width: 100%;
margin-top: 7px;
z-index: 1070;
}
&-submenu-vertical > & {
@ -95,6 +101,7 @@
position: absolute;
min-width: 160px;
margin-left: 4px;
z-index: 1070;
}
&-item,
@ -187,11 +194,13 @@
top: 1px;
float: left;
border-bottom: 2px solid transparent;
z-index: 1;
&-active,
&-selected {
border-bottom: 2px solid @primary-color;
color: @primary-color;
transform: translateZ(0);
}
> a {
@ -295,6 +304,7 @@
&-dark&-horizontal > &-submenu:hover,
&-dark&-horizontal > &-submenu &-submenu-title:hover {
color: #fff;
transform: translateZ(0);
}
&-dark &-item > a {
@ -320,11 +330,13 @@
border-right: 0;
background-color: @primary-color;
color: #fff;
transform: translateZ(0);
}
&-dark &-item-active,
&-dark &-submenu-title:hover {
background-color: transparent;
color: @primary-color;
transform: translateZ(0);
}
}

View File

@ -43,7 +43,7 @@
&:after {
content: "";
position: absolute;
background: rgba(255,255,255,0.01);
background: rgba(255, 255, 255, 0.01);
}
&-hidden {
@ -93,7 +93,7 @@
color: #666;
}
&-content {
&-inner-content {
padding: 8px 16px;
color: @text-color;
}
@ -102,9 +102,13 @@
padding: 8px 0 16px;
font-size: 12px;
color: @text-color;
.anticon {
margin-right: 8px;
> .anticon {
color: @error-color;
line-height: 17px;
position: absolute;
}
&-title {
padding-left: 20px;
}
}
@ -139,9 +143,9 @@
content: "";
}
&-placement-top > &-arrow,
&-placement-topLeft > &-arrow,
&-placement-topRight > &-arrow {
&-placement-top &-arrow,
&-placement-topLeft &-arrow,
&-placement-topRight &-arrow {
border-bottom-width: 0;
border-top-color: @popover-arrow-outer-color;
bottom: 0;
@ -153,20 +157,20 @@
border-top-color: @popover-arrow-color;
}
}
&-placement-top > &-arrow {
&-placement-top &-arrow {
left: 50%;
margin-left: -@popover-arrow-outer-width;
}
&-placement-topLeft > &-arrow {
&-placement-topLeft &-arrow {
left: 16px;
}
&-placement-topRight > &-arrow {
&-placement-topRight &-arrow {
right: 16px;
}
&-placement-right > &-arrow,
&-placement-rightTop > &-arrow,
&-placement-rightBottom > &-arrow {
&-placement-right &-arrow,
&-placement-rightTop &-arrow,
&-placement-rightBottom &-arrow {
left: 0;
border-left-width: 0;
border-right-color: @popover-arrow-outer-color;
@ -178,20 +182,20 @@
border-right-color: @popover-arrow-color;
}
}
&-placement-right > &-arrow {
&-placement-right &-arrow {
top: 50%;
margin-top: -@popover-arrow-outer-width;
}
&-placement-rightTop > &-arrow {
&-placement-rightTop &-arrow {
top: 12px;
}
&-placement-rightBottom > &-arrow {
&-placement-rightBottom &-arrow {
bottom: 12px;
}
&-placement-bottom > &-arrow,
&-placement-bottomLeft > &-arrow,
&-placement-bottomRight > &-arrow {
&-placement-bottom &-arrow,
&-placement-bottomLeft &-arrow,
&-placement-bottomRight &-arrow {
border-top-width: 0;
border-bottom-color: @popover-arrow-outer-color;
top: 0;
@ -203,20 +207,20 @@
border-bottom-color: @popover-arrow-color;
}
}
&-placement-bottom > &-arrow {
&-placement-bottom &-arrow {
left: 50%;
margin-left: -@popover-arrow-outer-width;
}
&-placement-bottomLeft > &-arrow {
&-placement-bottomLeft &-arrow {
left: 16px;
}
&-placement-bottomRight > &-arrow {
&-placement-bottomRight &-arrow {
right: 16px;
}
&-placement-left > &-arrow,
&-placement-leftTop > &-arrow,
&-placement-leftBottom > &-arrow {
&-placement-left &-arrow,
&-placement-leftTop &-arrow,
&-placement-leftBottom &-arrow {
right: 0;
border-right-width: 0;
border-left-color: @popover-arrow-outer-color;
@ -228,14 +232,14 @@
bottom: -@popover-arrow-width;
}
}
&-placement-left > &-arrow {
&-placement-left &-arrow {
top: 50%;
margin-top: -@popover-arrow-outer-width;
}
&-placement-leftTop > &-arrow {
&-placement-leftTop &-arrow {
top: 12px;
}
&-placement-leftBottom > &-arrow {
&-placement-leftBottom &-arrow {
bottom: 12px;
}
}

View File

@ -26,7 +26,7 @@
}
&-line-bg {
border-radius: 100px;
background-color: @primary-color;
background-color: @info-color;
transition: all 0.3s linear 0s;
position: relative;
}

View File

@ -82,6 +82,7 @@
th,
td {
padding: 16px 8px;
word-break: break-all;
}
th.@{table-prefix-cls}-selection-column,
@ -193,7 +194,7 @@
border-bottom: 1px solid @border-color-split;
}
tr:last-child {
tbody tr:last-child {
th,
td {
border-bottom: 0;
@ -332,11 +333,6 @@
}
}
// Hide selection component in children data
&[class*="@{table-prefix-cls}-row-level-"] .@{table-prefix-cls}-selection-column > span {
display: none;
}
&[class*="@{table-prefix-cls}-row-level-0"] .@{table-prefix-cls}-selection-column > span {
display: inline-block;
}

View File

@ -3,13 +3,16 @@
@effect-duration: .3s;
.@{tab-prefix-cls} {
outline: none;
box-sizing: border-box;
position: relative;
overflow: hidden;
.clearfix;
color: @text-color;
&-bar {
outline: none;
}
&-ink-bar {
z-index: 1;
position: absolute;
@ -23,14 +26,16 @@
&-transition-forward {
transition: right 0.3s @ease-in-out,
left 0.3s @ease-in-out 0.3s * 0.3;
transform: translateZ(0);
}
&-transition-backward {
transition: right 0.3s @ease-in-out 0.3s * 0.3,
left 0.3s @ease-in-out;
transform: translateZ(0);
}
}
&-tabs-bar {
&-bar {
border-bottom: 1px solid @border-color-base;
margin-bottom: 16px;
}
@ -176,6 +181,7 @@
&:active {
color: shade(@primary-color, 5%);
transform: translateZ(0);
}
.anticon {
@ -188,6 +194,7 @@
.@{tab-prefix-cls}-tab-active .@{tab-prefix-cls}-tab-inner {
color: @primary-color;
transform: translateZ(0);
}
}
@ -220,6 +227,7 @@
&-slide-horizontal-backward-enter&-slide-horizontal-backward-enter-active {
animation-name: antMoveLeftIn;
transform: translateZ(0);
animation-play-state: running;
}
@ -236,6 +244,7 @@
&-slide-horizontal-backward-leave&-slide-horizontal-backward-leave-active {
animation-name: antMoveRightOut;
transform: translateZ(0);
animation-play-state: running;
}
@ -249,6 +258,7 @@
&-slide-horizontal-forward-enter&-slide-horizontal-forward-enter-active {
animation-name: antMoveRightIn;
animation-play-state: running;
transform: translateZ(0);
}
&-slide-horizontal-forward-leave {
@ -263,6 +273,7 @@
}
&-slide-horizontal-forward-leave&-slide-horizontal-forward-leave-active {
transform: translateZ(0);
animation-name: antMoveLeftOut;
animation-play-state: running;
}
@ -284,7 +295,7 @@
width: auto;
}
.@{tab-prefix-cls}-tabs-bar {
.@{tab-prefix-cls}-bar {
border-bottom: 0;
}
@ -321,7 +332,7 @@
}
&-vertical&-left {
.@{tab-prefix-cls}-tabs-bar {
.@{tab-prefix-cls}-bar {
float: left;
border-right: 1px solid @border-color-split;
margin-right: -1px;
@ -348,7 +359,7 @@
}
&-vertical&-right {
.@{tab-prefix-cls}-tabs-bar {
.@{tab-prefix-cls}-bar {
float: right;
border-left: 1px solid @border-color-split;
margin-left: -1px;
@ -369,7 +380,7 @@
}
}
&-bottom &-tabs-bar {
&-bottom &-bar {
margin-bottom: 0;
margin-top: 16px;
}
@ -397,11 +408,13 @@
}
&&-card &-tab-active {
background: #fff;
transform: translateZ(0);
border-color: @border-color-base;
color: @primary-color;
}
&&-card &-tab-active &-tab-inner {
padding-bottom: 7px;
transform: translateZ(0);
}
&&-card &-nav-wrap {
margin-bottom: 0;
@ -430,6 +443,7 @@
&&-card &-tab-active .anticon-cross,
&&-card &-tab:hover .anticon-cross {
width: 16px;
transform: translateZ(0);
}
&-extra-content {

Some files were not shown because too many files have changed in this diff Show More