zent
Version:
一套前端设计语言和基于React的实现
550 lines (457 loc) • 17.3 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof2 = require('babel-runtime/helpers/typeof');
var _typeof3 = _interopRequireDefault(_typeof2);
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn');
var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2);
var _inherits2 = require('babel-runtime/helpers/inherits');
var _inherits3 = _interopRequireDefault(_inherits2);
var _react = require('react');
var _react2 = _interopRequireDefault(_react);
var _omit = require('lodash/omit');
var _omit2 = _interopRequireDefault(_omit);
var _isEqual = require('lodash/isEqual');
var _isEqual2 = _interopRequireDefault(_isEqual);
var _isArray = require('lodash/isArray');
var _isArray2 = _interopRequireDefault(_isArray);
var _noop = require('lodash/noop');
var _noop2 = _interopRequireDefault(_noop);
var _cloneDeep = require('lodash/cloneDeep');
var _cloneDeep2 = _interopRequireDefault(_cloneDeep);
var _propTypes = require('prop-types');
var _propTypes2 = _interopRequireDefault(_propTypes);
var _popover = require('../popover');
var _popover2 = _interopRequireDefault(_popover);
var _trigger = require('./trigger');
var _trigger2 = _interopRequireDefault(_trigger);
var _Popup = require('./Popup');
var _Popup2 = _interopRequireDefault(_Popup);
var _SimpleTrigger = require('./trigger/SimpleTrigger');
var _SimpleTrigger2 = _interopRequireDefault(_SimpleTrigger);
var _SelectTrigger = require('./trigger/SelectTrigger');
var _SelectTrigger2 = _interopRequireDefault(_SelectTrigger);
var _InputTrigger = require('./trigger/InputTrigger');
var _InputTrigger2 = _interopRequireDefault(_InputTrigger);
var _TagsTrigger = require('./trigger/TagsTrigger');
var _TagsTrigger2 = _interopRequireDefault(_TagsTrigger);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
/**
* Select
*/
var PopoverClickTrigger = function (_Popover$Trigger$Clic) {
(0, _inherits3['default'])(PopoverClickTrigger, _Popover$Trigger$Clic);
function PopoverClickTrigger() {
(0, _classCallCheck3['default'])(this, PopoverClickTrigger);
return (0, _possibleConstructorReturn3['default'])(this, (PopoverClickTrigger.__proto__ || Object.getPrototypeOf(PopoverClickTrigger)).apply(this, arguments));
}
(0, _createClass3['default'])(PopoverClickTrigger, [{
key: 'getTriggerProps',
value: function getTriggerProps(child) {
var _this2 = this;
return {
onClick: function onClick(evt) {
evt.preventDefault();
if (_this2.props.contentVisible) {
_this2.props.close();
} else if (!child.props.disabled) {
_this2.props.open();
_this2.triggerEvent(child, 'onClick', evt);
}
}
};
}
}]);
return PopoverClickTrigger;
}(_popover2['default'].Trigger.Click);
var Select = function (_ref) {
(0, _inherits3['default'])(Select, _ref);
function Select(props) {
(0, _classCallCheck3['default'])(this, Select);
var _this3 = (0, _possibleConstructorReturn3['default'])(this, (Select.__proto__ || Object.getPrototypeOf(Select)).call(this, props));
_this3.triggerChangeHandler = function (data) {
_this3.setState(data);
};
_this3.triggerDeleteHandler = function (data) {
var selectedItems = _this3.state.selectedItems;
selectedItems = selectedItems.filter(function (item) {
return item.cid !== data.cid;
});
_this3.setState({
selectedItems: selectedItems
}, function () {
_this3.props.onDelete(data);
});
};
_this3.optionChangedHandler = function (ev, selectedItem) {
var result = {};
ev = ev || {
preventDefault: _noop2['default'],
stopPropagation: _noop2['default']
};
var _this3$props = _this3.props,
onEmptySelected = _this3$props.onEmptySelected,
optionValue = _this3$props.optionValue,
optionText = _this3$props.optionText,
tags = _this3$props.tags,
onChange = _this3$props.onChange;
var selectedItems = _this3.state.selectedItems;
if (!selectedItem) {
onEmptySelected(ev);
return;
}
var args = (0, _omit2['default'])(selectedItem, ['cid']);
result[optionValue] = selectedItem.value;
result[optionText] = selectedItem.text;
var data = (0, _extends3['default'])({}, args, result);
if (tags) {
if (!selectedItems.some(function (item) {
return item.cid === selectedItem.cid;
})) {
selectedItems.push(selectedItem);
}
}
_this3.setState({
keyword: null,
selectedItems: selectedItems,
selectedItem: selectedItem
}, function () {
onChange({
target: (0, _extends3['default'])({}, _this3.props, {
type: tags ? 'select-multiple' : 'select-one',
value: selectedItem.value
}),
preventDefault: function preventDefault() {
ev.preventDefault();
},
stopPropagation: function stopPropagation() {
ev.stopPropagation();
}
}, data);
});
};
_this3.handlePopoverVisibleChange = function (visible) {
if (visible) {
_this3.props.onOpen();
}
_this3.setState({ open: visible });
};
if (props.simple) {
_this3.trigger = _SimpleTrigger2['default'];
} else if (props.search) {
_this3.trigger = _InputTrigger2['default'];
} else if (props.tags) {
_this3.trigger = _TagsTrigger2['default'];
} else {
_this3.trigger = props.trigger;
}
_this3.state = Object.assign({
selectedItems: [],
selectedItem: {
value: '',
text: ''
}
}, props);
return _this3;
}
(0, _createClass3['default'])(Select, [{
key: 'componentWillMount',
value: function componentWillMount() {
/**
* data支持字符串数组和对象数组两种模式
*
* 字符串数组默认value为下标
* 对象数组需提供value和text, 或者通过 optionValue-prop optionText-prop 自定义
*
*/
this.uniformedData = this.uniformData(this.props);
this.traverseData(this.props);
}
}, {
key: 'componentWillReceiveProps',
value: function componentWillReceiveProps(nextProps) {
this.uniformedData = this.uniformData(nextProps);
this.traverseData(nextProps);
}
/**
* 将使用 child-element 传入的 Options 格式化为对象数组(未严格约束)
* data-prop 的优先级高于 child-element
*
* @param {object} props - props of Select
* @returns {object[]} uniformedData - 格式化后对象数组
* @returns {string} uniformedData[].cid - internal id of option
* @returns {string} uniformedData[].text - text of an option
* @returns {any} uniformedData[].value - token of an option
* @memberof Select
*/
}, {
key: 'uniformData',
value: function uniformData(props) {
var data = props.data,
children = props.children,
optionValue = props.optionValue,
optionText = props.optionText;
var uniformedData = void 0;
// data-prop 高优先级, 格式化 optionValue、optionText
if (data) {
return uniformedData = data.map(function (option, index) {
// 处理字符串数组
if ((typeof option === 'undefined' ? 'undefined' : (0, _typeof3['default'])(option)) !== 'object') {
return { text: option, value: option, cid: '' + index };
}
// hacky the quirk when optionText = 'value' and avoid modify props
var optCopy = (0, _cloneDeep2['default'])(option);
optCopy.cid = '' + index;
if (optionValue) {
optCopy.value = option[optionValue];
}
if (optionText) {
optCopy.text = option[optionText];
}
return optCopy;
});
}
// 格式化 child-element
if (children) {
uniformedData = _react.Children.map(children, function (item, index) {
var value = item.props.value;
value = typeof value === 'undefined' ? item : value;
return Object.assign({}, item.props, {
value: value,
cid: '' + index,
text: item.props.children
});
});
}
return uniformedData;
}
/**
* accept uniformed data to traverse then inject selected option or options to next state
*
* @param {object[]} data - uniformedData
* @param {object} props - props of Select
* @memberof Select
*/
}, {
key: 'traverseData',
value: function traverseData(props) {
var _this4 = this;
var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : this.uniformedData;
// option 数组置空后重置组件状态
if (!data.length) {
return this.setState({
selectedItem: {},
selectedItems: []
});
}
var _state = this.state,
selectedItem = _state.selectedItem,
selectedItems = _state.selectedItems;
var value = props.value,
index = props.index,
initialIndex = props.initialIndex,
initialValue = props.initialValue;
// initialize selected internal state
var selected = { sItem: selectedItem, sItems: [] };
data.forEach(function (item, i) {
// 处理 quirk 默认选项(initialIndex, initialValue)
if (selectedItems.length === 0 && !selectedItem.cid && (initialValue !== null || initialIndex !== null)) {
var coord = { value: initialValue, index: initialIndex };
_this4.locateSelected(selected, coord, item, i);
}
// 处理受控逻辑(index, value)
if (value !== null || index !== null) {
_this4.locateSelected(selected, { value: value, index: index }, item, i);
}
});
this.setState({
selectedItem: selected.sItem,
selectedItems: selected.sItems
});
}
/**
* judge if param 'item' selected
*
* @param {object} state - next state marked selected item or items
* @param {object} coord - coordinate for seleted judging
* @param {object} item - option object after uniformed
* @param {number} i - index of option in options list
* @memberof Select
* */
}, {
key: 'locateSelected',
value: function locateSelected(state, coord, item, i) {
var value = coord.value,
index = coord.index;
if ((0, _isArray2['default'])(value) && value.indexOf(item.value) > -1) {
// rerender 去重
if (!state.sItems.find(function (selected) {
return selected.value === item.value;
})) {
state.sItems.push(item);
}
} else if ((0, _isArray2['default'])(value) && value.length === 0) {
// 多选重置
state.sItem = {};
state.sItems = [];
} else if ((typeof value === 'undefined' ? 'undefined' : (0, _typeof3['default'])(value)) === 'object' && (0, _isEqual2['default'])(value, item.value)) {
state.sItem = item;
} else if (typeof value !== 'undefined' && (typeof value === 'undefined' ? 'undefined' : (0, _typeof3['default'])(value)) !== 'object' && '' + item.value === '' + value || index !== 'undefined' && '' + i === '' + index) {
state.sItem = item;
} else if (!value && !index && value !== 0) {
// github#406 修复option-value为假值数字0时的异常重置。
// 单选重置
state.sItem = {};
state.sItems = [];
}
}
// 接收trigger改变后的数据,将数据传给popup
// 将被选中的option的数据传给trigger
}, {
key: 'render',
value: function render() {
var _this5 = this;
var _props = this.props,
placeholder = _props.placeholder,
maxToShow = _props.maxToShow,
className = _props.className,
popupClassName = _props.popupClassName,
disabled = _props.disabled,
emptyText = _props.emptyText,
_props$filter = _props.filter,
filter = _props$filter === undefined ? this.props.onFilter : _props$filter,
onAsyncFilter = _props.onAsyncFilter,
searchPlaceholder = _props.searchPlaceholder,
autoWidth = _props.autoWidth,
width = _props.width;
var _state2 = this.state,
open = _state2.open,
selectedItems = _state2.selectedItems,
_state2$selectedItem = _state2.selectedItem,
selectedItem = _state2$selectedItem === undefined ? {} : _state2$selectedItem,
extraFilter = _state2.extraFilter,
_state2$keyword = _state2.keyword,
keyword = _state2$keyword === undefined ? null : _state2$keyword;
var _selectedItem$cid = selectedItem.cid,
cid = _selectedItem$cid === undefined ? '' : _selectedItem$cid;
var disabledCls = disabled ? 'disabled' : '';
var prefixCls = this.props.prefix + '-select';
return _react2['default'].createElement(
_popover2['default'],
{
display: 'inline-block',
position: _popover2['default'].Position.AutoBottomLeft,
visible: open,
className: prefixCls + ' ' + popupClassName,
wrapperClassName: prefixCls + ' ' + className + ' ' + disabledCls,
onVisibleChange: this.handlePopoverVisibleChange,
width: width
},
_react2['default'].createElement(
PopoverClickTrigger,
null,
_react2['default'].createElement(_trigger2['default'], (0, _extends3['default'])({
disabled: disabled,
prefixCls: prefixCls,
trigger: this.trigger,
placeholder: placeholder,
selectedItems: selectedItems,
keyword: keyword
}, selectedItem, {
onChange: this.triggerChangeHandler,
onDelete: this.triggerDeleteHandler
}))
),
_react2['default'].createElement(
_popover2['default'].Content,
null,
_react2['default'].createElement(_Popup2['default'], {
ref: function ref(_ref2) {
return _this5.popup = _ref2;
},
cid: cid,
prefixCls: prefixCls,
data: this.uniformedData,
selectedItems: selectedItems,
extraFilter: extraFilter,
searchPlaceholder: searchPlaceholder,
emptyText: emptyText,
keyword: keyword,
filter: filter,
onAsyncFilter: onAsyncFilter,
maxToShow: maxToShow,
onChange: this.optionChangedHandler,
onFocus: this.popupFocusHandler,
onBlur: this.popupBlurHandler,
autoWidth: autoWidth
})
)
);
}
}]);
return Select;
}(_react.PureComponent || _react.Component);
Select.propTypes = {
data: _propTypes2['default'].array,
prefix: _propTypes2['default'].string,
className: _propTypes2['default'].string,
open: _propTypes2['default'].bool,
popupClassName: _propTypes2['default'].string,
disabled: _propTypes2['default'].bool,
placeholder: _propTypes2['default'].string,
maxToShow: _propTypes2['default'].number,
searchPlaceholder: _propTypes2['default'].string,
emptyText: _propTypes2['default'].node,
selectedItem: _propTypes2['default'].shape({
value: _propTypes2['default'].any,
text: _propTypes2['default'].string
}),
trigger: _propTypes2['default'].func,
optionValue: _propTypes2['default'].string,
optionText: _propTypes2['default'].string,
onChange: _propTypes2['default'].func,
onDelete: _propTypes2['default'].func,
filter: _propTypes2['default'].func,
onAsyncFilter: _propTypes2['default'].func,
onEmptySelected: _propTypes2['default'].func,
onOpen: _propTypes2['default'].func,
width: _propTypes2['default'].oneOfType([_propTypes2['default'].number, _propTypes2['default'].string]),
// 自动根据ref计算弹层宽度
autoWidth: _propTypes2['default'].bool
};
Select.defaultProps = {
prefix: 'zent',
disabled: false,
className: '',
open: false,
popupClassName: '',
trigger: _SelectTrigger2['default'],
placeholder: '请选择',
searchPlaceholder: '',
emptyText: '没有找到匹配项',
selectedItem: {
value: '',
text: ''
},
selectedItems: [],
optionValue: 'value',
optionText: 'text',
onChange: _noop2['default'],
onDelete: _noop2['default'],
onEmptySelected: _noop2['default'],
onOpen: _noop2['default'],
autoWidth: false,
// HACK
value: null,
index: null,
initialValue: null,
initialIndex: null
};
exports['default'] = Select;