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; + } + } +}