diff --git a/CHANGELOG.md b/CHANGELOG.md
index f613f3d4fa..f5906507ed 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,12 +4,12 @@
---
-## 0.11.1 `developing`
+## 0.11.1 `2015-12-29`
- 修复一个 Table 无法修改 pageSize 的问题。
- 修复一个 Table 子表格展开的对齐问题。
-- 修复一个 chrome 下部分图标左侧切边的问题。
-- 修复搜索输入框在表单下使用的样式问题。
+- 修复一个 Chrome 下部分图标左侧切边的问题。
+- 修复搜索输入框在表单下使用的样式问题。[#762](https://github.com/ant-design/ant-design/issues/762)
## 0.11.0 `2015-12-28`
diff --git a/components/cascader/demo/basic.md b/components/cascader/demo/basic.md
new file mode 100644
index 0000000000..445f039f4f
--- /dev/null
+++ b/components/cascader/demo/basic.md
@@ -0,0 +1,43 @@
+# 基本
+
+- order: 0
+
+省市区级联。
+
+---
+
+````jsx
+import { Cascader } from 'antd';
+
+const options = [{
+ value: 'zhejiang',
+ label: '浙江',
+ children: [{
+ value: 'hangzhou',
+ label: '杭州',
+ children: [{
+ value: 'xihu',
+ label: '西湖',
+ }],
+ }],
+}, {
+ value: 'jiangsu',
+ label: '江苏',
+ children: [{
+ value: 'nanjing',
+ label: '南京',
+ children: [{
+ value: 'zhonghuamen',
+ label: '中华门',
+ }],
+ }],
+}];
+
+function onChange(value) {
+ console.log(value);
+}
+
+ReactDOM.render(
+
+, mountNode);
+````
diff --git a/components/cascader/demo/custom-trigger.md b/components/cascader/demo/custom-trigger.md
new file mode 100644
index 0000000000..ddc07c01a1
--- /dev/null
+++ b/components/cascader/demo/custom-trigger.md
@@ -0,0 +1,53 @@
+# 可以自定义显示
+
+- order: 1
+
+切换按钮和结果分开。
+
+---
+
+````jsx
+import { Cascader } from 'antd';
+
+const options = [{
+ value: 'zhejiang',
+ label: '浙江',
+ children: [{
+ value: 'hangzhou',
+ label: '杭州',
+ }],
+}, {
+ value: 'jiangsu',
+ label: '江苏',
+ children: [{
+ value: 'nanjing',
+ label: '南京',
+ }],
+}];
+
+const CitySwitcher = React.createClass({
+ getInitialState() {
+ return {
+ text: '未选择',
+ };
+ },
+ onChange(value, selectedOptions) {
+ this.setState({
+ text: selectedOptions.map(o => o.label).join(', '),
+ });
+ },
+ render() {
+ return (
+
+ {this.state.text}
+
+
+ 切换城市
+
+
+ );
+ },
+});
+
+ReactDOM.render(, mountNode);
+````
diff --git a/components/cascader/demo/default-value.md b/components/cascader/demo/default-value.md
new file mode 100644
index 0000000000..db4ea4eee0
--- /dev/null
+++ b/components/cascader/demo/default-value.md
@@ -0,0 +1,43 @@
+# 默认值
+
+- order: 0
+
+默认值通过数组的方式指定。
+
+---
+
+````jsx
+import { Cascader } from 'antd';
+
+const options = [{
+ value: 'zhejiang',
+ label: '浙江',
+ children: [{
+ value: 'hangzhou',
+ label: '杭州',
+ children: [{
+ value: 'xihu',
+ label: '西湖',
+ }],
+ }],
+}, {
+ value: 'jiangsu',
+ label: '江苏',
+ children: [{
+ value: 'nanjing',
+ label: '南京',
+ children: [{
+ value: 'zhonghuamen',
+ label: '中华门',
+ }],
+ }],
+}];
+
+function onChange(value) {
+ console.log(value);
+}
+
+ReactDOM.render(
+
+, mountNode);
+````
diff --git a/components/cascader/demo/hover.md b/components/cascader/demo/hover.md
new file mode 100644
index 0000000000..f9e51caa30
--- /dev/null
+++ b/components/cascader/demo/hover.md
@@ -0,0 +1,49 @@
+# 移入展开
+
+- order: 2
+
+通过移入展开下级菜单,点击完成选择。
+
+---
+
+````jsx
+import { Cascader } from 'antd';
+
+const options = [{
+ value: 'zhejiang',
+ label: '浙江',
+ children: [{
+ value: 'hangzhou',
+ label: '杭州',
+ children: [{
+ value: 'xihu',
+ label: '西湖',
+ }],
+ }],
+}, {
+ value: 'jiangsu',
+ label: '江苏',
+ children: [{
+ value: 'nanjing',
+ label: '南京',
+ children: [{
+ value: 'zhonghuamen',
+ label: '中华门',
+ }],
+ }],
+}];
+
+function onChange(value) {
+ console.log(value);
+}
+
+// 只展示最后一项
+function displayRender(label) {
+ return label[label.length - 1];
+}
+
+ReactDOM.render(
+
+, mountNode);
+````
diff --git a/components/cascader/index.jsx b/components/cascader/index.jsx
new file mode 100644
index 0000000000..448766707a
--- /dev/null
+++ b/components/cascader/index.jsx
@@ -0,0 +1,102 @@
+import React from 'react';
+import Cascader from 'rc-cascader';
+import Input from '../input';
+import Icon from '../icon';
+import arrayTreeFilter from 'array-tree-filter';
+import classNames from 'classnames';
+
+class AntCascader extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ value: props.value || props.defaultValue || [],
+ popupVisible: false,
+ };
+ [
+ 'handleChange',
+ 'handlePopupVisibleChange',
+ 'setValue',
+ 'getLabel',
+ 'clearSelection',
+ ].forEach((method) => this[method] = this[method].bind(this));
+ }
+ componentWillReceiveProps(nextProps) {
+ if ('value' in nextProps) {
+ this.setState({ value: nextProps.value });
+ }
+ }
+ handleChange(value, selectedOptions) {
+ this.setValue(value, selectedOptions);
+ }
+ handlePopupVisibleChange(popupVisible) {
+ this.setState({ popupVisible });
+ this.props.onPopupVisibleChange(popupVisible);
+ }
+ setValue(value, selectedOptions = []) {
+ if (!('value' in this.props)) {
+ this.setState({ value });
+ }
+ this.props.onChange(value, selectedOptions);
+ }
+ getLabel() {
+ const { options, displayRender } = this.props;
+ const label = arrayTreeFilter(options, (o, level) => o.value === this.state.value[level])
+ .map(o => o.label);
+ return displayRender(label);
+ }
+ clearSelection(e) {
+ e.preventDefault();
+ e.stopPropagation();
+ this.setValue([]);
+ this.setState({ popupVisible: false });
+ }
+ render() {
+ const { prefixCls, children, placeholder, style, size } = this.props;
+ const sizeCls = classNames({
+ 'ant-input-lg': size === 'large',
+ 'ant-input-sm': size === 'small',
+ });
+ const clearIcon = this.state.value.length > 0 ?
+ : null;
+ const arrowCls = classNames({
+ [`${prefixCls}-picker-arrow`]: true,
+ [`${prefixCls}-picker-arrow-expand`]: this.state.popupVisible,
+ });
+ return (
+
+ {children ||
+
+
+ {clearIcon}
+
+
+ }
+
+ );
+ }
+}
+
+AntCascader.defaultProps = {
+ prefixCls: 'ant-cascader',
+ placeholder: '请选择',
+ transitionName: 'slide-up',
+ onChange() {},
+ options: [],
+ displayRender(label) {
+ return label.join(' / ');
+ },
+ size: 'default',
+ onPopupVisibleChange() {},
+};
+
+export default AntCascader;
diff --git a/components/cascader/index.md b/components/cascader/index.md
new file mode 100644
index 0000000000..4d9ce58c3f
--- /dev/null
+++ b/components/cascader/index.md
@@ -0,0 +1,34 @@
+# Cascader
+
+- category: Components
+- chinese: 级联选择
+- type: 表单
+
+---
+
+级联选择框。
+
+
+## 何时使用
+
+- 需要从一组相关联的数据集合进行选择,例如省市区,公司层级,事物分类等。
+- 从一个较大的数据集合中进行选择时,用多级分类进行分隔,方便选择。
+- 比起 Select 组件,可以在同一个浮层中完成选择,有较好的体验。
+
+## API
+
+```html
+
+```
+
+| 参数 | 说明 | 类型 | 默认值 |
+|------|------|------|--------|
+| options | 可选项数据源 | object | - |
+| defaultValue | 默认的选中项 | array |[] |
+| value | 指定选中项 | array | - |
+| onChange | 选择完成后的回调 | `function(value, selectedOptions)` | - |
+| displayRender | 选择后展示的渲染函数 | `function(label)`` | `function(label) { return label.join(' / ') }` |
+| style | 自定义样式 | string | - |
+| popupClassName | 自定义浮层类名 | string | - |
+| placeholder | 输入框占位文本 | string | '请选择' |
+| size | 输入框大小,可选 `large` `default` `small` | string | `default` |
diff --git a/components/date-picker/locale/en_US.js b/components/date-picker/locale/en_US.js
index cb67d925d1..aff512e58b 100644
--- a/components/date-picker/locale/en_US.js
+++ b/components/date-picker/locale/en_US.js
@@ -5,7 +5,8 @@ import CalendarLocale from 'rc-calendar/lib/locale/en_US';
// 统一合并为完整的 Locale
let locale = objectAssign({}, GregorianCalendarLocale);
locale.lang = objectAssign({
- placeholder: 'Select a date'
+ placeholder: 'Select date',
+ timePlaceholder: 'Select time',
}, CalendarLocale);
// All settings at:
diff --git a/components/form/demo/advanced-search-form.md b/components/form/demo/advanced-search-form.md
new file mode 100644
index 0000000000..2c2b58c686
--- /dev/null
+++ b/components/form/demo/advanced-search-form.md
@@ -0,0 +1,121 @@
+# 高级搜索
+
+- order: 10
+
+三列栅格式的表单排列方式,常用于数据表格的高级搜索。
+
+有部分定制的样式代码,由于输入标签长度不确定,需要根据具体情况自行调整。
+
+---
+
+````jsx
+import { Form, Input, Row, Col, Button } from 'antd';
+const FormItem = Form.Item;
+
+ReactDOM.render(
+
+, mountNode);
+````
+
+````css
+/* 定制样式 */
+
+.advanced-search-form {
+ padding: 16px 8px;
+ background: #f8f8f8;
+ border: 1px solid #d9d9d9;
+ border-radius: 6px;
+}
+
+/* 由于输入标签长度不确定,所以需要微调使之看上去居中 */
+.advanced-search-form > .row {
+ margin-left: -10px;
+}
+
+.advanced-search-form > .row > .col-8 {
+ padding: 0 8px;
+}
+
+.advanced-search-form .ant-form-item {
+ margin-bottom: 16px;
+}
+
+.advanced-search-form .ant-btn + .ant-btn {
+ margin-left: 8px;
+}
+````
+
+
diff --git a/components/form/index.md b/components/form/index.md
index 8cbdab87d9..234713a52d 100644
--- a/components/form/index.md
+++ b/components/form/index.md
@@ -3,6 +3,7 @@
- category: Components
- chinese: 表单
- type: 表单
+- cols: 1
---
@@ -86,3 +87,8 @@ Mixin:当表单控件的输入值改变时,更新 formData。
```
+
diff --git a/components/select/demo/coordinate.md b/components/select/demo/coordinate.md
index 07b9e5224f..cfe89f6525 100644
--- a/components/select/demo/coordinate.md
+++ b/components/select/demo/coordinate.md
@@ -4,6 +4,8 @@
省市联动是典型的例子。
+推荐使用 [cascader](/components/cascader/) 组件。
+
---
````jsx
diff --git a/components/tree-select/demo/basic.md b/components/tree-select/demo/basic.md
new file mode 100644
index 0000000000..4562aade6f
--- /dev/null
+++ b/components/tree-select/demo/basic.md
@@ -0,0 +1,55 @@
+# 基本
+
+- order: 0
+
+最简单的用法。
+
+---
+
+````jsx
+import { TreeSelect } from 'antd';
+const TreeNode = TreeSelect.TreeNode;
+
+const Demo = React.createClass({
+ getInitialState() {
+ return {
+ value: 'leaf1',
+ };
+ },
+ onChange(e) {
+ let value;
+ if (e.target) {
+ value = e.target.value;
+ } else {
+ value = e;
+ }
+ this.setState({value});
+ },
+ render() {
+ return (
+
+
Single Select
+
+
+
+
+
+
+
+ sss} key="random3" />
+
+
+
+
+ );
+ },
+});
+
+ReactDOM.render(
+
+, document.getElementById('components-tree-select-demo-basic'));
+````
diff --git a/components/tree-select/demo/enhance.md b/components/tree-select/demo/enhance.md
new file mode 100644
index 0000000000..cd6e59543a
--- /dev/null
+++ b/components/tree-select/demo/enhance.md
@@ -0,0 +1,89 @@
+# 更多功能
+
+- order: 1
+
+更多功能。
+
+---
+
+````jsx
+import { TreeSelect } from 'antd';
+const TreeNode = TreeSelect.TreeNode;
+
+const x = 3;
+const y = 2;
+const z = 1;
+const gData = [];
+const generateData = (_level, _preKey, _tns) => {
+ const preKey = _preKey || '0';
+ const tns = _tns || gData;
+
+ const children = [];
+ for (let i = 0; i < x; i++) {
+ const key = `${preKey}-${i}`;
+ tns.push({title: key, key: key});
+ if (i < y) {
+ children.push(key);
+ }
+ }
+ if (_level < 0) {
+ return tns;
+ }
+ const __level = _level - 1;
+ children.forEach((key, index) => {
+ tns[index].children = [];
+ return generateData(__level, key, tns[index].children);
+ });
+};
+generateData(z);
+
+const Demo = React.createClass({
+ getInitialState() {
+ return {
+ value: ['0-0'],
+ };
+ },
+ onSelect(selectedKey, node, selectedKeys) {
+ console.log('selected: ', selectedKey, selectedKeys);
+ this.setState({
+ value: selectedKeys,
+ });
+ },
+ onChange(value) {
+ console.log('selected ' + value);
+ this.setState({
+ value: value,
+ });
+ },
+ render() {
+ const loop = data => {
+ return data.map((item) => {
+ if (item.children) {
+ return {loop(item.children)};
+ }
+ return ;
+ });
+ };
+ const tProps = {
+ // defaultValue: this.state.value,
+ value: this.state.value,
+ onChange: this.onChange,
+ onSelect: this.onSelect,
+ multiple: true,
+ // treeCheckable: true,
+ treeDefaultExpandAll: true,
+ };
+ return (
+
more
+
+ {loop(gData)}
+
+ );
+ },
+});
+
+ReactDOM.render(
+
+
+, document.getElementById('components-tree-select-demo-enhance'));
+````
diff --git a/components/tree-select/index.jsx b/components/tree-select/index.jsx
new file mode 100644
index 0000000000..56e1d5ccc0
--- /dev/null
+++ b/components/tree-select/index.jsx
@@ -0,0 +1,49 @@
+import React from 'react';
+import TreeSelect, { TreeNode } from 'rc-tree-select';
+import classNames from 'classnames';
+// import assign from 'object-assign';
+// import animation from '../common/openAnimation';
+
+const AntTreeSelect = React.createClass({
+ getDefaultProps() {
+ return {
+ prefixCls: 'ant-tree-select',
+ transitionName: 'slide-up',
+ optionLabelProp: 'value',
+ choiceTransitionName: 'zoom',
+ showSearch: false,
+ size: 'default'
+ };
+ },
+ render() {
+ const props = this.props;
+ let {
+ size, className, combobox, notFoundContent
+ } = this.props;
+
+ const cls = classNames({
+ 'ant-select-lg': size === 'large',
+ 'ant-select-sm': size === 'small',
+ [className]: !!className,
+ });
+
+ if (combobox) {
+ notFoundContent = null;
+ }
+
+ let checkable = props.treeCheckable;
+ if (checkable) {
+ checkable = ;
+ }
+
+ return (
+
+ );
+ }
+});
+
+AntTreeSelect.TreeNode = TreeNode;
+export default AntTreeSelect;
diff --git a/components/tree-select/index.md b/components/tree-select/index.md
new file mode 100644
index 0000000000..8f389fc216
--- /dev/null
+++ b/components/tree-select/index.md
@@ -0,0 +1,49 @@
+# TreeSelect
+
+- category: Components
+- chinese: 树选择控件
+- type: 表单
+
+---
+
+## 何时使用
+
+当需要从树控件中灵活地筛选数据时
+
+## API
+
+### Tree props
+
+| 参数 | 说明 | 类型 | 默认值 |
+|-----------|------------------------------------------|------------|--------|
+| value | 指定当前选中的条目 | string/Array | 无 |
+| defaultValue | 指定默认选中的条目 | string/Array | 无 |
+| multiple | 支持多选 | boolean | false |
+| tags | 可以把随意输入的条目作为 tag,输入项不需要与下拉选项匹配 | boolean |false |
+| onSelect | 被选中时调用,参数为选中项的 value 值 | function(value, option) | 无 |
+| onChange | 选中option,或input的value变化(combobox 模式下)时,调用此函数 | function(value, label) | 无 |
+| allowClear | 显示清除按钮 | boolean | false |
+| onSearch | 文本框值变化时回调 | function(value: String) | |
+| placeholder | 选择框默认文字 | string | 无 |
+| searchPlaceholder | 搜索框默认文字 | string | 无 |
+| dropdownMatchSelectWidth | 下拉菜单和选择器同宽 | boolean | true |
+| combobox | 输入框自动提示模式 | boolean | false |
+| size | 选择框大小,可选 `large` `small` | String | default |
+| showSearch | 在下拉中显示搜索框 | boolean | false |
+| disabled | 是否禁用 | boolean | false |
+| treeDefaultExpandAll | 默认展开所有树节点 | bool | false |
+| treeCheckable | 显示checkbox | bool | false |
+| filterTreeNode | 是否根据输入项进行筛选,返回值true | function(treeNode) | - |
+| treeNodeFilterProp | 输入项过滤对应的 treeNode 属性 | String | 'value' |
+| treeNodeLabelProp | 作为显示的prop设置 | String | 'value' |
+| loadData | 异步加载数据 | function(node) | - |
+
+### TreeNode props
+
+| 参数 | 说明 | 类型 | 默认值 |
+|-----------|------------------------------------------|------------|--------|
+| disabled | 是否禁用 | Boolean | false |
+| key | 此项必须设置 | String | |
+| value | 默认根据此属性值进行筛选 | String | - |
+| title | 树节点显示的内容 | String | '---' |
+| isLeaf | 是否是叶子节点 | bool | false |
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 44a2c7d95e..f1bf6ccde5 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -9,9 +9,9 @@ Ant Design React 致力于提供给程序员**愉悦**的开发体验。
## 第一个例子
-最简单的试用方式参照以下 JSFiddle 演示, 也推荐 Fork 本例来进行 Bug Report, 注意不要在实际项目中这样使用。
+最简单的试用方式参照以下 JSFiddle 演示, 也推荐 Fork 本例来进行 `Bug Report`, 注意不要在实际项目中这样使用。
-- [antd JSFiddle](http://jsfiddle.net/yiminghe/9zrstuto/1/)
+- [antd JSFiddle](http://jsfiddle.net/9zrstuto/70/)
## 标准开发
diff --git a/index.js b/index.js
index 0b5a8bbbbc..3d0a4f5fe4 100644
--- a/index.js
+++ b/index.js
@@ -29,6 +29,7 @@ const antd = {
Alert: require('./components/alert'),
Validation: require('./components/validation'),
Tree: require('./components/tree'),
+ TreeSelect: require('./components/tree-select'),
Upload: require('./components/upload'),
Badge: require('./components/badge'),
Menu: require('./components/menu'),
@@ -43,6 +44,7 @@ const antd = {
Calendar: require('./components/calendar'),
TimePicker: require('./components/time-picker'),
Transfer: require('./components/transfer'),
+ Cascader: require('./components/cascader'),
};
antd.version = require('./package.json').version;
diff --git a/package.json b/package.json
index 9e00194be9..a0c2f4fc28 100644
--- a/package.json
+++ b/package.json
@@ -32,6 +32,7 @@
],
"license": "MIT",
"dependencies": {
+ "array-tree-filter": "~1.0.0",
"classnames": "~2.2.0",
"css-animation": "1.1.x",
"gregorian-calendar": "~4.1.0",
@@ -39,6 +40,7 @@
"object-assign": "~4.0.1",
"rc-animate": "~2.0.2",
"rc-calendar": "~5.2.0",
+ "rc-cascader": "~0.5.0",
"rc-checkbox": "~1.1.1",
"rc-collapse": "~1.4.4",
"rc-dialog": "~5.2.2",
@@ -59,7 +61,8 @@
"rc-tabs": "~5.6.0",
"rc-time-picker": "~1.0.0",
"rc-tooltip": "~3.3.0",
- "rc-tree": "~0.19.0",
+ "rc-tree": "^0.23.1",
+ "rc-tree-select": "^0.3.3",
"rc-trigger": "~1.0.6",
"rc-upload": "~1.7.0",
"rc-util": "~3.0.1",
@@ -99,10 +102,10 @@
"lodash": "^3.10.0",
"nico-jsx": "~0.7.0",
"pre-commit": "1.x",
- "react": "~0.14.2",
- "react-addons-test-utils": "~0.14.2",
+ "react": "~0.14.5",
+ "react-addons-test-utils": "~0.14.5",
"react-copy-to-clipboard": "^3.0.4",
- "react-dom": "~0.14.2",
+ "react-dom": "~0.14.5",
"react-router": "~1.0.3",
"react-stateless-wrapper": "~1.0.2",
"reqwest": "~2.0.5",
diff --git a/site/static/style.css b/site/static/style.css
index 9652398b59..1f7c4dfcc3 100644
--- a/site/static/style.css
+++ b/site/static/style.css
@@ -556,13 +556,6 @@ footer ul li > a {
margin: 20px 0;
}
-.markdown code,
-.markdown kbd,
-.markdown pre,
-.markdown samp {
- font-family: Consolas, monospace;
-}
-
.markdown p,
.markdown pre {
margin: 1.2em 0;
@@ -590,14 +583,13 @@ footer ul li > a {
}
.markdown pre {
- background: #F7F7F7;
border-radius: 6px;
}
.markdown pre code {
- background: #F7F7F7;
border: none;
- padding: 12px 20px;
+ padding: 1em 2em;
+ background: #f9f9f9;
margin: 0;
}
diff --git a/site/static/tomorrow.css b/site/static/tomorrow.css
index 9026804c27..585bc4608a 100644
--- a/site/static/tomorrow.css
+++ b/site/static/tomorrow.css
@@ -35,22 +35,23 @@
}
code {
- background: #f6f6f6;
+ background: #f7f7f7;
padding: 1px 6px;
border-radius: 3px;
color: #888;
- font-size: 90%;
+ font-size: 0.8rem;
border: 1px solid #e9e9e9;
+ white-space: nowrap;
}
pre code {
display: block;
background: white;
color: #666;
- font-family: Consolas, monospace;
line-height: 1.5;
border: 1px solid #e9e9e9;
padding: 10px 15px;
border-radius: 6px;
- font-size: 14px;
+ font-size: 0.9rem;
+ white-space: pre;
}
diff --git a/style/components/cascader.less b/style/components/cascader.less
new file mode 100644
index 0000000000..dfc2b9d7b9
--- /dev/null
+++ b/style/components/cascader.less
@@ -0,0 +1,133 @@
+@cascader-prefix-cls: ant-cascader;
+
+.@{cascader-prefix-cls} {
+ font-size: @font-size-base;
+ &-input {
+ width: 172px;
+ display: block;
+ cursor: pointer;
+ }
+ &-picker {
+ position: relative;
+ display: inline-block;
+ cursor: pointer;
+
+ &-clear {
+ opacity: 0;
+ position: absolute;
+ right: 8px;
+ z-index: 1;
+ background: #fff;
+ top: 50%;
+ font-size: 12px;
+ color: #ccc;
+ width: 12px;
+ height: 12px;
+ margin-top: -6px;
+ line-height: 12px;
+ cursor: pointer;
+ transition: color 0.3s ease, opacity 0.15s ease;
+ &:hover {
+ color: #999;
+ }
+ }
+
+ &:hover &-clear {
+ opacity: 1;
+ }
+
+ // arrow
+ &-arrow {
+ position: absolute;
+ top: 50%;
+ right: 8px;
+ width: 12px;
+ height: 12px;
+ margin-top: -6px;
+ line-height: 12px;
+ .iconfont-size-under-12px(8px);
+ &:before {
+ transition: transform 0.2s ease;
+ }
+ &&-expand {
+ .ie-rotate(2);
+ &:before {
+ .rotate(180deg);
+ }
+ }
+ }
+ }
+ &-menus {
+ font-size: 12px;
+ overflow: hidden;
+ background: #fff;
+ position: absolute;
+ border: 1px solid @border-color-base;
+ border-radius: @border-radius-base;
+ box-shadow: @box-shadow-base;
+ &-hidden {
+ display: none;
+ }
+ &.slide-up-enter.slide-up-enter-active&-placement-bottomLeft,
+ &.slide-up-appear.slide-up-appear-active&-placement-bottomLeft {
+ animation-name: antSlideUpIn;
+ }
+
+ &.slide-up-enter.slide-up-enter-active&-placement-topLeft,
+ &.slide-up-appear.slide-up-appear-active&-placement-topLeft {
+ animation-name: antSlideDownIn;
+ }
+
+ &.slide-up-leave.slide-up-leave-active&-placement-bottomLeft {
+ animation-name: antSlideUpOut;
+ }
+
+ &.slide-up-leave.slide-up-leave-active&-placement-topLeft {
+ animation-name: antSlideDownOut;
+ }
+ }
+ &-menu {
+ float: left;
+ width: 111px;
+ height: 180px;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ border-right: 1px solid @border-color-split;
+ &:last-child {
+ border-right-color: transparent;
+ margin-right: -1px;
+ }
+ }
+ &-menu-item {
+ height: 32px;
+ line-height: 32px;
+ padding: 0 16px;
+ cursor: pointer;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ transition: all 0.3s ease;
+ &:hover {
+ background: tint(@primary-color, 90%);
+ }
+ &-active {
+ background: tint(@primary-color, 80%);
+ &:hover {
+ background: tint(@primary-color, 80%);
+ }
+ }
+ &-expand {
+ position: relative;
+ &:after {
+ content: '\e600';
+ font-family: 'anticon';
+ .iconfont-size-under-12px(8px);
+ color: #999;
+ position: absolute;
+ right: 15px;
+ line-height: 32px;
+ }
+ }
+ }
+}
diff --git a/style/components/index.less b/style/components/index.less
index 0048394171..14107786b5 100644
--- a/style/components/index.less
+++ b/style/components/index.less
@@ -27,6 +27,7 @@
@import "tag";
@import "alert";
@import "tree";
+@import "treeSelect";
@import "carousel/slick";
@import "carousel/slick-theme";
@import "upload";
@@ -38,3 +39,4 @@
@import "calendar";
@import "timepicker";
@import "transfer";
+@import "cascader";
diff --git a/style/components/treeSelect.less b/style/components/treeSelect.less
new file mode 100644
index 0000000000..6bf36e14f3
--- /dev/null
+++ b/style/components/treeSelect.less
@@ -0,0 +1,580 @@
+@tree-select-tree-prefix-cls: ant-tree-select-tree;
+.antCheckboxFn(@checkbox-prefix-cls: ant-tree-select-tree-checkbox);
+@import "../mixins/iconfont";
+.antTreeSwitcherIcon() {
+ position: relative;
+ &:after {
+ .iconfont-size-under-12px(6px);
+ content: '\e611';
+ display: inline-block;
+ font-family: 'anticon';
+ font-weight: bold;
+ position: absolute;
+ top: 10px;
+ right: 4px;
+ color: #666;
+ transition: transform .3s ease;
+ }
+}
+.@{tree-select-tree-prefix-cls} {
+ margin: 0;
+ padding: 5px;
+ font-size: 12px;
+ li {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+ white-space: nowrap;
+ outline: 0;
+ ul {
+ margin: 0;
+ padding: 0 0 0 18px;
+ }
+ a {
+ display: inline-block;
+ padding: 1px 4px;
+ border-radius: 2px;
+ margin: 0;
+ cursor: pointer;
+ height: 20px;
+ text-decoration: none;
+ vertical-align: top;
+ color: #666;
+ }
+ span {
+ &.@{tree-select-tree-prefix-cls}-checkbox {
+ margin: 3px 4px 0 0;
+ }
+ &.@{tree-select-tree-prefix-cls}-switcher-noop,
+ &.@{tree-select-tree-prefix-cls}-switcher,
+ &.@{tree-select-tree-prefix-cls}-iconEle {
+ line-height: 0;
+ margin: 0;
+ width: 16px;
+ height: 18px;
+ display: inline-block;
+ vertical-align: middle;
+ border: 0 none;
+ cursor: pointer;
+ outline: none;
+ }
+ &.@{tree-select-tree-prefix-cls}-icon_loading {
+ &:after {
+ content: '\e6a1';
+ display: inline-block;
+ font-family: 'anticon';
+ font-weight: bold;
+ .animation(loadingCircle 1s infinite linear);
+ margin-top: 8px;
+ }
+ }
+ &.@{tree-select-tree-prefix-cls}-switcher {
+ &-disabled {
+ background: #fff;
+ position: relative;
+ &:after {
+ content: '-';
+ position: absolute;
+ top: 8px;
+ left: 6px;
+ color: gray;
+ }
+ }
+ &.@{tree-select-tree-prefix-cls}-roots_open,
+ &.@{tree-select-tree-prefix-cls}-center_open,
+ &.@{tree-select-tree-prefix-cls}-bottom_open,
+ &.@{tree-select-tree-prefix-cls}-noline_open {
+ .antTreeSwitcherIcon();
+ }
+ &.@{tree-select-tree-prefix-cls}-roots_close,
+ &.@{tree-select-tree-prefix-cls}-center_close,
+ &.@{tree-select-tree-prefix-cls}-bottom_close,
+ &.@{tree-select-tree-prefix-cls}-noline_close {
+ .antTreeSwitcherIcon();
+ .ie-rotate(3);
+ &:after {
+ transform: rotate(270deg) scale(0.5);
+ }
+ }
+ }
+ }
+ }
+ &-child-tree {
+ display: none;
+ &-open {
+ display: block;
+ }
+ }
+ &-treenode-disabled {
+ >span,
+ >a {
+ color: gray;
+ }
+ }
+ &-node-selected {
+ background-color: tint(@primary-color, 90%);
+ }
+ &-icon__open {
+ margin-right: 2px;
+ vertical-align: top;
+ }
+ &-icon__close {
+ margin-right: 2px;
+ vertical-align: top;
+ }
+}
+
+
+@tree-select-prefix-cls: ant-tree-select;
+
+@duration: .3s;
+
+@import "../mixins/iconfont";
+//mixin
+.selection__clear() {
+ cursor: pointer;
+ float: right;
+ font-weight: bold;
+}
+
+.@{tree-select-prefix-cls} {
+ box-sizing: border-box;
+ display: inline-block;
+ margin: 0;
+ position: relative;
+ vertical-align: middle;
+ color: #666;
+ font-size: @font-size-base;
+
+ > ul > li > a {
+ padding: 0;
+ background-color: #fff;
+ }
+
+ // arrow
+ &-arrow {
+ .iconfont-mixin();
+ position: absolute;
+ top: 50%;
+ right: 8px;
+ line-height: 1;
+ margin-top: -5px;
+ .iconfont-size-under-12px(8px);
+
+ * {
+ display: none;
+ }
+
+ &:before {
+ content: '\e603';
+ transition: transform 0.2s ease;
+ }
+ }
+
+ &-selection {
+ outline: none;
+ user-select: none;
+
+ box-sizing: border-box;
+ display: block;
+
+ background-color: #fff;
+ border-radius: @border-radius-base;
+ border: 1px solid #d9d9d9;
+ .transition(all .3s @ease-in-out);
+
+ &:hover {
+ .hover;
+ }
+ &:active {
+ .active;
+ }
+ }
+
+ &-disabled {
+ color: #ccc;
+ }
+
+ &-disabled &-selection {
+ &:hover,
+ &:active {
+ border-color: #d9d9d9;
+ }
+ }
+
+ &-disabled &-selection--single {
+ cursor: not-allowed;
+ }
+
+ &-selection--single {
+ height: 28px;
+ cursor: pointer;
+
+ .@{tree-select-prefix-cls}-selection__rendered {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ padding-left: 8px;
+ padding-right: 24px;
+ line-height: 26px;
+ }
+
+ .@{tree-select-prefix-cls}-selection__clear {
+ .selection__clear();
+ }
+
+ .@{tree-select-prefix-cls}-selection__placeholder {
+ color: #ccc;
+ }
+ }
+
+ &-lg {
+ .ant-select-selection--single {
+ height: 32px;
+ .ant-select-selection__rendered {
+ line-height: 30px;
+ }
+ }
+
+ .ant-select-selection--multiple {
+ min-height: 32px;
+ .ant-select-selection__rendered {
+ li {
+ height: 24px;
+ .ant-select-selection__choice__content {
+ font-size: 14px;
+ line-height: 24px;
+ }
+ }
+ }
+ }
+ }
+
+ &-sm {
+ .ant-select-selection--single {
+ height: 22px;
+ .ant-select-selection__rendered {
+ line-height: 20px;
+ }
+ }
+ .ant-select-selection--multiple {
+ min-height: 22px;
+ .ant-select-selection__rendered {
+ li {
+ height: 14px;
+ .ant-select-selection__choice__content {
+ line-height: 14px;
+ position: relative;
+ top: -3px;
+ }
+ .ant-select-selection__choice__remove {
+ position: relative;
+ top: -4px;
+ }
+ }
+ }
+ }
+ }
+
+ &-disabled &-selection__choice__remove {
+ color: #ccc;
+ cursor: default;
+ &:hover {
+ color: #ccc;
+ }
+ }
+
+ &-search__field__wrap {
+ display: inline-block;
+ position: relative;
+ }
+
+ &-search__field__placeholder {
+ position: absolute;
+ top: 0;
+ left: 3px;
+ color: #aaa;
+ }
+
+ &-search--inline {
+ float: left;
+
+ .@{tree-select-prefix-cls}-search__field__wrap {
+ width: 100%;
+ }
+
+ .@{tree-select-prefix-cls}-search__field {
+ border: 0;
+ font-size: 100%;
+ background: transparent;
+ outline: 0;
+ }
+ > i {
+ float: right;
+ }
+ }
+
+ &-selection--multiple {
+ min-height: 28px;
+ cursor: text;
+
+ .@{tree-select-prefix-cls}-search__field__placeholder {
+ top: 6px;
+ left: 10px;
+ }
+
+ .@{tree-select-prefix-cls}-search--inline {
+ width: auto;
+ .@{tree-select-prefix-cls}-search__field {
+ width: 0.75em;
+ }
+ }
+
+ .@{tree-select-prefix-cls}-selection__rendered {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ padding-left: 6px;
+ padding-bottom: 4px;
+ }
+
+ .@{tree-select-prefix-cls}-selection__clear {
+ .selection__clear();
+ margin-top: 5px;
+ margin-right: 10px;
+ }
+
+ > ul > li {
+ margin-top: 4px;
+ height: 20px;
+ line-height: 20px;
+ }
+
+ .@{tree-select-prefix-cls}-selection__choice {
+ background-color: #f3f3f3;
+ border-radius: 4px;
+ cursor: default;
+ float: left;
+ padding: 0 15px;
+ margin-right: 4px;
+ max-width: 99%;
+ position: relative;
+ overflow: hidden;
+ transition: padding @duration @ease-in-out;
+ padding: 0 20px 0 10px;
+ }
+
+ .@{tree-select-prefix-cls}-selection__choice__content {
+ display: inline-block;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 100%;
+ transition: margin @duration @ease-in-out;
+ }
+
+ .@{tree-select-prefix-cls}-selection__choice__remove {
+ .iconfont-mixin();
+ color: #999;
+ line-height: 20px;
+ cursor: pointer;
+ display: inline-block;
+ font-weight: bold;
+ transition: all 0.3s @ease-in-out;
+ .iconfont-size-under-12px(8px);
+ position: absolute;
+ right: 4px;
+ padding: 0 0 0 8px;
+ &:hover {
+ color: #404040;
+ }
+ &:before {
+ content: "\e62d";
+ }
+ }
+ }
+
+ &-open {
+ .@{tree-select-prefix-cls}-arrow {
+ .ie-rotate(2);
+ -ms-transform: rotate(180deg);
+ &:before {
+ .rotate(180deg);
+ }
+ }
+ .@{tree-select-prefix-cls}-selection {
+ .active();
+ }
+ }
+
+ &-combobox {
+ .@{tree-select-prefix-cls}-arrow {
+ display: none;
+ }
+ .@{tree-select-prefix-cls}-search--inline {
+ height: 100%;
+ float: none;
+ }
+ .@{tree-select-prefix-cls}-search__field__placeholder {
+ left: 10px;
+ cursor: text;
+ }
+ .@{tree-select-prefix-cls}-search__field__wrap {
+ width: 100%;
+ height: 100%;
+ }
+ .@{tree-select-prefix-cls}-search__field {
+ padding: 0 10px;
+ width: 100%;
+ height: 100%;
+ position: relative;
+ z-index: 1;
+ }
+ .@{tree-select-prefix-cls}-selection__rendered {
+ padding: 0;
+ height: 100%;
+ }
+ }
+}
+
+.@{tree-select-prefix-cls}-dropdown {
+ &.slide-up-enter.slide-up-enter-active&-placement-bottomLeft,
+ &.slide-up-appear.slide-up-appear-active&-placement-bottomLeft {
+ animation-name: antSlideUpIn;
+ }
+
+ &.slide-up-enter.slide-up-enter-active&-placement-topLeft,
+ &.slide-up-appear.slide-up-appear-active&-placement-topLeft {
+ animation-name: antSlideDownIn;
+ }
+
+ &.slide-up-leave.slide-up-leave-active&-placement-bottomLeft {
+ animation-name: antSlideUpOut;
+ }
+
+ &.slide-up-leave.slide-up-leave-active&-placement-topLeft {
+ animation-name: antSlideDownOut;
+ }
+
+ &-hidden {
+ display: none;
+ }
+
+ background-color: white;
+ border: 1px solid #d9d9d9;
+ box-shadow: @box-shadow-base;
+ border-radius: @border-radius-base;
+ box-sizing: border-box;
+ z-index: 1070;
+ left: -9999px;
+ top: -9999px;
+ position: absolute;
+ outline: none;
+ overflow: hidden;
+ font-size: @font-size-base;
+
+ &-menu {
+ outline: none;
+ margin-bottom: 0;
+ padding-left: 0; // Override default ul/ol
+ list-style: none;
+ max-height: 250px;
+ overflow: auto;
+
+ &-item-group-list {
+ margin: 0;
+ padding: 0;
+
+ > .@{tree-select-prefix-cls}-dropdown-menu-item {
+ padding-left: 24px;
+ }
+ }
+
+ &-item-group-title {
+ color: #999;
+ line-height: 1.5;
+ padding: 8px 15px;
+ }
+
+ &-item {
+ position: relative;
+ display: block;
+ padding: 7px 15px;
+ font-weight: normal;
+ color: #666;
+ white-space: nowrap;
+ cursor: pointer;
+ overflow: hidden;
+ transition: background 0.3s ease;
+
+ &:first-child {
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ }
+ &:last-child {
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ }
+ &:hover,
+ &-active {
+ background-color: tint(@primary-color, 90%);
+ }
+
+ &-selected {
+ background-color: tint(@primary-color, 80%);
+ &:hover {
+ background-color: tint(@primary-color, 80%);
+ }
+ }
+
+ &-disabled {
+ color: #ccc;
+ cursor: not-allowed;
+
+ &:hover {
+ color: #ccc;
+ background-color: #fff;
+ cursor: not-allowed;
+ }
+ }
+
+ &-divider {
+ height: 1px;
+ margin: 1px 0;
+ overflow: hidden;
+ background-color: #e5e5e5;
+ line-height: 0;
+ }
+ }
+ }
+
+ &-container-open,
+ &-open {
+ .@{tree-select-prefix-cls}-dropdown {
+ display: block;
+ }
+ }
+
+ .@{tree-select-prefix-cls}-dropdown-search {
+ display: block;
+ padding: 4px;
+ .@{tree-select-prefix-cls}-search__field__placeholder {
+ left: 7px;
+ top: 5px;
+ }
+ .@{tree-select-prefix-cls}-search__field__wrap {
+ width: 100%;
+ }
+ .@{tree-select-prefix-cls}-search__field {
+ padding: 4px 7px;
+ width: 100%;
+ box-sizing: border-box;
+ border: 1px solid #d9d9d9;
+ border-radius: 4px;
+ outline: none;
+ }
+ &.@{tree-select-prefix-cls}-search--hide {
+ display: none;
+ }
+ }
+}