UNPKG

zarm-web

Version:
418 lines (365 loc) 10.6 kB
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); } import React, { Component } from 'react'; import Events from '../utils/events'; import { FormItemContext } from '../form/createContext'; import Option from './Option'; import Dropdown from '../dropdown'; import Menu from '../menu'; import InputWithTags from '../tag-input'; import LocaleReceiver from '../locale-provider/LocaleReceiver'; import SelectMultiple from './SelectMultiple'; import { isEmpty } from '../utils'; const EMPTY_STRING = ''; const EMPTY_STRING_VALUE = '$$EMPTY_STRING_VALUE'; /** * placeholder */ class Select extends Component { static mapEmptyStringToEmptyValue(values) { if (Array.isArray(values)) { return values.map(value => { if (value === EMPTY_STRING) { return EMPTY_STRING_VALUE; } return value; }); } if (values === EMPTY_STRING) { return EMPTY_STRING_VALUE; } return values; } static getOptionMap(options) { if (!Array.isArray(options)) { options = [options]; } const optionData = []; const optionMap = {}; React.Children.map(options, option => { if (option && typeof option === 'object' && option.type) { const value = Select.mapEmptyStringToEmptyValue(option.props.value); if (option.props && value) { // handle optionMap optionMap[value] = option; // handle OptionData optionData.push({ key: option.key, props: option.props, value, children: option.props.children }); } } return optionMap; }); return [optionMap, optionData]; } static mapEmptyValueToEmptyString(selected) { return selected.map(select => { if (select === EMPTY_STRING_VALUE) { return EMPTY_STRING; } return select; }); } constructor(props) { super(props); this.inputBox = void 0; this.inputWithTags = void 0; this.oldInputDivHeight = 0; this.inputWithTagsRef = e => { this.inputWithTags = e; }; this.onDeleteTag = (_e, _key, _value, index) => { const selected = Select.mapEmptyValueToEmptyString(this.state.value.slice()); selected.splice(index, 1); const selectedData = selected.map((select, selectIndex) => { const vdom = this.state.optionMap[select || EMPTY_STRING_VALUE]; const text = vdom ? vdom.props.children : ''; return { text, value: select, index: selectIndex }; }); this.props.onChange(selected, selectedData); }; this.onSearchValueChange = value => { const { onSearchChange } = this.props; // const textContent = (e.target as HTMLDivElement).textContent; this.setState({ searchValue: value, dropdown: true }, () => { if (typeof onSearchChange === 'function') { onSearchChange(this.state.searchValue); } }); }; const _value2 = props.value === undefined ? props.defaultValue : props.value; const state = { value: String(_value2), dropdown: false, searchValue: '', showPlacehoder: true, optionMap: {}, optionData: [] }; const { children } = this.props; if (props.multiple) { if (!Array.isArray(_value2)) { state.value = [String(_value2)]; } else { state.value = _value2.map(val => String(val)); } } else { state.value = String(_value2); } state.value = Select.mapEmptyStringToEmptyValue(state.value); const [optionMap, optionData] = Select.getOptionMap(children); state.optionMap = optionMap; state.optionData = optionData; this.state = state; } componentDidMount() { this.bindOuterHandlers(); } componentWillReceiveProps(nextProps) { const { defaultValue, children } = this.props; if ('value' in nextProps || nextProps.defaultValue !== defaultValue) { let value = nextProps.value === undefined ? nextProps.defaultValue : nextProps.value; if (nextProps.multiple) { if (!Array.isArray(value)) { value = [String(value)]; } else { value = value.map(val => String(val)); } } else { value = String(value); } this.setState({ value: Select.mapEmptyStringToEmptyValue(value) }); } if (nextProps.children !== children) { const [optionMap, optionData] = Select.getOptionMap(nextProps.children); this.setState({ optionData, optionMap }); } } componentWillUnmount() { this.unbindOuterHandlers(); } onOptionChange(_, props, index) { const { multiple, onChange } = this.props; const { handleFieldChange } = this.context; const { optionMap, optionData, value: stateValue } = this.state; if ('disabled' in props || props.isDisabled) { return; } if (props.search || props.isSearch) { this.setState({ searchValue: '' }); this.inputBox.textContent = ''; } if (!isEmpty(this.context)) { handleFieldChange(); } const value = String(props.value); if (multiple) { const selected = Select.mapEmptyValueToEmptyString(stateValue.slice()); const position = selected.indexOf(value); if (position === -1) { selected.push(value); } else { selected.splice(position, 1); } const selectedData = selected.map(select => { const selectValue = select || EMPTY_STRING_VALUE; const vdom = optionMap[selectValue]; const text = vdom ? vdom.props.children : ''; const indexs = optionData.findIndex(elem => String(elem.value) === String(selectValue)); return { text, value: select, indexs }; }); this.setState({ value: Select.mapEmptyStringToEmptyValue(selected) }, () => { onChange(selected, selectedData); }); return; } const selected = { index, value, text: Array.isArray(props.children) ? props.children.join() : props.children }; this.setState({ value: Select.mapEmptyStringToEmptyValue(value) }, () => { this.setDropdown(false, () => onChange(selected)); }); } setDropdown(isOpen, callback) { this.setState({ dropdown: isOpen, searchValue: '' }, () => { if (typeof callback === 'function') { callback(); } }); } bindOuterHandlers() { Events.on(document, 'keyup', e => this.handleKeyup(e)); } unbindOuterHandlers() { Events.off(document, 'keyup', e => this.handleKeyup(e)); } handleKeyup(e) { const { dropdown } = this.state; if (dropdown === true && e.keyCode === 27) { this.setDropdown(false); } } render() { const { searchValue, value, optionMap, optionData, dropdown } = this.state; const { prefixCls, placeholder, size, tagTheme, style, zIndex, multiple, getPopupContainer, locale, remoteSearch } = this.props; const disabled = 'disabled' in this.props; const radius = 'radius' in this.props; const search = 'search' in this.props; const placeholderText = placeholder || locale.placeholder; let valueText; if (multiple && Array.isArray(value)) { valueText = value.reduce((prev, item) => { if (optionMap[item]) { prev.push({ key: item, value: optionMap[item].props.children }); } return prev; }, []); } else { const optionProps = optionMap[value]; if (optionProps) { const optionChildren = optionProps.props.children; Array.isArray(optionChildren) ? valueText = optionChildren.join() : valueText = optionChildren; } } const children = []; const filterCondition = (option, optionIndex) => { if (search && searchValue) { return String(option.props.children).includes(searchValue); } // remoteSearch会走此处逻辑 return optionIndex > -1; }; optionData.filter(filterCondition).forEach((elem, index) => { const checked = Array.isArray(value) ? value.indexOf(String(elem.value)) > -1 : String(elem.value) === value; children.push(React.createElement(Option, _extends({ key: elem.key || elem.value, showCheckIcon: checked }, elem.props, { checked: checked, onChange: e => { this.onOptionChange(e, elem.props, index); } }), elem.children)); }); const menuStyle = { maxHeight: 250, overflow: 'auto' }; const menus = children && children.length > 0 ? React.createElement(Menu, { size: size, style: menuStyle }, children) : React.createElement("span", { className: `${prefixCls}--notfound` }, locale.noMatch); return React.createElement(Dropdown, { triggerBoxStyle: style, disabled: disabled, visible: dropdown, isRadius: radius, overlay: menus, zIndex: zIndex, getPopupContainer: getPopupContainer, onVisibleChange: visible => { if (visible === true) { this.setState({ dropdown: visible, searchValue: '' }); } else { this.setState({ dropdown: visible }); } } }, React.createElement(InputWithTags, { tagTheme: tagTheme, radius: radius, size: size, disabled: disabled, ref: this.inputWithTagsRef, style: style, searchValue: searchValue, search: search, remoteSearch: remoteSearch, active: dropdown, value: valueText, placeholder: placeholderText, onDeleteTag: this.onDeleteTag, onSearchChange: this.onSearchValueChange })); } } Select.contextType = FormItemContext; Select.defaultProps = { prefixCls: 'za-select', radius: true, onSearchChange: () => {}, onChange: () => {} }; Select.Option = Option; Select.Multiple = SelectMultiple; export default LocaleReceiver('Select')(Select);