UNPKG

shineout

Version:

Shein 前端组件库

842 lines (704 loc) 28.1 kB
import _extends from "@babel/runtime/helpers/extends"; import _createClass from "@babel/runtime/helpers/createClass"; import _inheritsLoose from "@babel/runtime/helpers/inheritsLoose"; import _assertThisInitialized from "@babel/runtime/helpers/assertThisInitialized"; import _defineProperty from "@babel/runtime/helpers/defineProperty"; import React from 'react'; import { SUBMIT_TOPIC } from '../Datum/types'; import { PureComponent } from '../component'; import { getUidStr } from '../utils/uid'; import { selectClass } from './styles'; import Result from './Result'; import OptionList from './OptionList'; import OptionTree from './OptionTree'; import BoxList from './BoxList'; import { isObject, isFunc } from '../utils/is'; import { docSize } from '../utils/dom/document'; import { getParent } from '../utils/dom/element'; import { isRTL } from '../config'; import absoluteList from '../AnimationList/AbsoluteList'; import { getDirectionClass } from '../utils/classname'; var WrappedOptionList = absoluteList(OptionList); var WrappedBoxList = absoluteList(BoxList); var WrappedOptionTree = absoluteList(OptionTree); var isResult = function isResult(el, selector) { return getParent(el, selector || "." + selectClass('result')); }; var DefaultValue = { clearable: false, data: [], height: 250, itemsInView: 10, lineHeight: 34, loading: false, multiple: false, renderItem: function renderItem(e) { return e; }, text: {}, compressed: false, trim: true, autoAdapt: false, showArrow: true, focusSelected: true }; var Select = /*#__PURE__*/ function (_PureComponent) { _inheritsLoose(Select, _PureComponent); function Select(props) { var _this; _this = _PureComponent.call(this, props) || this; _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "blurHandler", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "renderPending", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "optionList", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "selectId", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "mouseDown", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "lastResult", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "lastFoucs", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "focusInput", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "inputReset", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "element", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "blured", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "inputBlurTimer", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "lastChangeIsOptionClick", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleRemove", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "inputLocked", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "keyLocked", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "cancelDeleteLockTimer", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "deleteLock", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "forceChange", function () { if (_this.inputBlurTimer && _this.blurHandler) { clearTimeout(_this.inputBlurTimer); _this.blurHandler(); } }); _this.state = { control: 'mouse', focus: false, position: 'drop-down' }; _this.bindElement = _this.bindElement.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.bindOptionFunc = _this.bindOptionFunc.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.setInputReset = _this.setInputReset.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.shouldFocus = _this.shouldFocus.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleClick = _this.handleClick.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleFocus = _this.handleFocus.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleClear = _this.handleClear.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleChange = _this.handleChange.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleRemove = _this.handleChange.bind(_assertThisInitialized(_assertThisInitialized(_this)), false); _this.handleKeyDown = _this.handleKeyDown.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleKeyUp = _this.handleKeyUp.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleInputFocus = _this.handleInputFocus.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleControlChange = _this.handleControlChange.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleClickAway = _this.handleClickAway.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleInputBlur = _this.handleInputBlur.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.bindFocusInputFunc = _this.bindFocusInputFunc.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleFilter = _this.handleFilter.bind(_assertThisInitialized(_assertThisInitialized(_this))); // this.toInputTriggerCollapse = this.toInputTriggerCollapse.bind(this) _this.renderItem = _this.renderItem.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.renderResult = _this.renderResult.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleDelete = _this.handleDelete.bind(_assertThisInitialized(_assertThisInitialized(_this))); // option list not render till first focused _this.renderPending = props.open !== true; _this.optionList = {}; _this.selectId = "select_" + getUidStr(); // this.closeByResult = false _this.mouseDown = false; // this.lastResult = undefined _this.focusInput = null; return _this; } var _proto = Select.prototype; _proto.componentDidMount = function componentDidMount() { _PureComponent.prototype.componentDidMount.call(this); this.setOpenEvent(); var formDatum = this.props.formDatum; if (formDatum) { formDatum.subscribe(SUBMIT_TOPIC, this.forceChange); } }; _proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) { this.setOpenEvent(); var onFilter = this.props.onFilter; // clear filter if (onFilter) { if (prevState.focus !== this.state.focus && !this.state.focus || prevProps.open !== this.props.open && !this.props.open) { setTimeout(function () { onFilter(''); }, 400); } } }; _proto.componentWillUnmount = function componentWillUnmount() { _PureComponent.prototype.componentWillUnmount.call(this); var formDatum = this.props.formDatum; if (formDatum) { formDatum.unsubscribe(SUBMIT_TOPIC, this.forceChange); } this.clearClickAway(); }; _proto.setOpenEvent = function setOpenEvent() { var focus = this.focus || this.props.inputFocus; if (this.lastFoucs !== focus) if (focus) { this.bindClickAway(); } else if (this.lastFoucs !== undefined) { this.clearClickAway(); } this.lastFoucs = focus; }; _proto.getDisabledStatus = function getDisabledStatus() { if (typeof this.props.disabled === 'function') { return this.props.disabled; } return !!this.props.disabled; }; _proto.getFocusSelected = function getFocusSelected() { var _this$props = this.props, reFocus = _this$props.reFocus, focusSelected = _this$props.focusSelected; if (reFocus) return false; return focusSelected; }; _proto.setInputReset = function setInputReset(fn) { this.inputReset = fn; }; // @ts-ignore _proto.isDescendent = function isDescendent(el, id) { // const stay = el.classList.contains(selectClass('input')) || el.classList.contains(selectClass('item')) // if (stay) this.optionsHold = true // if (el.classList.contains(selectClass('result')) && this.optionsHold === null && this.state.focus) { // this.closeByResult = true // this.optionsHold = false // } if (el.getAttribute('data-id') === id) return true; // in label if (el.tagName === 'LABEL' && el.htmlFor && el.contains(this.element) && el.contains(document.getElementById(el.htmlFor))) { return true; } if (!el.parentElement) return false; return this.isDescendent(el.parentElement, id); }; _proto.bindOptionFunc = function bindOptionFunc(name, fn) { this.optionList[name] = fn; }; _proto.bindFocusInputFunc = function bindFocusInputFunc(fn) { this.focusInput = fn; }; _proto.bindElement = function bindElement(el) { this.element = el; }; _proto.bindClickAway = function bindClickAway() { document.addEventListener('click', this.handleClickAway, true); }; _proto.clearClickAway = function clearClickAway() { document.removeEventListener('click', this.handleClickAway, true); }; _proto.handleClickAway = function handleClickAway(e) { var desc = this.isDescendent(e.target, this.selectId); if (!desc) { if (!getParent(e.target, "[data-id=" + this.selectId + "]")) { this.blured = true; this.props.onBlur(); if (this.element) this.element.blur(); } this.handleState(false, null); } }; _proto.handleClick = function handleClick(e) { var _this$props2 = this.props, onCreate = _this$props2.onCreate, onFilter = _this$props2.onFilter; var plain = !onCreate && !onFilter; var target = e.target; if (this.focus) { if (plain && isResult(target) || isResult(target, "." + selectClass('caret'))) { this.handleState(false, e); return; } } this.handleState(true, e); }; _proto.handleState = function handleState(focus, e) { if (this.getDisabledStatus() === true) return; if (focus === this.focus) return; // click close icon if (focus && e && e.target.classList.contains(selectClass('close'))) return; var _this$props3 = this.props, _this$props3$height = _this$props3.height, height = _this$props3$height === void 0 ? DefaultValue.height : _this$props3$height, onCollapse = _this$props3.onCollapse; var position = this.props.position; if (!position) { var windowHeight = docSize.height; var rectElement = this.element.parentElement || this.element; var rect = rectElement.getBoundingClientRect(); // 计算时要算上 marginTop/marginBottom 4 var margin = 4; var bottom = height + rect.bottom + margin; var canDropUp = rect.top > windowHeight - rect.bottom; if (bottom > windowHeight && canDropUp) position = 'drop-up'; } if (onCollapse) onCollapse(focus); this.setState({ focus: focus, position: position || 'drop-down' }); if (focus) { this.blured = false; this.renderPending = false; } }; _proto.handleControlChange = function handleControlChange(control) { if (control !== this.state.control) this.setState({ control: control }); }; _proto.handleChange = function handleChange(_isActive, data, fromInput) { var _this2 = this; var _this$props4 = this.props, datum = _this$props4.datum, multiple = _this$props4.multiple, emptyAfterSelect = _this$props4.emptyAfterSelect, onFilter = _this$props4.onFilter, filterText = _this$props4.filterText, onCreate = _this$props4.onCreate, reFocus = _this$props4.reFocus; if (this.getDisabledStatus() === true) return; // if click option, ignore blur event if (this.inputBlurTimer) { this.lastChangeIsOptionClick = true; clearTimeout(this.inputBlurTimer); this.inputBlurTimer = null; } var unMatchedData = data; if (multiple) { if (isObject(unMatchedData) && unMatchedData.IS_NOT_MATCHED_VALUE) { datum.remove(unMatchedData); } else { var checked = !datum.check(data); if (checked) { datum.add(data); } else { if (fromInput === true) return; datum.remove(data); } if (this.inputReset) this.inputReset(); } } else { datum.set(data); if (!reFocus) this.handleState(false); // let the element focus setTimeout(function () { if (reFocus && _this2.focusInput) _this2.focusInput(true); if (onCreate && _this2.blured) return; if (_this2.element) _this2.element.focus(); }, 10); } if (emptyAfterSelect && onFilter && filterText) onFilter('', 'select'); } // toInputTriggerCollapse(text) { // const { onCreate, datum } = this.props // if (onCreate) { // datum.set(onCreate(text)) // } // this.handleState(true) // } ; _proto.shouldFocus = function shouldFocus(el) { if (el.getAttribute('data-id') === this.selectId) return true; if (getParent(el, "." + selectClass('result'))) return true; return false; }; _proto.handleFocus = function handleFocus(e) { if (!this.shouldFocus(e.target)) return; this.props.onFocus(e); }; _proto.handleInputFocus = function handleInputFocus() { var _this$props5 = this.props, hideCreateOption = _this$props5.hideCreateOption, onCreate = _this$props5.onCreate; this.inputLocked = true; var noHover = onCreate && hideCreateOption; if (this.props.inputable && this.state.control === 'keyboard' && !noHover) { if (this.optionList.handleHover) this.optionList.handleHover(0, true); } }; _proto.handleInputBlur = function handleInputBlur(text) { var _this3 = this; var _this$props6 = this.props, onFilter = _this$props6.onFilter, onCreate = _this$props6.onCreate, multiple = _this$props6.multiple, filterSingleSelect = _this$props6.filterSingleSelect, data = _this$props6.data; if (onFilter && text && filterSingleSelect && data.length === 1) { this.handleChange(false, data[0], false); return; } if (!onCreate) return; if (multiple && !text) return; if (this.lastChangeIsOptionClick) return; this.blurHandler = function () { var retData = onCreate(text); _this3.handleChange(false, retData, true); }; // if click option, ignore input blur this.inputBlurTimer = setTimeout(function () { if (_this3.blurHandler) _this3.blurHandler(); _this3.blurHandler = null; }, 200); }; _proto.handleClear = function handleClear() { this.props.datum.setValue([]); this.element.focus(); if (this.focus === false) { this.forceUpdate(); } else { this.handleState(false); } }; _proto.handleHideOption = function handleHideOption() { var _this$props7 = this.props, datum = _this$props7.datum, innerData = _this$props7.innerData; var checked = datum.check(innerData); if (checked) { if (this.inputReset) this.inputReset(); return; } this.handleChange(true, innerData); }; _proto.handleEnter = function handleEnter() { var _this$props8 = this.props, onCreate = _this$props8.onCreate, hideCreateOption = _this$props8.hideCreateOption; var hoverIndex = this.optionList.getIndex && this.optionList.getIndex(); if (onCreate && hideCreateOption && hoverIndex === -1) { this.handleHideOption(); return; } var data = this.props.data[hoverIndex]; if (!data) { // eslint-disable-next-line prefer-destructuring data = this.props.data[0]; } if (data && !data[this.props.groupKey]) { var checked = !this.props.datum.check(data); this.handleChange(checked, data); if (this.optionList.handleHover) this.optionList.handleHover(hoverIndex); } }; _proto.handleKeyDown = function handleKeyDown(e) { var onEnterExpand = this.props.onEnterExpand; this.keyLocked = true; // just for enter to open the list if ((e.keyCode === 13 || e.keyCode === 40) && !this.focus) { e.preventDefault(); if (typeof onEnterExpand === 'function') { var canOpen = onEnterExpand(e); if (canOpen === false) return; } this.handleClick(e); return; } // fot close the list if (e.keyCode === 9) { this.props.onBlur(e); // e.preventDefault() if (this.focus) this.handleState(false, e);else this.clearClickAway(); return; } // no focus no event if (!this.focus) return; this.handleControlChange('keyboard'); switch (e.keyCode) { case 38: if (this.optionList.hoverMove) this.optionList.hoverMove(-1); e.preventDefault(); break; case 40: if (this.optionList.hoverMove) this.optionList.hoverMove(1); e.preventDefault(); break; case 13: this.handleEnter(); e.preventDefault(); e.stopPropagation(); break; case 8: this.handleDelete(e); break; default: this.lastChangeIsOptionClick = false; } }; _proto.handleKeyUp = function handleKeyUp() { this.keyLocked = false; }; _proto.cancelDeleteLock = function cancelDeleteLock() { var _this4 = this; if (this.cancelDeleteLockTimer) { clearTimeout(this.cancelDeleteLockTimer); } this.cancelDeleteLockTimer = setTimeout(function () { _this4.deleteLock = false; }, 400); }; _proto.handleDelete = function handleDelete(e) { var _this$props9 = this.props, multiple = _this$props9.multiple, inputText = _this$props9.inputText, datum = _this$props9.datum, value = _this$props9.value, data = _this$props9.data; if (!multiple) return; if (inputText) { this.deleteLock = true; } else if (this.deleteLock) { this.cancelDeleteLock(); } if (inputText || this.deleteLock) return; if (!value || Array.isArray(value) && !value.length) return; e.preventDefault(); var raws = Array.isArray(value) ? value : [value]; var values = [].concat(raws); if (isFunc(datum.disabled)) { // find last deleteable value for (var i = values.length - 1; i >= 0; i--) { var item = values[i]; if (!datum.disabled(datum.getDataByValue(data, item))) { values.splice(i, 1); datum.handleChange(values, datum.getDataByValue(data, item), false); return; } } } }; _proto.handleFilter = function handleFilter() { var _this$props10 = this.props, onFilter = _this$props10.onFilter, onCreate = _this$props10.onCreate, hideCreateOption = _this$props10.hideCreateOption; var hideCreate = onCreate && hideCreateOption; if (onCreate && !hideCreateOption) { // 创建选项的时候 选择第一个 if (this.optionList.handleHover) this.optionList.handleHover(0, true); } if (hideCreate) { if (this.optionList.handleHover) this.optionList.handleHover(-1, true); } if (onFilter) { onFilter.apply(void 0, arguments); } }; _proto.renderItem = function renderItem(data, index) { var renderItem = this.props.renderItem; return typeof renderItem === 'function' ? renderItem(data, index) : data[renderItem]; }; _proto.renderResult = function renderResult(data, index) { var renderResult = this.props.renderResult; if (!renderResult) return this.renderItem(data, index); return typeof renderResult === 'function' ? renderResult(data, index) : data[renderResult]; } /** * custom options list header */ ; _proto.renderCustomHeader = function renderCustomHeader() { var header = this.props.header; if (React.isValidElement(header)) return React.createElement("div", { className: selectClass('custom-header') }, header); return null; }; _proto.renderTree = function renderTree() { var position = this.state.position; var optionWidth = this.props.optionWidth; var props = { treeData: this.props.treeData, expanded: this.props.expanded, onExpand: this.props.onExpand, loader: this.props.loader, defaultExpanded: this.props.defaultExpanded, defaultExpandAll: this.props.defaultExpandAll, datum: this.props.datum, keygen: this.props.keygen, multiple: this.props.multiple, text: this.props.text, height: this.props.height, loading: this.props.loading, onFilter: this.props.onFilter, filterText: this.props.filterText, absolute: this.props.absolute, zIndex: this.props.zIndex, childrenKey: this.props.childrenKey, expandIcons: this.props.expandIcons, emptyText: this.props.emptyText, renderOptionList: this.props.renderOptionList, renderItem: this.renderItem }; var style = optionWidth ? { width: optionWidth, display: 'block' } : { display: 'none' }; return React.createElement(WrappedOptionTree, _extends({ onChange: this.handleChange, parentElement: this.element, position: position, rootClass: selectClass(position, isRTL() && 'rtl'), selectId: this.selectId, focus: this.focus, renderPending: this.renderPending, fixed: "min" }, props, { style: style, customHeader: this.renderCustomHeader() })); }; _proto.renderList = function renderList() { var _this$state = this.state, control = _this$state.control, position = _this$state.position; var _this$props11 = this.props, autoAdapt = _this$props11.autoAdapt, value = _this$props11.value, optionWidth = _this$props11.optionWidth; var props = { data: this.props.data, datum: this.props.datum, keygen: this.props.keygen, multiple: this.props.multiple, columns: this.props.columns, columnWidth: this.props.columnWidth, columnsTitle: this.props.columnsTitle, text: this.props.text, itemsInView: this.props.itemsInView || DefaultValue.itemsInView, absolute: this.props.absolute, lineHeight: this.props.lineHeight || DefaultValue.lineHeight, height: this.props.height || DefaultValue.height, loading: this.props.loading, onFilter: this.props.onFilter, filterText: this.props.filterText, zIndex: this.props.zIndex, groupKey: this.props.groupKey, hideCreateOption: this.props.hideCreateOption, emptyText: this.props.emptyText, renderOptionList: this.props.renderOptionList }; var style = optionWidth ? { width: optionWidth } : {}; if (typeof props.columns === 'number' && props.columns >= 1 || props.columns === -1) { return React.createElement(WrappedBoxList, _extends({}, props, { columns: props.columns, style: style, rootClass: selectClass(position, isRTL() && 'rtl'), autoClass: selectClass(autoAdapt && 'auto-adapt'), bindOptionFunc: this.bindOptionFunc, renderPending: this.renderPending, focus: this.focus, selectId: this.selectId, onChange: this.handleChange, renderItem: this.renderItem, parentElement: this.element, position: position, fixed: autoAdapt ? 'min' : true, value: value, customHeader: this.renderCustomHeader() })); } return React.createElement(WrappedOptionList, _extends({}, props, { style: style, autoAdapt: autoAdapt, rootClass: selectClass(position, isRTL() && 'rtl'), autoClass: selectClass(autoAdapt && 'auto-adapt'), bindOptionFunc: this.bindOptionFunc, renderPending: this.renderPending, focus: this.focus, control: control, selectId: this.selectId, onControlChange: this.handleControlChange, onChange: this.handleChange, renderItem: this.renderItem, parentElement: this.element, position: position, fixed: autoAdapt ? 'min' : true, value: value, customHeader: this.renderCustomHeader() })); }; _proto.renderOptions = function renderOptions() { var treeData = this.props.treeData; if (treeData) return this.renderTree(); return this.renderList(); }; _proto.render = function render() { var _this$props12 = this.props, placeholder = _this$props12.placeholder, multiple = _this$props12.multiple, clearable = _this$props12.clearable, size = _this$props12.size, datum = _this$props12.datum, filterText = _this$props12.filterText, onCreate = _this$props12.onCreate, compressed = _this$props12.compressed, compressedBound = _this$props12.compressedBound, trim = _this$props12.trim, renderUnmatched = _this$props12.renderUnmatched, showArrow = _this$props12.showArrow, compressedClassName = _this$props12.compressedClassName, resultClassName = _this$props12.resultClassName, maxLength = _this$props12.maxLength, innerTitle = _this$props12.innerTitle, keygen = _this$props12.keygen, convertBr = _this$props12.convertBr, _this$props12$data = _this$props12.data, data = _this$props12$data === void 0 ? DefaultValue.data : _this$props12$data, onFilter = _this$props12.onFilter, treeData = _this$props12.treeData; var disabled = this.getDisabledStatus(); var className = selectClass('inner', size, this.focus && 'focus', this.state.position, multiple && 'multiple', disabled === true && getDirectionClass('disabled'), !trim && 'pre'); return React.createElement("div", { // eslint-disable-next-line tabIndex: disabled === true ? -1 : 0, ref: this.bindElement, className: className, "data-id": this.selectId, onFocus: this.handleFocus, onClick: this.handleClick, onKeyDown: this.handleKeyDown, onKeyUp: this.handleKeyUp }, React.createElement(Result, { trim: trim, maxLength: maxLength, filterText: filterText, onClear: clearable ? this.handleClear : undefined, onCreate: onCreate, onRemove: this.handleRemove, onFilter: onFilter ? this.handleFilter : undefined, datum: datum, disabled: disabled, focus: this.focus, values: datum.values, getResultByValue: this.props.getResultByValue, multiple: multiple, placeholder: placeholder, renderResult: this.renderResult, renderUnmatched: renderUnmatched, onInputBlur: this.handleInputBlur, onInputFocus: this.handleInputFocus, setInputReset: this.setInputReset, bindFocusInputFunc: this.bindFocusInputFunc // collapse={this.toInputTriggerCollapse} , compressed: compressed, compressedBound: compressedBound, showArrow: showArrow, focusSelected: this.getFocusSelected(), compressedClassName: compressedClassName, resultClassName: resultClassName, innerTitle: innerTitle, keygen: keygen, data: treeData || data, convertBr: convertBr }), this.renderOptions()); }; _createClass(Select, [{ key: "focus", get: function get() { if ('open' in this.props) { return !!this.props.open; } return this.state.focus; } }]); return Select; }(PureComponent); _defineProperty(Select, "defaultProps", DefaultValue); export default Select;