UNPKG

chowa

Version:

UI component library based on React

358 lines (357 loc) 16 kB
/** * @license chowa v1.1.3 * * Copyright (c) Chowa Techonlogies Co.,Ltd.(http://www.chowa.cn). * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const React = require("react"); const PropTypes = require("prop-types"); const classnames_1 = require("classnames"); const receiver_1 = require("../i18n/receiver"); const utils_1 = require("../utils/"); const tool_1 = require("./tool"); const cascader_card_1 = require("./cascader-card"); const cascader_list_1 = require("./cascader-list"); const cascader_not_found_1 = require("./cascader-not-found"); const cascader_filter_options_1 = require("./cascader-filter-options"); const dropdown_1 = require("../dropdown"); const icon_1 = require("../icon"); class Cascader extends React.PureComponent { constructor(props) { super(props); const { options, defaultValue, value } = props; this.state = { renderOptions: [].concat(props.options), searchValue: '', searching: false, selectorVisible: props.visible || props.defaultVisible, selectedOptions: tool_1.compileSelectedOptions(value || defaultValue, options), showClear: false, optionsTier: tool_1.computedOptionsTier(options), activeOption: undefined, activeFilterOptions: undefined }; [ 'onVisibleChange', 'onSelectHandler', 'onSearchChangeHandler', 'onSearchBlurHandler', 'onSearchFocusHandler', 'onTriggerMouseEnterHandler', 'onTriggerMouseLeaveHandler', 'clearSelectedValues', 'onKeyboardOperation', 'onOptionMouseEnter', 'onOptionMouseLeave', 'onFilterOptionMouseEnter', 'onFilterOptionMouseLeave', 'onFilterSelectHandler' ].forEach((fn) => { this[fn] = this[fn].bind(this); }); } componentDidUpdate(preProps, preState) { if (!utils_1.isEqual(preProps.value, this.props.value)) { this.setState({ selectedOptions: tool_1.compileSelectedOptions(this.props.value, this.state.renderOptions) }); } if (!utils_1.isEqual(preProps.options, this.props.options)) { this.setState({ optionsTier: tool_1.computedOptionsTier(this.props.options), renderOptions: tool_1.filterOptions(this.props.options, this.state.searchValue, this.props.onFilter) }); } if (this.props.searchable && this.state.selectorVisible && (preState.selectorVisible !== this.state.selectorVisible || !utils_1.isEqual(preState.selectedOptions, this.state.selectedOptions))) { this.inputElement.focus(); } if (preProps.visible !== this.props.visible && this.props.visible !== this.state.selectorVisible) { this.setState({ selectorVisible: this.props.visible }); } } clearSelectedValues(e) { this.setState({ selectedOptions: [] }, () => { if (this.props.onChange) { this.props.onChange([]); } }); utils_1.stopReactPropagation(e); } onOptionMouseEnter(option) { this.setState({ activeOption: option }); } onOptionMouseLeave() { this.setState({ activeOption: undefined }); } onFilterOptionMouseEnter(spread) { this.setState({ activeFilterOptions: spread }); } onFilterOptionMouseLeave() { this.setState({ activeFilterOptions: undefined }); } onTriggerMouseEnterHandler() { this.setState({ showClear: true }); } onTriggerMouseLeaveHandler() { this.setState({ showClear: false }); } onKeyboardOperation(e) { const { selectorVisible, activeOption, selectedOptions, searchValue, optionsTier, activeFilterOptions, renderOptions } = this.state; if (e.keyCode === 9) { return this.setState({ selectorVisible: false }); } if (!selectorVisible) { if (e.keyCode === 13 || e.keyCode === 40) { this.setState({ selectorVisible: true }); e.preventDefault(); } } else { switch (e.keyCode) { case 38: if (!searchValue) { this.setState({ activeOption: tool_1.getPreOption(selectedOptions, renderOptions, optionsTier, activeOption) }); } else { this.setState({ activeFilterOptions: tool_1.getPreFilterOption(renderOptions, activeFilterOptions) }); } e.preventDefault(); break; case 40: if (!searchValue) { this.setState({ activeOption: tool_1.getNextOption(selectedOptions, renderOptions, optionsTier, activeOption) }); } else { this.setState({ activeFilterOptions: tool_1.getNextFilterOption(renderOptions, activeFilterOptions) }); } e.preventDefault(); break; case 13: case 39: if (!searchValue) { if (utils_1.isExist(activeOption)) { const updateTier = optionsTier < selectedOptions.length + 1 ? optionsTier : selectedOptions.length + 1; this.setState({ activeOption: undefined }); this.onSelectHandler(activeOption, updateTier); } } else { if (utils_1.isExist(activeFilterOptions)) { this.onFilterSelectHandler(activeFilterOptions); } } e.preventDefault(); break; case 37: if (!searchValue && selectedOptions.length > 0) { this.setState({ activeOption: undefined }); this.onSelectHandler(undefined, selectedOptions.length); } e.preventDefault(); break; case 27: this.setState({ selectorVisible: false }); e.preventDefault(); break; } } utils_1.stopReactPropagation(e); } onSearchChangeHandler(e) { if (this.props.onSearch) { this.props.onSearch(e.target.value); } this.setState({ searchValue: e.target.value, renderOptions: tool_1.filterOptions(this.props.options, e.target.value, this.props.onFilter) }); utils_1.stopReactPropagation(e); } onSearchFocusHandler(e) { this.setState({ searching: true }); utils_1.stopReactPropagation(e); } onSearchBlurHandler(e) { this.setState({ searching: false }); utils_1.stopReactPropagation(e); } onVisibleChange(v) { this.setState({ selectorVisible: v, searchValue: '', renderOptions: this.props.options }); } onSelectHandler(option, tier) { const { changeOnSelect, onChange } = this.props; const { optionsTier } = this.state; const selectedOptions = [].concat(this.state.selectedOptions); if (tier <= selectedOptions.length) { selectedOptions.splice(tier - 1, selectedOptions.length + 1 - tier); } if (utils_1.isExist(option)) { selectedOptions.push(option); } this.setState({ selectedOptions }, () => { if (onChange) { const values = selectedOptions.map((item) => item.value); if (changeOnSelect) { onChange(values); } else if (selectedOptions.length === this.state.optionsTier) { onChange(values); } } }); if (optionsTier === selectedOptions.length) { this.setState({ selectorVisible: false }); } } onFilterSelectHandler(spread) { this.setState({ selectedOptions: spread }, () => { if (this.props.onChange) { const values = spread.map((item) => item.value); this.props.onChange(values); } }); this.setState({ selectorVisible: false }); } renderDrop(i18nNoDataDescription) { const { mode, noDataDescription, noDataImg, noDataImgStyle, optionTitles, separator } = this.props; const { searchValue, selectedOptions, optionsTier, activeOption, renderOptions, activeFilterOptions } = this.state; const selectorBaseProps = { options: renderOptions, selectedOptions, activeOption, onSelect: this.onSelectHandler, onKeyDown: this.onKeyboardOperation, onOptionMouseEnter: this.onOptionMouseEnter, onOptionMouseLeave: this.onOptionMouseLeave }; return (React.createElement("div", { className: utils_1.preClass('cascader-selector-wrapper') }, renderOptions.length === 0 && searchValue && React.createElement(cascader_not_found_1.default, { noDataImgStyle: noDataImgStyle, noDataImg: noDataImg, noDataDescription: utils_1.isExist(noDataDescription) ? noDataDescription : i18nNoDataDescription }), renderOptions.length > 0 && searchValue && React.createElement(cascader_filter_options_1.default, { options: renderOptions, activeOptions: activeFilterOptions, selectedOptions: selectedOptions, onOptionMouseEnter: this.onFilterOptionMouseEnter, onOptionMouseLeave: this.onFilterOptionMouseLeave, onSelect: this.onFilterSelectHandler, onKeyDown: this.onKeyboardOperation, separator: separator }), mode === 'list' && !searchValue && React.createElement(cascader_list_1.default, Object.assign({}, selectorBaseProps)), mode === 'card' && !searchValue && React.createElement(cascader_card_1.default, Object.assign({ optionsTier: optionsTier }, selectorBaseProps, { optionTitles: optionTitles })))); } render() { const { className, style, showArrow, disabled, externalWheelHide, clearable, tabIndex, changeOnSelect, formatter, separator, searchable, placeholder } = this.props; const { selectorVisible, selectedOptions, showClear, optionsTier, searching, searchValue } = this.state; const amount = selectedOptions.length; const componentClass = classnames_1.default({ [utils_1.preClass('cascader')]: true, [utils_1.preClass('cascader-disabled')]: disabled, [utils_1.preClass('cascader-focused')]: selectorVisible, [className]: utils_1.isExist(className) }); const arrowClass = classnames_1.default({ [utils_1.preClass('cascader-arrow')]: true, [utils_1.preClass('cascader-arrow-active')]: selectorVisible }); const innerClass = classnames_1.default({ [utils_1.preClass('cascader-selection')]: true, [utils_1.preClass('cascader-searching')]: searching }); const searchInputStyle = { display: (selectorVisible ? 'block' : 'none') }; return (React.createElement(dropdown_1.default, { trigger: 'click', content: (React.createElement(receiver_1.default, { module: 'Cascader' }, (i18n) => this.renderDrop(i18n.noDataDescription))), disabled: disabled, visible: selectorVisible, externalWheelHide: externalWheelHide, onVisibleChange: this.onVisibleChange }, React.createElement("div", { onMouseEnter: clearable ? this.onTriggerMouseEnterHandler : null, onMouseLeave: clearable ? this.onTriggerMouseLeaveHandler : null, onKeyDown: disabled ? null : this.onKeyboardOperation, className: componentClass, style: style, tabIndex: disabled ? -1 : tabIndex }, React.createElement("div", { className: innerClass }, (!searchValue && ((amount === 0 && changeOnSelect) || (amount !== optionsTier && !changeOnSelect))) && React.createElement("span", { key: 'placeholder', className: utils_1.preClass('cascader-placeholder') }, utils_1.isExist(placeholder) && placeholder, !utils_1.isExist(placeholder) && React.createElement(receiver_1.default, { module: 'Cascader' }, (i18n) => i18n.placeholder)), !searchValue && React.createElement("span", null, ((amount === optionsTier && !changeOnSelect) || (amount > 0 && changeOnSelect)) && !utils_1.isExist(formatter) && selectedOptions.map((option) => option.value).join(` ${separator} `), ((amount === optionsTier && !changeOnSelect) || (amount > 0 && changeOnSelect)) && utils_1.isExist(formatter) && formatter(selectedOptions)), searchable && React.createElement("input", { placeholder: '', type: 'text', value: searchValue, style: searchInputStyle, className: utils_1.preClass('cascader-search-input'), onFocus: this.onSearchFocusHandler, onChange: this.onSearchChangeHandler, onBlur: this.onSearchBlurHandler, onKeyDown: this.onKeyboardOperation, ref: (ele) => { this.inputElement = ele; } })), showArrow && React.createElement("span", { className: arrowClass }, React.createElement(icon_1.default, { type: 'arrow-down' })), clearable && React.createElement(utils_1.ClearButton, { visible: showClear && (changeOnSelect ? amount > 0 : amount === optionsTier), onClick: this.clearSelectedValues })))); } } Cascader.propTypes = { className: PropTypes.string, style: PropTypes.object, visible: PropTypes.bool, defaultVisible: PropTypes.bool, externalWheelHide: PropTypes.bool, tabIndex: PropTypes.number, options: PropTypes.array.isRequired, optionTitles: PropTypes.array, onChange: PropTypes.func, changeOnSelect: PropTypes.bool, defaultValue: PropTypes.array, value: PropTypes.array, noDataDescription: PropTypes.node, noDataImg: PropTypes.string, noDataImgStyle: PropTypes.object, mode: PropTypes.oneOf(['list', 'card']), placeholder: PropTypes.string, showArrow: PropTypes.bool, disabled: PropTypes.bool, searchable: PropTypes.bool, formatter: PropTypes.func, separator: PropTypes.node, onSearch: PropTypes.func, onFilter: PropTypes.func, clearable: PropTypes.bool }; Cascader.defaultProps = { visible: false, defaultVisible: false, externalWheelHide: true, tabIndex: 0, mode: 'list', changeOnSelect: false, searchable: false, showArrow: true, disabled: false, separator: '/', clearable: false }; exports.default = Cascader;