UNPKG

22.7 kBJavaScriptView Raw
1import _extends from 'babel-runtime/helpers/extends';
2import _classCallCheck from 'babel-runtime/helpers/classCallCheck';
3import _possibleConstructorReturn from 'babel-runtime/helpers/possibleConstructorReturn';
4import _inherits from 'babel-runtime/helpers/inherits';
5
6var _class, _temp;
7
8import React, { Component } from 'react';
9import cx from 'classnames';
10import PropTypes from 'prop-types';
11import { polyfill } from 'react-lifecycles-compat';
12
13import Icon from '../../icon';
14import Button from '../../button';
15import zhCN from '../../locale/zh-cn';
16import { func, obj } from '../../util';
17import ConfigProvider from '../../config-provider';
18import TransferPanel from '../view/transfer-panel';
19
20var config = ConfigProvider.config;
21var bindCtx = func.bindCtx;
22var pickOthers = obj.pickOthers;
23
24
25var getLeftValue = function getLeftValue(dataSource, rightValue) {
26 return dataSource.map(function (item) {
27 return item.value;
28 }).filter(function (itemValue) {
29 return rightValue.indexOf(itemValue) === -1;
30 });
31};
32
33var filterCheckedValue = function filterCheckedValue(left, right, dataSource) {
34 var result = {
35 left: [],
36 right: []
37 };
38
39 if (left.length || right.length) {
40 var value = dataSource.map(function (item) {
41 return item.value;
42 });
43 value.forEach(function (itemValue) {
44 if (left.indexOf(itemValue) > -1) {
45 result.left.push(itemValue);
46 } else if (right.indexOf(itemValue) > -1) {
47 result.right.push(itemValue);
48 }
49 });
50 }
51
52 return result;
53};
54
55/**
56 * Transfer
57 */
58var Transfer = (_temp = _class = function (_Component) {
59 _inherits(Transfer, _Component);
60
61 Transfer.normalizeValue = function normalizeValue(value) {
62 if (value) {
63 if (Array.isArray(value)) {
64 return value;
65 }
66 /* istanbul ignore next */
67 return [value];
68 }
69
70 return [];
71 };
72
73 Transfer.getDerivedStateFromProps = function getDerivedStateFromProps(nextProps, prevState) {
74 var innerUpdate = prevState.innerUpdate,
75 value = prevState.value,
76 leftValue = prevState.leftValue;
77
78 if (innerUpdate) {
79 return {
80 innerUpdate: false,
81 value: value,
82 leftValue: leftValue
83 };
84 }
85 var st = {};
86
87 var newValue = void 0;
88 if ('value' in nextProps) {
89 var _value = Transfer.normalizeValue(nextProps.value);
90 st.value = _value;
91 newValue = _value;
92 } else {
93 /* istanbul ignore next */
94 newValue = prevState.value;
95 }
96 st.leftValue = getLeftValue(nextProps.dataSource, newValue);
97
98 var _filterCheckedValue = filterCheckedValue(prevState.leftCheckedValue, prevState.rightCheckedValue, nextProps.dataSource),
99 left = _filterCheckedValue.left,
100 right = _filterCheckedValue.right;
101
102 st.leftCheckedValue = left;
103 st.rightCheckedValue = right;
104
105 return st;
106 };
107
108 function Transfer(props, context) {
109 _classCallCheck(this, Transfer);
110
111 var _this = _possibleConstructorReturn(this, _Component.call(this, props, context));
112
113 var value = props.value,
114 defaultValue = props.defaultValue,
115 defaultLeftChecked = props.defaultLeftChecked,
116 defaultRightChecked = props.defaultRightChecked,
117 dataSource = props.dataSource,
118 rtl = props.rtl,
119 operations = props.operations;
120
121 if (operations.length === 0) {
122 operations.push(React.createElement(Icon, { rtl: rtl, type: 'arrow-right' }));
123 operations.push(React.createElement(Icon, { rtl: rtl, type: 'arrow-left' }));
124 }
125
126 var _filterCheckedValue2 = filterCheckedValue(Transfer.normalizeValue(defaultLeftChecked), Transfer.normalizeValue(defaultRightChecked), dataSource),
127 left = _filterCheckedValue2.left,
128 right = _filterCheckedValue2.right;
129
130 var stValue = Transfer.normalizeValue('value' in props ? value : defaultValue);
131 _this.state = {
132 value: stValue,
133 leftCheckedValue: left,
134 rightCheckedValue: right,
135 leftValue: getLeftValue(dataSource, stValue)
136 };
137
138 bindCtx(_this, ['handlePanelChange', 'handlePanelSort', 'handleMoveItem', 'handleSimpleMove', 'handleSimpleMoveAll']);
139 return _this;
140 }
141
142 Transfer.prototype.groupDatasource = function groupDatasource(value, itemValues, dataSource) {
143 return value.reduce(function (ret, itemValue) {
144 var index = itemValues.indexOf(itemValue);
145 if (index > -1) {
146 ret.push(dataSource[index]);
147 }
148 return ret;
149 }, []);
150 };
151
152 Transfer.prototype.handlePanelChange = function handlePanelChange(position, value) {
153 var _setState;
154
155 var _state = this.state,
156 leftCheckedValue = _state.leftCheckedValue,
157 rightCheckedValue = _state.rightCheckedValue;
158 var onSelect = this.props.onSelect;
159
160 var valuePropName = position === 'left' ? 'leftCheckedValue' : 'rightCheckedValue';
161 // inner state changed
162 this.setState((_setState = {
163 innerUpdate: true
164 }, _setState[valuePropName] = value, _setState));
165 onSelect && onSelect(position === 'left' ? value : leftCheckedValue, position === 'left' ? rightCheckedValue : value, position === 'left' ? 'source' : 'target');
166 };
167
168 Transfer.prototype.handlePanelSort = function handlePanelSort(position, dragValue, referenceValue, dragGap) {
169 var _this2 = this;
170
171 var _state2 = this.state,
172 value = _state2.value,
173 leftValue = _state2.leftValue;
174
175 var newValue = position === 'right' ? value : leftValue;
176 var currentIndex = newValue.indexOf(dragValue);
177 var referenceIndex = newValue.indexOf(referenceValue);
178 var expectIndex = dragGap === 'before' ? referenceIndex : referenceIndex + 1;
179 if (currentIndex === expectIndex) {
180 return;
181 }
182
183 newValue.splice(currentIndex, 1);
184 if (currentIndex < expectIndex) {
185 expectIndex = expectIndex - 1;
186 }
187 newValue.splice(expectIndex, 0, dragValue);
188 this.setState({
189 innerUpdate: true,
190 value: value,
191 leftValue: leftValue
192 }, function () {
193 _this2.props.onSort(newValue, position);
194 });
195 };
196
197 Transfer.prototype.handleMoveItem = function handleMoveItem(direction) {
198 var _st;
199
200 var rightValue = void 0;
201 var newLeftValue = void 0;
202 var movedValue = void 0;
203 var valuePropName = void 0;
204
205 var _state3 = this.state,
206 value = _state3.value,
207 leftValue = _state3.leftValue,
208 leftCheckedValue = _state3.leftCheckedValue,
209 rightCheckedValue = _state3.rightCheckedValue;
210
211
212 if (direction === 'right') {
213 rightValue = leftCheckedValue.concat(value);
214 newLeftValue = leftValue.filter(function (itemValue) {
215 return leftCheckedValue.indexOf(itemValue) === -1;
216 });
217 movedValue = leftCheckedValue;
218 valuePropName = 'leftCheckedValue';
219 } else {
220 rightValue = value.filter(function (itemValue) {
221 return rightCheckedValue.indexOf(itemValue) === -1;
222 });
223 newLeftValue = rightCheckedValue.concat(leftValue);
224 movedValue = rightCheckedValue;
225 valuePropName = 'rightCheckedValue';
226 }
227
228 var st = (_st = {}, _st[valuePropName] = [], _st);
229
230 this.setValueState(st, rightValue, newLeftValue, movedValue, direction);
231 };
232
233 Transfer.prototype.handleSimpleMove = function handleSimpleMove(direction, v) {
234 var rightValue = void 0;
235 var newLeftValue = void 0;
236
237 var _state4 = this.state,
238 value = _state4.value,
239 leftValue = _state4.leftValue;
240
241
242 if (direction === 'right') {
243 rightValue = [v].concat(value);
244 newLeftValue = leftValue.filter(function (itemValue) {
245 return itemValue !== v;
246 });
247 } else {
248 rightValue = value.filter(function (itemValue) {
249 return itemValue !== v;
250 });
251 newLeftValue = [v].concat(leftValue);
252 }
253
254 this.setValueState({}, rightValue, newLeftValue, [v], direction);
255 };
256
257 Transfer.prototype.handleSimpleMoveAll = function handleSimpleMoveAll(direction) {
258 var rightValue = void 0;
259 var newLeftValue = void 0;
260 var movedValue = void 0;
261
262 var dataSource = this.props.dataSource;
263 var _state5 = this.state,
264 value = _state5.value,
265 leftValue = _state5.leftValue;
266
267 var disabledValue = dataSource.reduce(function (ret, item) {
268 if (item.disabled) {
269 ret.push(item.value);
270 }
271
272 return ret;
273 }, []);
274
275 if (direction === 'right') {
276 movedValue = leftValue.filter(function (itemValue) {
277 return disabledValue.indexOf(itemValue) === -1;
278 });
279 rightValue = movedValue.concat(value);
280 newLeftValue = leftValue.filter(function (itemValue) {
281 return disabledValue.indexOf(itemValue) > -1;
282 });
283 } else {
284 movedValue = value.filter(function (itemValue) {
285 return disabledValue.indexOf(itemValue) === -1;
286 });
287 rightValue = value.filter(function (itemValue) {
288 return disabledValue.indexOf(itemValue) > -1;
289 });
290 newLeftValue = movedValue.concat(leftValue);
291 }
292
293 this.setValueState({}, rightValue, newLeftValue, movedValue, direction);
294 };
295
296 // eslint-disable-next-line max-params
297
298
299 Transfer.prototype.setValueState = function setValueState(st, rightValue, leftValue, movedValue, direction) {
300 var _this3 = this;
301
302 var dataSource = this.props.dataSource;
303
304 var callback = function callback() {
305 if ('onChange' in _this3.props) {
306 var itemValues = dataSource.map(function (item) {
307 return item.value;
308 });
309 var rightData = _this3.groupDatasource(rightValue, itemValues, dataSource);
310 var leftData = _this3.groupDatasource(leftValue, itemValues, dataSource);
311 var movedData = _this3.groupDatasource(movedValue, itemValues, dataSource);
312
313 _this3.props.onChange(rightValue, rightData, {
314 leftValue: leftValue,
315 leftData: leftData,
316 movedValue: movedValue,
317 movedData: movedData,
318 direction: direction
319 });
320 }
321 };
322
323 if (!('value' in this.props)) {
324 st.value = rightValue;
325 st.leftValue = leftValue;
326 }
327
328 if (Object.keys(st).length) {
329 this.setState(st, callback);
330 } else {
331 // eslint-disable-next-line callback-return
332 callback();
333 }
334 };
335
336 Transfer.prototype.renderCenter = function renderCenter() {
337 var _props = this.props,
338 prefix = _props.prefix,
339 mode = _props.mode,
340 operations = _props.operations,
341 disabled = _props.disabled,
342 leftDisabled = _props.leftDisabled,
343 rightDisabled = _props.rightDisabled,
344 locale = _props.locale;
345 var _state6 = this.state,
346 leftCheckedValue = _state6.leftCheckedValue,
347 rightCheckedValue = _state6.rightCheckedValue;
348
349 return React.createElement(
350 'div',
351 { className: prefix + 'transfer-operations' },
352 mode === 'simple' ? React.createElement(Icon, { className: prefix + 'transfer-move', size: 'large', type: 'switch' }) : [React.createElement(
353 Button,
354 {
355 'aria-label': locale.moveToRight,
356 key: 'l2r',
357 className: prefix + 'transfer-operation',
358 type: leftCheckedValue.length ? 'primary' : 'normal',
359 disabled: leftDisabled || disabled || !leftCheckedValue.length,
360 onClick: this.handleMoveItem.bind(this, 'right')
361 },
362 operations[0]
363 ), React.createElement(
364 Button,
365 {
366 'aria-label': locale.moveToLeft,
367 key: 'r2l',
368 className: prefix + 'transfer-operation',
369 type: rightCheckedValue.length ? 'primary' : 'normal',
370 disabled: rightDisabled || disabled || !rightCheckedValue.length,
371 onClick: this.handleMoveItem.bind(this, 'left')
372 },
373 operations[1]
374 )]
375 );
376 };
377
378 Transfer.prototype.render = function render() {
379 var _props2 = this.props,
380 prefix = _props2.prefix,
381 mode = _props2.mode,
382 disabled = _props2.disabled,
383 className = _props2.className,
384 dataSource = _props2.dataSource,
385 locale = _props2.locale,
386 _props2$showSearch = _props2.showSearch,
387 showSearch = _props2$showSearch === undefined ? false : _props2$showSearch,
388 _props2$searchProps = _props2.searchProps,
389 searchProps = _props2$searchProps === undefined ? {} : _props2$searchProps,
390 filter = _props2.filter,
391 onSearch = _props2.onSearch,
392 leftDisabled = _props2.leftDisabled,
393 rightDisabled = _props2.rightDisabled,
394 searchPlaceholder = _props2.searchPlaceholder,
395 notFoundContent = _props2.notFoundContent,
396 titles = _props2.titles,
397 listClassName = _props2.listClassName,
398 listStyle = _props2.listStyle,
399 itemRender = _props2.itemRender,
400 sortable = _props2.sortable,
401 useVirtual = _props2.useVirtual,
402 rtl = _props2.rtl,
403 id = _props2.id,
404 children = _props2.children,
405 showCheckAll = _props2.showCheckAll;
406 var _state7 = this.state,
407 value = _state7.value,
408 leftValue = _state7.leftValue,
409 leftCheckedValue = _state7.leftCheckedValue,
410 rightCheckedValue = _state7.rightCheckedValue;
411
412 var itemValues = dataSource.map(function (item) {
413 return item.value;
414 });
415 var leftDatasource = this.groupDatasource(leftValue, itemValues, dataSource);
416 var rightDatasource = this.groupDatasource(value, itemValues, dataSource);
417 var panelProps = {
418 prefix: prefix,
419 mode: mode,
420 locale: locale,
421 filter: filter,
422 onSearch: onSearch,
423 searchPlaceholder: searchPlaceholder,
424 listClassName: listClassName,
425 listStyle: listStyle,
426 itemRender: itemRender,
427 onMove: this.handleSimpleMove,
428 onMoveAll: this.handleSimpleMoveAll,
429 onChange: this.handlePanelChange,
430 sortable: sortable,
431 useVirtual: useVirtual,
432 onSort: this.handlePanelSort,
433 baseId: id,
434 customerList: children,
435 showCheckAll: showCheckAll
436 };
437 var others = pickOthers(Object.keys(Transfer.propTypes), this.props);
438
439 if (rtl) {
440 others.dir = 'rtl';
441 }
442 var _showSearch = Array.isArray(showSearch) ? showSearch : [showSearch, showSearch];
443 var _searchProps = Array.isArray(searchProps) ? searchProps : [searchProps, searchProps];
444 var _notFoundContent = Array.isArray(notFoundContent) ? notFoundContent : [notFoundContent, notFoundContent];
445 return React.createElement(
446 'div',
447 _extends({ className: cx(prefix + 'transfer', className), id: id }, others),
448 React.createElement(TransferPanel, _extends({}, panelProps, {
449 position: 'left',
450 dataSource: leftDatasource,
451 disabled: leftDisabled || disabled,
452 value: leftCheckedValue,
453 showSearch: _showSearch[0],
454 searchProps: _searchProps[0],
455 notFoundContent: _notFoundContent[0],
456 title: titles[0]
457 })),
458 this.renderCenter(),
459 React.createElement(TransferPanel, _extends({}, panelProps, {
460 position: 'right',
461 dataSource: rightDatasource,
462 disabled: rightDisabled || disabled,
463 value: rightCheckedValue,
464 showSearch: _showSearch[1],
465 searchProps: _searchProps[1],
466 notFoundContent: _notFoundContent[1],
467 title: titles[1]
468 }))
469 );
470 };
471
472 return Transfer;
473}(Component), _class.contextTypes = {
474 prefix: PropTypes.string
475}, _class.propTypes = _extends({}, ConfigProvider.propTypes, {
476 prefix: PropTypes.string,
477 pure: PropTypes.bool,
478 rtl: PropTypes.bool,
479 className: PropTypes.string,
480 /**
481 * 移动选项模式
482 */
483 mode: PropTypes.oneOf(['normal', 'simple']),
484 /**
485 * 数据源
486 */
487 dataSource: PropTypes.arrayOf(PropTypes.object),
488 /**
489 * (用于受控)当前值
490 */
491 value: PropTypes.arrayOf(PropTypes.string),
492 /**
493 * (用于非受控)初始值
494 */
495 defaultValue: PropTypes.arrayOf(PropTypes.string),
496 /**
497 * 值发生改变的时候触发的回调函数
498 * @param {Array} value 右面板值
499 * @param {Array} data 右面板数据
500 * @param {Object} extra 额外参数
501 * @param {Array} extra.leftValue 左面板值
502 * @param {Array} extra.leftData 左面板数据
503 * @param {Array} extra.movedValue 发生移动的值
504 * @param {Object} extra.movedData 发生移动的数据
505 * @param {String} extra.direction 移动的方向,值为'left'或'right'
506 */
507 onChange: PropTypes.func,
508 /**
509 * Item 被选中的时候触发的回调函数
510 * @param {Array} sourceSelectedValue 源面板选中的 Item 列表
511 * @param {Array} targetSelectedValue 目标面板选中的 Item 列表
512 * @param {String} trigger 触发面板,值为'source'或'target'
513 */
514 onSelect: PropTypes.func,
515 /**
516 * 是否禁用
517 */
518 disabled: PropTypes.bool,
519 /**
520 * 是否禁用左侧面板
521 */
522 leftDisabled: PropTypes.bool,
523 /**
524 * 是否禁用右侧面板
525 */
526 rightDisabled: PropTypes.bool,
527 /**
528 * 列表项渲染函数
529 * @param {Object} data 数据
530 * @return {ReactNode} 列表项内容
531 */
532 itemRender: PropTypes.func,
533 /**
534 * 自定义搜索函数
535 * @param {String} searchedValue 搜索的内容
536 * @param {Object} data 数据
537 * @return {Boolean} 是否匹配到
538 * @default 根据 label 属性匹配
539 */
540 filter: PropTypes.func,
541 /**
542 * 搜索框输入时触发的回调函数
543 * @param {String} searchedValue 搜索的内容
544 * @param {String} position 搜索面板的位置
545 */
546 onSearch: PropTypes.func,
547 /**
548 * 搜索框占位符
549 */
550 searchPlaceholder: PropTypes.string,
551 /**
552 * 左右面板是否显示搜索框
553 */
554 showSearch: PropTypes.oneOfType([PropTypes.bool, PropTypes.arrayOf(PropTypes.bool)]),
555 /**
556 * 左右面板搜索框配置项,同 Search 组件 props
557 */
558 searchProps: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object)]),
559 /**
560 * 列表为空显示内容
561 */
562 notFoundContent: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
563 /**
564 * 左右面板标题
565 */
566 titles: PropTypes.arrayOf(PropTypes.node),
567 /**
568 * 向右向左移动按钮显示内容
569 * @default [<Icon type="arrow-right" />, <Icon type="arrow-left" />]
570 */
571 operations: PropTypes.arrayOf(PropTypes.node),
572 /**
573 * 左面板默认选中值
574 */
575 defaultLeftChecked: PropTypes.arrayOf(PropTypes.string),
576 /**
577 * 右面板默认选中值
578 */
579 defaultRightChecked: PropTypes.arrayOf(PropTypes.string),
580 /**
581 * 左右面板列表自定义样式类名
582 */
583 listClassName: PropTypes.string,
584 /**
585 * 左右面板列表自定义样式对象
586 */
587 listStyle: PropTypes.object,
588 /**
589 * 是否允许拖拽排序
590 */
591 sortable: PropTypes.bool,
592 /**
593 * 拖拽排序时触发的回调函数
594 * @param {Array} value 排序后的值
595 * @param {String} position 拖拽的面板位置,值为:left 或 right
596 */
597 onSort: PropTypes.func,
598 /**
599 * 自定义国际化文案对象
600 */
601 locale: PropTypes.object,
602 /**
603 * 请设置 id 以保证transfer的可访问性
604 */
605 id: PropTypes.string,
606 /**
607 * 接收 children 自定义渲染列表
608 */
609 children: PropTypes.func,
610 /**
611 * 是否开启虚拟滚动
612 */
613 useVirtual: PropTypes.bool,
614 /**
615 * 是否显示底部全选 checkbox
616 */
617 showCheckAll: PropTypes.bool
618}), _class.defaultProps = {
619 prefix: 'next-',
620 pure: false,
621 mode: 'normal',
622 dataSource: [],
623 defaultValue: [],
624 disabled: false,
625 leftDisabled: false,
626 rightDisabled: false,
627 showCheckAll: true,
628 itemRender: function itemRender(data) {
629 return data.label;
630 },
631 showSearch: false,
632 filter: function filter(searchedValue, data) {
633 var labelString = '';
634 var loop = function loop(arg) {
635 if (React.isValidElement(arg) && arg.props.children) {
636 React.Children.forEach(arg.props.children, loop);
637 } else if (typeof arg === 'string') {
638 labelString += arg;
639 }
640 };
641 loop(data.label);
642
643 return labelString.length >= searchedValue.length && labelString.indexOf(searchedValue) > -1;
644 },
645 onSearch: function onSearch() {},
646 notFoundContent: 'Not Found',
647 titles: [],
648 operations: [],
649 defaultLeftChecked: [],
650 defaultRightChecked: [],
651 sortable: false,
652 onSort: function onSort() {},
653 locale: zhCN.Transfer
654}, _temp);
655Transfer.displayName = 'Transfer';
656
657
658export default config(polyfill(Transfer));
\No newline at end of file