amis
Version:
一种MIS页面生成工具
414 lines (413 loc) • 20.4 kB
JavaScript
"use strict";
/**
* @file Select
* @description
* @author fex
* @date 2017-11-07
*/
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var uncontrollable = require("uncontrollable");
var react_1 = tslib_1.__importDefault(require("react"));
/*@require react-datetime/css/react-datetime.css*/;
var Overlay_1 = tslib_1.__importDefault(require("./Overlay"));
var PopOver_1 = tslib_1.__importDefault(require("./PopOver"));
var downshift_1 = tslib_1.__importDefault(require("downshift"));
var icons_1 = require("./icons");
var match_sorter_1 = tslib_1.__importDefault(require("match-sorter"));
var helper_1 = require("../utils/helper");
var find = require("lodash/find");
var isPlainObject = require("lodash/isPlainObject");
var union = require("lodash/union");
var Options_1 = require("../renderers/Form/Options");
var react_dom_1 = require("react-dom");
var theme_1 = require("../theme");
var Checkbox_1 = tslib_1.__importDefault(require("./Checkbox"));
function value2array(value, props) {
if (props.multi || props.multiple) {
if (typeof value === 'string') {
value = value.split(props.delimiter || ',');
}
if (!Array.isArray(value)) {
if (value === null || value === undefined) {
return [];
}
value = [value];
}
return value.map(function (value) { return expandValue(value, props); }).filter(function (item) { return item; });
}
else if (Array.isArray(value)) {
value = value[0];
}
var expandedValue = expandValue(value, props);
return expandedValue ? [expandedValue] : [];
}
exports.value2array = value2array;
function expandValue(value, props) {
var valueType = typeof value;
if (valueType !== 'string' && valueType !== 'number' && valueType !== 'boolean') {
return value;
}
var options = props.options;
if (!options) {
return null;
}
return find(options, function (item) { return String(item[props.valueField || 'value']) === String(value); });
}
exports.expandValue = expandValue;
function normalizeOptions(options) {
if (typeof options === 'string') {
return options.split(',').map(function (item) { return ({
label: item,
value: item
}); });
}
else if (Array.isArray(options) && typeof options[0] === 'string') {
return options.map(function (item) { return ({
label: item,
value: item
}); });
}
else if (Array.isArray(options)) {
return options.map(function (item) {
var option = tslib_1.__assign(tslib_1.__assign({}, item), { value: item && item.value });
if (typeof option.children !== 'undefined') {
option.children = normalizeOptions(option.children);
}
return option;
});
}
else if (isPlainObject(options)) {
return Object.keys(options).map(function (key) { return ({
label: options[key],
value: key
}); });
}
return [];
}
exports.normalizeOptions = normalizeOptions;
var Select = /** @class */ (function (_super) {
tslib_1.__extends(Select, _super);
function Select(props) {
var _this = _super.call(this, props) || this;
_this.menu = react_1.default.createRef();
_this.open = _this.open.bind(_this);
_this.close = _this.close.bind(_this);
_this.toggle = _this.toggle.bind(_this);
_this.onBlur = _this.onBlur.bind(_this);
_this.onFocus = _this.onFocus.bind(_this);
_this.focus = _this.focus.bind(_this);
_this.inputRef = _this.inputRef.bind(_this);
_this.handleChange = _this.handleChange.bind(_this);
_this.handleInputChange = _this.handleInputChange.bind(_this);
_this.clearValue = _this.clearValue.bind(_this);
_this.handleStateChange = _this.handleStateChange.bind(_this);
_this.handleKeyPress = _this.handleKeyPress.bind(_this);
_this.getTarget = _this.getTarget.bind(_this);
_this.toggleCheckAll = _this.toggleCheckAll.bind(_this);
_this.state = {
isOpen: false,
isFocused: false,
inputValue: '',
highlightedIndex: -1,
selection: value2array(props.value, props)
};
return _this;
}
Select.prototype.componentDidMount = function () {
var _a = this.props, loadOptions = _a.loadOptions, options = _a.options, multiple = _a.multiple, checkAll = _a.checkAll, defaultCheckAll = _a.defaultCheckAll, onChange = _a.onChange, simpleValue = _a.simpleValue;
var selection = this.state.selection;
if (multiple && checkAll && defaultCheckAll && options.length) {
selection = union(options, selection);
this.setState({
selection: selection
}, function () { return onChange(simpleValue ? selection.map(function (item) { return item.value; }) : selection); });
}
loadOptions && loadOptions('');
};
Select.prototype.componentWillReceiveProps = function (nextProps) {
var props = this.props;
if (props.value !== nextProps.value || JSON.stringify(props.options) !== JSON.stringify(nextProps.options)) {
this.setState({
selection: value2array(nextProps.value, nextProps)
});
}
};
Select.prototype.open = function () {
this.props.disabled ||
this.setState({
isOpen: true
});
};
Select.prototype.close = function () {
this.setState({
isOpen: false
});
};
Select.prototype.toggle = function (e) {
if (e && this.menu.current && this.menu.current.contains(e.target)) {
return;
}
this.props.disabled ||
this.setState({
isOpen: !this.state.isOpen
});
};
Select.prototype.onFocus = function (e) {
this.props.disabled ||
this.setState({
isFocused: true
}, this.focus);
this.props.onFocus && this.props.onFocus(e);
};
Select.prototype.onBlur = function (e) {
this.setState({
isFocused: false,
inputValue: ''
});
this.props.onBlur && this.props.onBlur(e);
};
Select.prototype.focus = function () {
this.input ? this.input.focus() : this.getTarget() && this.getTarget().focus();
};
Select.prototype.blur = function () {
this.input ? this.input.blur() : this.getTarget() && this.getTarget().blur();
};
Select.prototype.getTarget = function () {
if (!this.target) {
this.target = react_dom_1.findDOMNode(this);
}
return this.target;
};
Select.prototype.inputRef = function (ref) {
this.input = ref;
};
Select.prototype.toggleCheckAll = function () {
var _a = this.props, options = _a.options, onChange = _a.onChange, simpleValue = _a.simpleValue;
var selection = this.state.selection;
var optionsValues = options.map(function (option) { return option.value; });
var selectionValues = selection.map(function (select) { return select.value; });
var checkedAll = optionsValues.every(function (option) { return selectionValues.indexOf(option) > -1; });
selection = checkedAll ? [] : options;
onChange(simpleValue ? selection.map(function (item) { return item.value; }) : selection);
};
Select.prototype.removeItem = function (index, e) {
var _a = this.props, onChange = _a.onChange, simpleValue = _a.simpleValue;
var value = this.state.selection;
e && e.stopPropagation();
value = Array.isArray(value) ? value.concat() : [value];
value.splice(index, 1);
onChange(simpleValue ? value.map(function (item) { return item.value; }) : value);
};
Select.prototype.handleInputChange = function (evt) {
var _this = this;
var loadOptions = this.props.loadOptions;
this.setState({
inputValue: evt.currentTarget.value
}, function () { return loadOptions && loadOptions(_this.state.inputValue); });
};
Select.prototype.handleChange = function (selectItem) {
var _a = this.props, onChange = _a.onChange, multiple = _a.multiple, onNewOptionClick = _a.onNewOptionClick, simpleValue = _a.simpleValue;
var selection = this.state.selection;
if (selectItem.isNew) {
delete selectItem.isNew;
onNewOptionClick(selectItem);
}
if (multiple) {
selection = selection.concat();
var idx = selection.indexOf(selectItem);
if (~idx) {
selection.splice(idx, 1);
}
else {
selection.push(selectItem);
}
onChange(simpleValue ? selection.map(function (item) { return item.value; }) : selection);
}
else {
onChange(simpleValue ? selectItem.value : selectItem);
}
};
Select.prototype.handleStateChange = function (changes) {
var _a = this.props, multiple = _a.multiple, checkAll = _a.checkAll;
var update = {};
var loadOptions = this.props.loadOptions;
var doLoad = false;
if (changes.isOpen !== void 0) {
update.isOpen = changes.isOpen;
}
if (changes.highlightedIndex !== void 0) {
update.highlightedIndex = changes.highlightedIndex;
}
switch (changes.type) {
case downshift_1.default.stateChangeTypes.keyDownEnter:
case downshift_1.default.stateChangeTypes.clickItem:
update = tslib_1.__assign(tslib_1.__assign({}, update), { inputValue: '', isOpen: multiple && checkAll ? true : false, isFocused: multiple && checkAll ? true : false });
doLoad = true;
break;
case downshift_1.default.stateChangeTypes.changeInput:
update.highlightedIndex = 0;
break;
}
if (Object.keys(update).length) {
this.setState(update, doLoad && loadOptions ? function () { return loadOptions(''); } : undefined);
}
};
Select.prototype.handleKeyPress = function (e) {
if (e.key === ' ') {
this.toggle();
}
};
Select.prototype.clearValue = function (e) {
var onChange = this.props.onChange;
e.preventDefault();
e.stopPropagation();
onChange('');
};
Select.prototype.renderValue = function (_a) {
var _this = this;
var inputValue = _a.inputValue, isOpen = _a.isOpen;
var _b = this.props, multiple = _b.multiple, placeholder = _b.placeholder, ns = _b.classPrefix, labelField = _b.labelField, searchable = _b.searchable, creatable = _b.creatable;
var selection = this.state.selection;
if (searchable && !creatable && inputValue && (multiple ? !selection.length : true)) {
return null;
}
if (!selection.length) {
return creatable && inputValue ? null : (react_1.default.createElement("div", { key: "placeholder", className: ns + "Select-placeholder" }, placeholder));
}
return selection.map(function (item, index) {
return multiple ? (react_1.default.createElement("div", { className: ns + "Select-value", key: index },
react_1.default.createElement("span", { className: ns + "Select-valueIcon", onClick: _this.removeItem.bind(_this, index) }, "\u00D7"),
react_1.default.createElement("span", { className: ns + "Select-valueLabel" }, item[labelField || 'label']))) : inputValue && isOpen ? null : (react_1.default.createElement("div", { className: ns + "Select-value", key: index }, item.label));
});
};
Select.prototype.renderOuter = function (_a) {
var _b;
var _this = this;
var selectedItem = _a.selectedItem, getItemProps = _a.getItemProps, highlightedIndex = _a.highlightedIndex, inputValue = _a.inputValue, isOpen = _a.isOpen;
var _c = this.props, popOverContainer = _c.popOverContainer, options = _c.options, valueField = _c.valueField, labelField = _c.labelField, noResultsText = _c.noResultsText, loadOptions = _c.loadOptions, creatable = _c.creatable, promptTextCreator = _c.promptTextCreator, multiple = _c.multiple, cx = _c.classnames, checkAll = _c.checkAll, checkAllLabel = _c.checkAllLabel;
var selection = this.state.selection;
var checkedAll = false;
var checkedPartial = false;
var filtedOptions = inputValue && isOpen && !loadOptions
? match_sorter_1.default(options, inputValue, {
keys: [labelField || 'label', valueField || 'value']
})
: options.concat();
if (multiple) {
if (checkAll) {
var optionsValues = options.map(function (option) { return option.value; });
var selectionValues_1 = selection.map(function (select) { return select.value; });
checkedAll = optionsValues.every(function (option) { return selectionValues_1.indexOf(option) > -1; });
checkedPartial = optionsValues.some(function (option) { return selectionValues_1.indexOf(option) > -1; });
}
else {
filtedOptions = filtedOptions.filter(function (option) { return !~selectedItem.indexOf(option); });
}
}
if (inputValue && creatable && !find(options, function (item) { return item[labelField || 'label'] == inputValue; })) {
filtedOptions.unshift((_b = {},
_b[labelField] = inputValue,
_b[valueField] = inputValue,
_b.isNew = true,
_b));
}
var menu = (react_1.default.createElement("div", { ref: this.menu, className: cx('Select-menu') },
multiple && checkAll ? (react_1.default.createElement("div", { className: cx('Select-checkAll') },
react_1.default.createElement(Checkbox_1.default, { checked: checkedPartial, partial: checkedPartial && !checkedAll, onChange: this.toggleCheckAll }, checkAllLabel))) : null,
filtedOptions.length ? (filtedOptions.map(function (item, index) {
var checked = checkAll ? selection.some(function (o) { return o.value == item.value; }) : false;
return (react_1.default.createElement("div", tslib_1.__assign({}, getItemProps({
key: index,
index: index,
item: item,
disabled: item.disabled
}), { className: cx("Select-option", {
'is-disabled': item.disabled,
'is-highlight': highlightedIndex === index,
'is-active': selectedItem === item ||
(Array.isArray(selectedItem) && ~selectedItem.indexOf(item))
}) }), checkAll ? (react_1.default.createElement(Checkbox_1.default, { checked: checked, trueValue: item.value, onChange: function () { return _this.handleChange(item); } }, item.isNew
? promptTextCreator(item.label)
: item.disabled
? item[labelField]
: Options_1.highlight(item[labelField], inputValue, cx('Select-option-hl')))) : item.isNew ? (promptTextCreator(item.label)) : (react_1.default.createElement("span", null,
item.disabled
? item.label
: Options_1.highlight(item[labelField], inputValue, cx('Select-option-hl')),
item.tip))));
})) : (react_1.default.createElement("div", { className: cx('Select-option Select-option--placeholder') }, noResultsText))));
if (popOverContainer) {
return (react_1.default.createElement(Overlay_1.default, { container: popOverContainer, placement: "left-bottom-left-top", target: this.getTarget, show: true },
react_1.default.createElement(PopOver_1.default, { className: cx('Select-popover'), style: { width: this.target ? this.target.offsetWidth : 'auto' } }, menu)));
}
else {
return react_1.default.createElement("div", { className: cx('Select-menuOuter') }, menu);
}
};
Select.prototype.render = function () {
var _this = this;
var _a = this.props, cx = _a.classnames, multiple = _a.multiple, searchable = _a.searchable, inline = _a.inline, className = _a.className, value = _a.value, loading = _a.loading, spinnerClassName = _a.spinnerClassName, clearable = _a.clearable, labelField = _a.labelField, disabled = _a.disabled;
var selection = this.state.selection;
var inputValue = this.state.inputValue;
return (react_1.default.createElement(downshift_1.default, { selectedItem: selection, highlightedIndex: this.state.highlightedIndex, isOpen: this.state.isOpen, inputValue: inputValue, onChange: this.handleChange, onStateChange: this.handleStateChange, onOuterClick: this.close, itemToString: function (item) { return (item ? item[labelField] : ''); } }, function (options) {
var _a;
var isOpen = options.isOpen, getInputProps = options.getInputProps;
return (react_1.default.createElement("div", { tabIndex: searchable || disabled ? -1 : 0, onKeyPress: _this.handleKeyPress, onClick: _this.toggle, onFocus: _this.onFocus, onBlur: _this.onBlur, className: cx("Select", (_a = {},
_a["Select--multi"] = multiple,
_a["Select--inline"] = inline,
_a["Select--searchable"] = searchable,
_a['is-opened'] = isOpen,
_a['is-focused'] = _this.state.isFocused,
_a['is-disabled'] = disabled,
_a), className) },
react_1.default.createElement("div", { className: cx("Select-valueWrap") },
_this.renderValue(options),
searchable && !disabled ? (react_1.default.createElement("input", tslib_1.__assign({}, getInputProps({
className: cx("Select-input"),
onFocus: _this.onFocus,
onBlur: _this.onBlur,
onKeyDown: function (event) {
if (event.key === 'Backspace' && !inputValue) {
_this.removeItem(value.length - 1);
}
},
onChange: _this.handleInputChange,
ref: _this.inputRef
})))) : null),
clearable && !disabled && value && value.length ? (react_1.default.createElement("a", { onClick: _this.clearValue, className: cx('Select-clear') },
react_1.default.createElement(icons_1.Icon, { icon: "close", className: "icon" }))) : null,
loading ? (react_1.default.createElement("span", { className: cx('Select-spinner') },
react_1.default.createElement("i", { className: spinnerClassName }))) : null,
react_1.default.createElement("span", { className: cx('Select-arrow') }),
isOpen ? _this.renderOuter(options) : null));
}));
};
Select.defaultProps = {
multiple: false,
clearable: true,
creatable: false,
searchPromptText: '输入内容进行检索',
loadingPlaceholder: '加载中..',
noResultsText: '没有结果',
clearAllText: '移除所有',
clearValueText: '移除',
placeholder: '请选择',
valueField: 'value',
labelField: 'label',
spinnerClassName: 'fa fa-spinner fa-spin fa-1x fa-fw',
promptTextCreator: function (label) { return "\u65B0\u589E\uFF1A" + label; },
onNewOptionClick: helper_1.noop,
inline: false,
disabled: false,
checkAll: false,
checkAllLabel: '全选',
defaultCheckAll: false
};
return Select;
}(react_1.default.Component));
exports.Select = Select;
exports.default = theme_1.themeable(uncontrollable(Select, {
value: 'onChange'
}));
//# sourceMappingURL=./components/Select.js.map