diff --git a/docs/search/index.en-us.md b/docs/search/index.en-us.md index 2670aff0e2..ebe458f5f3 100644 --- a/docs/search/index.en-us.md +++ b/docs/search/index.en-us.md @@ -40,3 +40,4 @@ search data in forms or pages. | popupContent | custom popup menu | ReactNode | - | | visible | popupContent is displayed | Boolean | - | | hasClear | show clear text button | Boolean | false | +| disabled | disabled or not | Boolean | false | diff --git a/docs/search/index.md b/docs/search/index.md index 4ec001bdbb..f82cf8fc7b 100644 --- a/docs/search/index.md +++ b/docs/search/index.md @@ -41,3 +41,4 @@ | popupContent | 自定义渲染的的下拉框 | ReactNode | - | | visible | 自定义渲染的的下拉框 | Boolean | - | | hasClear | 是否显示清除按钮 | Boolean | false | +| disabled | 是否禁用 | Boolean | false | diff --git a/docs/slider/demo/slick-goto.md b/docs/slider/demo/slick-goto.md index 621b9c8257..c054354b09 100644 --- a/docs/slider/demo/slick-goto.md +++ b/docs/slider/demo/slick-goto.md @@ -26,7 +26,7 @@ class SlickGoTo extends React.Component { constructor(props) { super(props); this.state = { - index: 0, // The initial value here need to be set to 0 for `activeIndex`. If you want the initial as 0 , you can use the `defaultIndex` property to set. + index: 0, // The initial value here need to be set to 0 for `activeIndex`. If you want the initial as 0 , you can use the `defaultActiveIndex` property to set. }; this.changeHandler = this.changeHandler.bind(this); } diff --git a/docs/table/demo/style.md b/docs/table/demo/style.md index 60a477b3fb..ab27500792 100644 --- a/docs/table/demo/style.md +++ b/docs/table/demo/style.md @@ -72,8 +72,8 @@ class App extends React.Component { - - + +
diff --git a/docs/table/index.en-us.md b/docs/table/index.en-us.md index 1b4bed4979..37c575cce3 100644 --- a/docs/table/index.en-us.md +++ b/docs/table/index.en-us.md @@ -131,6 +131,7 @@ ReactDOM.render( | sortable | whether to support sorting | Boolean | - | | width | width of column,width needs to be set in lock style | Number/String | - | | align | alignment of cell

**options**:
'left', 'center', 'right' | Enum | - | +| alignHeader | alignment of header cell, value of align by default

**options**:
'left', 'center', 'right' | Enum | - | | filters | generates a title filter menu in the format `[{label:'xxx', value:'xxx'}]` | Array<Object> | - | | filterMode | whether the filtering mode is single or multiple selection

**options**:
'single', 'multiple' | Enum | 'multiple' | | lock | whether the lock column is supported, the options are `left`, `right`, `true` | Boolean/String | - | diff --git a/docs/table/index.md b/docs/table/index.md index fe2c64d0d2..9c5bf7410e 100644 --- a/docs/table/index.md +++ b/docs/table/index.md @@ -132,18 +132,19 @@ ReactDOM.render( ### Table.Column -| 参数 | 说明 | 类型 | 默认值 | -| ---------- | --------------------------------------------------------------------------------------------------- | ------------------------------- | ---------------- | -| dataIndex | 指定列对应的字段,支持`a.b`形式的快速取值 | String | - | -| cell | 行渲染的逻辑
value, rowIndex, record, context四个属性只可读不可被更改
Function(value, index, record) => Element | ReactElement/ReactNode/Function | (value) => value | -| title | 表头显示的内容
value, rowIndex, record, context四个属性只可读不可被更改 | ReactElement/ReactNode/Function | - | -| sortable | 是否支持排序 | Boolean | - | -| width | 列宽,注意在锁列的情况下一定需要配置宽度 | Number/String | - | -| align | 单元格的对齐方式

**可选值**:
'left', 'center', 'right' | Enum | - | -| filters | 生成标题过滤的菜单, 格式为`[{label:'xxx', value:'xxx'}]` | Array<Object> | - | -| filterMode | 过滤的模式是单选还是多选

**可选值**:
'single', 'multiple' | Enum | 'multiple' | -| lock | 是否支持锁列,可选值为`left`,`right`, `true` | Boolean/String | - | -| resizable | 是否支持列宽调整, 当该值设为true,table的布局方式会修改为fixed. | Boolean | false | +| 参数 | 说明 | 类型 | 默认值 | +| ----------- | --------------------------------------------------------------------------------------------------- | ------------------------------- | ---------------- | +| dataIndex | 指定列对应的字段,支持`a.b`形式的快速取值 | String | - | +| cell | 行渲染的逻辑
value, rowIndex, record, context四个属性只可读不可被更改
Function(value, index, record) => Element | ReactElement/ReactNode/Function | (value) => value | +| title | 表头显示的内容
value, rowIndex, record, context四个属性只可读不可被更改 | ReactElement/ReactNode/Function | - | +| sortable | 是否支持排序 | Boolean | - | +| width | 列宽,注意在锁列的情况下一定需要配置宽度 | Number/String | - | +| align | 单元格的对齐方式

**可选值**:
'left', 'center', 'right' | Enum | - | +| alignHeader | 单元格标题的对齐方式, 不配置默认读取align值

**可选值**:
'left', 'center', 'right' | Enum | - | +| filters | 生成标题过滤的菜单, 格式为`[{label:'xxx', value:'xxx'}]` | Array<Object> | - | +| filterMode | 过滤的模式是单选还是多选

**可选值**:
'single', 'multiple' | Enum | 'multiple' | +| lock | 是否支持锁列,可选值为`left`,`right`, `true` | Boolean/String | - | +| resizable | 是否支持列宽调整, 当该值设为true,table的布局方式会修改为fixed. | Boolean | false | ### Table.ColumnGroup diff --git a/scripts/server/server.js b/scripts/server/server.js index 21aefbdd29..1329fefbd4 100644 --- a/scripts/server/server.js +++ b/scripts/server/server.js @@ -77,7 +77,7 @@ function run(port) { }); const url = `http://${host}:${port}/${componentName}`; - logger.warn(`Start server, listen to ${url}.`); + logger.warn(`Start server, listen to ${url}`); const server = new WebpackDevServer(compiler, { disableHostCheck: true, diff --git a/src/dialog/inner.jsx b/src/dialog/inner.jsx index dfe0ce14d3..4af7226ce4 100644 --- a/src/dialog/inner.jsx +++ b/src/dialog/inner.jsx @@ -101,11 +101,11 @@ export default class Inner extends Component { } renderCloseLink() { - const { prefix, closeable, onClose } = this.props; + const { prefix, closeable, onClose, locale } = this.props; if (closeable) { return ( - diff --git a/src/locale/en-us.js b/src/locale/en-us.js index acced0100a..3dd8025b85 100644 --- a/src/locale/en-us.js +++ b/src/locale/en-us.js @@ -39,6 +39,7 @@ export default { second: 'S' }, Dialog: { + close: 'Close', ok: 'OK', cancel: 'Cancel' }, diff --git a/src/locale/ja-jp.js b/src/locale/ja-jp.js index ee0bbe0f73..86a9fbfba5 100644 --- a/src/locale/ja-jp.js +++ b/src/locale/ja-jp.js @@ -39,6 +39,7 @@ export default { second: '秒' }, Dialog: { + close: '閉鎖する', ok: '確認', cancel: 'キャンセル' }, diff --git a/src/locale/zh-cn.js b/src/locale/zh-cn.js index 8f5f067cd4..70747363ce 100644 --- a/src/locale/zh-cn.js +++ b/src/locale/zh-cn.js @@ -39,6 +39,7 @@ export default { second: '秒' }, Dialog: { + close: '关闭', ok: '确认', cancel: '取消' }, diff --git a/src/locale/zh-tw.js b/src/locale/zh-tw.js index 5dde2ee664..957fd82600 100644 --- a/src/locale/zh-tw.js +++ b/src/locale/zh-tw.js @@ -39,6 +39,7 @@ export default { second: '秒' }, Dialog: { + close: '關閉', ok: '確認', cancel: '取消' }, diff --git a/src/search/Search.jsx b/src/search/Search.jsx index 372146ba03..5228e65476 100644 --- a/src/search/Search.jsx +++ b/src/search/Search.jsx @@ -109,8 +109,13 @@ class Search extends React.Component { * 是否显示清除按钮 */ hasClear: PropTypes.bool, + /** + * 是否禁用 + */ + disabled: PropTypes.bool, locale: PropTypes.object, rtl: PropTypes.bool, + }; static defaultProps = { @@ -125,6 +130,7 @@ class Search extends React.Component { onSearch: func.noop, onFilterChange: func.noop, hasClear: false, + disabled: false, }; constructor(props) { @@ -159,6 +165,9 @@ class Search extends React.Component { }; onSearch = () => { + if (this.props.disabled) { + return; + } this.props.onSearch(this.state.value, this.state.filterValue); }; @@ -171,6 +180,9 @@ class Search extends React.Component { }; onKeyDown = (e) => { + if (this.props.disabled) { + return; + } if (e.keyCode !== KEYCODE.ENTER) { return; } @@ -178,7 +190,7 @@ class Search extends React.Component { } render() { const { - shape, filter, hasIcon, + shape, filter, hasIcon, disabled, placeholder, type, className, style, size, prefix, searchText, dataSource, filterProps, buttonProps, @@ -200,13 +212,13 @@ class Search extends React.Component { [`${prefix}search-icon`]: true, [buttonProps.className]: !!buttonProps.className }); - searchIcon = ; + searchIcon = ; } else { const cls = classNames({ [`${prefix}search-btn`]: true, [buttonProps.className]: !!buttonProps.className }); - searchBtn = (); @@ -219,6 +231,7 @@ class Search extends React.Component { hasBorder={false} dataSource={filter} size={size} + disabled={disabled} value={this.state.filterValue} onChange={this.onFilterChange} /> @@ -246,6 +259,7 @@ class Search extends React.Component { value={this.state.value} onChange={this.onChange} popupContent={popupContent} + disabled={disabled} /> ); diff --git a/src/select/select.jsx b/src/select/select.jsx index ae87c654d2..876298936c 100644 --- a/src/select/select.jsx +++ b/src/select/select.jsx @@ -172,7 +172,7 @@ class Select extends Base { searchValue: 'searchValue' in props ? props.searchValue : '' }); - // For cache choosen value + // because dataSource maybe updated while select a item, so we should cache choosen value's item this.valueDataSource = { valueDS: [], // [{value,label}] mapValueDS: {} // {value: {value,label}} @@ -226,19 +226,12 @@ class Select extends Base { if ('value' in nextProps) { // under controll - this.valueDataSource = getValueDataSource( - nextProps.value, - this.valueDataSource.mapValueDS, - this.dataStore.getMapDS() - ); + this.valueDataSource = getValueDataSource(nextProps.value, this.valueDataSource.mapValueDS, this.dataStore.getMapDS()); } else if ('defaultValue' in nextProps && + nextProps.defaultValue === this.valueDataSource.value && (nextProps.children !== this.props.children || nextProps.dataSource !== this.props.dataSource)) { - //has defaultValue and dataSource changed - this.valueDataSource = getValueDataSource( - nextProps.defaultValue, - this.valueDataSource.mapValueDS, - this.dataStore.getMapDS() - ); + //has defaultValue and value not changed and dataSource changed + this.valueDataSource = getValueDataSource(nextProps.defaultValue, this.valueDataSource.mapValueDS, this.dataStore.getMapDS()); } } @@ -347,7 +340,7 @@ class Select extends Base { const { cacheValue, mode, hiddenSelected } = this.props; - // 非受控更新缓存map + // cache those value maybe not exists in dataSource if (cacheValue || mode === 'tag') { this.valueDataSource = itemObj; } @@ -589,7 +582,11 @@ class Select extends Base { // get detail value if (!this.useDetailValue()) { - value = this.valueDataSource.valueDS; + if (value === this.valueDataSource.value) { + value = this.valueDataSource.valueDS; + } else { + value = getValueDataSource(value, this.valueDataSource.mapValueDS, this.dataStore.getMapDS()).valueDS; + } } if (mode === 'single') { @@ -641,7 +638,7 @@ class Select extends Base { // because of can not close Popup by click Input while hasSearch. // so when Popup open and hasSearch, we should close Popup intentionally - this.state.visible && this.hasSearch() && this.setVisible(!this.state.visible); + this.state.visible && this.hasSearch() && this.setVisible(false); } handleClear = e => { diff --git a/src/tab/main.scss b/src/tab/main.scss index c89c448fa0..120b9aba93 100644 --- a/src/tab/main.scss +++ b/src/tab/main.scss @@ -390,6 +390,36 @@ } } } + + &-pure > #{$tab-prefix}-bar { + position: relative; + #{$tab-prefix}-nav-extra { + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + } + } + + &-capsule > #{$tab-prefix}-bar { + position: relative; + #{$tab-prefix}-nav-extra { + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + } + } + + &-text > #{$tab-prefix}-bar { + position: relative; + #{$tab-prefix}-nav-extra { + position: absolute; + top: 50%; + right: 0; + transform: translateY(-50%); + } + } } @import "./rtl.scss"; diff --git a/src/tab/rtl.scss b/src/tab/rtl.scss index 2cc589ecf7..b583674425 100644 --- a/src/tab/rtl.scss +++ b/src/tab/rtl.scss @@ -14,4 +14,11 @@ left: 0; } } + + & > #{$tab-prefix}-bar { + #{$tab-prefix}-nav-extra { + right: auto; + left: 0; + } + } } diff --git a/src/table/base/cell.jsx b/src/table/base/cell.jsx index 8a49124fcf..4f0ed1094a 100644 --- a/src/table/base/cell.jsx +++ b/src/table/base/cell.jsx @@ -49,7 +49,7 @@ export default class Cell extends React.Component { render() { /* eslint-disable no-unused-vars */ const {prefix, className, cell, value, resizable, colIndex, rowIndex, record, context, align, style = {}, component: Tag, - children, title, width, innerStyle, primaryKey, __normalized, filterMode, filters, sortable, lock, pure, ...others} = this.props; + children, title, width, innerStyle, primaryKey, __normalized, filterMode, filters, sortable, lock, pure, locale, ...others} = this.props; const tagStyle = {...style}; const cellProps = {value, index: rowIndex, record, context}; let content = cell; diff --git a/src/table/base/header.jsx b/src/table/base/header.jsx index 10e9d822a3..e9990764cb 100644 --- a/src/table/base/header.jsx +++ b/src/table/base/header.jsx @@ -55,7 +55,7 @@ export default class Header extends React.Component { const header = columns.map((cols, index) => { const col = cols.map((col, j) => { /* eslint-disable no-unused-vars, prefer-const */ - let { title, colSpan, sortable, resizable, dataIndex, filters, filterMode, width, align, className, __normalized, lock, ...others } = col; + let { title, colSpan, sortable, resizable, dataIndex, filters, filterMode, width, align, alignHeader, className, __normalized, lock, ...others } = col; className = classnames({ [`${prefix}table-header-node`]: true, @@ -95,7 +95,7 @@ export default class Header extends React.Component { pure={pure} cell={title} component="th" - align={align} + align={alignHeader ? alignHeader : align} className={className} ref={this.getCellRef.bind(this, index, j)} type="header"> diff --git a/src/table/base/row.jsx b/src/table/base/row.jsx index 6406187004..97d01a863b 100644 --- a/src/table/base/row.jsx +++ b/src/table/base/row.jsx @@ -85,7 +85,8 @@ export default class Row extends React.Component { const { Cell, columns, getCellProps, cellRef, prefix, rowIndex, primaryKey, pure, locale } = this.props; const { lockType } = this.context; return columns.map((child, colIndex) => { - const { dataIndex, align, width, ...others } = child; + /* eslint-disable no-unused-vars, prefer-const */ + const { dataIndex, align, alignHeader, width, ...others } = child; const value = fetchDataByPath(record, dataIndex); const attrs = getCellProps(rowIndex, colIndex, dataIndex, record) || {}; @@ -140,7 +141,7 @@ export default class Row extends React.Component { render() { /* eslint-disable no-unused-vars*/ - const { prefix, className, onClick, onMouseEnter, onMouseLeave, columns, Cell, getCellProps, rowIndex, record, children, primaryKey, cellRef, colGroup, pure, ...others } = this.props; + const { prefix, className, onClick, onMouseEnter, onMouseLeave, columns, Cell, getCellProps, rowIndex, record, children, primaryKey, cellRef, colGroup, pure, locale, ...others } = this.props; const cls = classnames({ [`${prefix}table-row`]: true, [className]: className diff --git a/src/table/column.jsx b/src/table/column.jsx index b377468cc0..65bb688e89 100644 --- a/src/table/column.jsx +++ b/src/table/column.jsx @@ -35,6 +35,10 @@ export default class Column extends React.Component { * 单元格的对齐方式 */ align: PropTypes.oneOf(['left', 'center', 'right']), + /** + * 单元格标题的对齐方式, 不配置默认读取align值 + */ + alignHeader: PropTypes.oneOf(['left', 'center', 'right']), /** * 生成标题过滤的菜单, 格式为`[{label:'xxx', value:'xxx'}]` */ diff --git a/src/table/list/row.jsx b/src/table/list/row.jsx index 4a07a9e121..a5350d245e 100644 --- a/src/table/list/row.jsx +++ b/src/table/list/row.jsx @@ -16,7 +16,7 @@ export default class GroupListRow extends Row { render() { /* eslint-disable no-unused-vars*/ - const { prefix, className, onClick, onMouseEnter, onMouseLeave, columns, Cell, rowIndex, record, children, primaryKey, colGroup, cellRef, getCellProps, ...others } = this.props; + const { prefix, className, onClick, onMouseEnter, onMouseLeave, columns, Cell, rowIndex, record, children, primaryKey, colGroup, cellRef, getCellProps, locale, ...others } = this.props; const cls = classnames({ [`${prefix}table-row`]: true, [className]: className diff --git a/test/collapse/a11y-spec.js b/test/collapse/a11y-spec.js new file mode 100644 index 0000000000..51f54819ef --- /dev/null +++ b/test/collapse/a11y-spec.js @@ -0,0 +1,50 @@ +import React from 'react'; +import Enzyme from 'enzyme'; +import Adapter from 'enzyme-adapter-react-16'; +import Collapse from '../../src/collapse/index'; +import '../../src/collapse/style'; +import a11y from '../util/a11y'; + +Enzyme.configure({ adapter: new Adapter() }); + + +const Panel = Collapse.Panel; + +describe('Collapse A11y', () => { + let wrapper; + + afterEach(() => { + if (wrapper) { + wrapper.unmount(); + wrapper = null; + } + a11y.afterEach(); + }); + + it('should not have any violations for children rendered component', (done) => { + wrapper = a11y.test( + + Pannel Content + + + Pannel Content + +
others
+
, done); + }); + + it('should not have any violations for data rendered component', (done) => { + + let list = [ + { + title: '', + content: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.' + }, + { + title: 'Well, hello there', + content: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet. Lorem ipsum dolor sit amet, consetetur sadipscing elitr, sed diam nonumy eirmod tempor invidunt ut labore et dolore magna aliquyam erat, sed diam voluptua. At vero eos et accusam et justo duo dolores et ea rebum. Stet clita kasd gubergren, no sea takimata sanctus est Lorem ipsum dolor sit amet.' + } + ]; + wrapper = a11y.test(, done, { incomplete: true }); + }); +}); diff --git a/test/collapse/index-spec.js b/test/collapse/index-spec.js index 1b65df75dd..1828a6f61f 100644 --- a/test/collapse/index-spec.js +++ b/test/collapse/index-spec.js @@ -1,5 +1,4 @@ import React from 'react'; -import ReactDOM from 'react-dom'; import Enzyme, { mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import assert from 'power-assert'; diff --git a/test/search/index-spec.js b/test/search/index-spec.js index 14c5d3f1c3..36389aec30 100644 --- a/test/search/index-spec.js +++ b/test/search/index-spec.js @@ -180,7 +180,6 @@ describe('Search', () => { wrapper = mount(); assert(wrapper.find('.next-select-values em').text() === FILTER_VALUE); wrapper.find('button').simulate('click'); - }); it('act in controlled way', (done) => { @@ -216,6 +215,32 @@ describe('Search', () => { wrapper.setProps({ value: VALUE, filterValue: FILTER_VALUE }); wrapper.find('button').simulate('click'); }); + it('should support disabled', () => { + const onSearch = sinon.spy(); + const onChange = sinon.spy(); + wrapper = mount(); + wrapper.find('.next-icon').simulate('click'); + assert(onSearch.notCalled); + wrapper.find('input').simulate('change', { target: { value: '20' } }); + assert(onChange.notCalled); + }); + it('should support enter key', () => { + const onSearch = sinon.spy(); + wrapper = mount(); + // 支持enter + wrapper.find('button').simulate('keyDown', {keyCode: 13}); + assert(onSearch.calledOnce); + // 不支持非enter + wrapper.find('button').simulate('keyDown', {keyCode: 14}); + assert(onSearch.calledOnce); + }); + it('should support disable enter key', () => { + const onSearch = sinon.spy(); + wrapper = mount(); + // 支持enter + wrapper.find('.next-icon').simulate('keyDown', {keyCode: 13}); + assert(onSearch.notCalled); + }); }); diff --git a/test/select/index-spec.js b/test/select/index-spec.js index 8afd47eb0d..54395aebeb 100644 --- a/test/select/index-spec.js +++ b/test/select/index-spec.js @@ -83,6 +83,42 @@ describe('Select', () => { assert(wrapper.find('.next-select em').text() === 'TT2'); }); + it('should change display text while choose item and change dataSource', () => { + const dataSource = ['abc', 'bbb']; + class App extends React.Component { + render() { + return ( +