UNPKG

shineout

Version:

Shein 前端组件库

643 lines (544 loc) 20.4 kB
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 _extends from "@babel/runtime/helpers/extends"; import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/objectWithoutPropertiesLoose"; import React from 'react'; import immer from 'immer'; import classnames from 'classnames'; import { isFunc } from '../utils/is'; import { PureComponent } from '../component'; import { getUidStr } from '../utils/uid'; import DatumTree from '../Datum/Tree'; import { selectClass } from '../Select/styles'; import { cascaderClass } from './styles'; import Result from './Result'; import CascaderList from './List'; import FilterList from './FilterList'; import { docSize } from '../utils/dom/document'; import { getParent } from '../utils/dom/element'; import absoluteList from '../AnimationList/AbsoluteList'; import { isRTL } from '../config'; import { getKey } from '../utils/uid'; var OptionList = absoluteList(function (_ref) { var focus = _ref.focus, getRef = _ref.getRef, other = _objectWithoutPropertiesLoose(_ref, ["focus", "getRef"]); return focus ? React.createElement("div", _extends({}, other, { ref: getRef })) : null; }); var isDescendent = function isDescendent(el, id) { if (el.getAttribute('data-id') === id) return true; if (!el.parentElement) return false; return isDescendent(el.parentElement, id); }; var DefaultProps = { data: [], height: 300, clearable: true, showArrow: true, expandTrigger: 'click', childrenKey: 'children' }; var Cascader = /*#__PURE__*/ function (_PureComponent) { _inheritsLoose(Cascader, _PureComponent); function Cascader(props) { var _this; _this = _PureComponent.call(this, props) || this; _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "pathChangeTimer", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "datum", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "selectId", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "isRendered", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "lastFoucs", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "shouldUpdateAfterRef", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "ref", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "close", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleBlur", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "handleClick", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "input", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "lastValue", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "element", void 0); _defineProperty(_assertThisInitialized(_assertThisInitialized(_this)), "renderPending", void 0); _this.state = { focus: false, path: [], position: 'drop-down' }; _this.datum = new DatumTree({ data: props.data, loader: props.loader, keygen: props.keygen, mode: props.mode, onChange: props.onChange, value: props.value, disabled: typeof props.disabled === 'function' ? props.disabled : undefined, childrenKey: props.childrenKey || DefaultProps.childrenKey, unmatch: props.unmatch }); _this.isRendered = false; _this.selectId = "select_" + getUidStr(); _this.handleClick = _this.handleState.bind(_assertThisInitialized(_assertThisInitialized(_this)), true); _this.handleBlur = _this.handleState.bind(_assertThisInitialized(_assertThisInitialized(_this)), false); _this.handleFocus = _this.handleFocus.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleKeyDown = _this.handleKeyDown.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleClickAway = _this.handleClickAway.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handlePathChange = _this.handlePathChange.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleClear = _this.handleClear.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.shouldFocus = _this.shouldFocus.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.bindRef = _this.bindRef.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleChange = _this.handleChange.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.bindInput = _this.bindInput.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.handleRemove = _this.handleRemove.bind(_assertThisInitialized(_assertThisInitialized(_this))); _this.close = _this.handleBlur; var componentRef = { close: _this.close }; if (props.getComponentRef) { if (isFunc(props.getComponentRef)) { props.getComponentRef(componentRef); } else { props.getComponentRef.current = componentRef; } } return _this; } var _proto = Cascader.prototype; _proto.componentDidMount = function componentDidMount() { _PureComponent.prototype.componentDidMount.call(this); this.setOpenEvent(); this.updatePathByValue(); if (this.props.mode !== undefined && this.props.loader && [0, 1, 2].includes(this.props.mode)) { console.error(new Error("The mode " + this.props.mode + " is not supported when loader setted. Only 3 or 4 can be set.")); } }; _proto.componentDidUpdate = function componentDidUpdate(prevProps, prevState) { this.datum.mode = this.props.mode; this.datum.updateDisabled(this.props.disabled); this.setOpenEvent(); var _this$props = this.props, onFilter = _this$props.onFilter, filterText = _this$props.filterText; if (prevProps.sourceData !== this.props.sourceData) this.datum.setData(this.props.sourceData, true); if (prevProps.value !== this.props.value) { this.datum.setValue(this.props.value || []); this.updatePathByValue(); } if (prevState.focus !== this.state.focus && !this.state.focus || prevProps.open !== this.props.open && !this.props.open) { if (onFilter) { setTimeout(function () { onFilter(''); }, 400); } if (this.shouldFinal) { this.updatePathByValue(true); } } if (filterText !== undefined && prevProps.filterText !== filterText) { this.updatePath(); } }; _proto.componentWillUnmount = function componentWillUnmount() { _PureComponent.prototype.componentWillUnmount.call(this); 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.bindRef = function bindRef(el) { this.ref = el; }; _proto.bindClickAway = function bindClickAway() { document.addEventListener('mousedown', this.handleClickAway); }; _proto.bindInput = function bindInput(input) { this.input = input; }; _proto.clearClickAway = function clearClickAway() { document.removeEventListener('mousedown', this.handleClickAway); }; _proto.shouldFocus = function shouldFocus(el) { if (el.getAttribute('data-id') === this.selectId) return true; if (getParent(el, "." + cascaderClass('result'))) return true; return false; }; _proto.updatePath = function updatePath() { var _this$props2 = this.props, firstMatchNode = _this$props2.firstMatchNode, keygen = _this$props2.keygen, filterText = _this$props2.filterText; if (!filterText || !firstMatchNode) { this.setState({ path: [] }); return; } var key = getKey(firstMatchNode, keygen); var current = this.datum.getPath(key); if (!current) return; this.setState(immer(function (draft) { draft.path = [].concat(current.path, [key]); })); }; _proto.updatePathByValue = function updatePathByValue(force) { var _this$props3 = this.props, mode = _this$props3.mode, value = _this$props3.value; if (mode !== undefined) return; if (value === this.lastValue && !force) return; if (!value || !value.length) { this.setState({ path: [] }); } else { var v = value[value.length - 1]; var data = this.datum.getDataById(v); if (data === null || this.datum.isUnMatch(data)) return; try { var _ref2 = this.datum.getPath(v) || {}, path = _ref2.path; path = path || []; this.handlePathChange(v, null, path); } catch (e) { console.error(e); } } }; _proto.handleClickAway = function handleClickAway(e) { var desc = isDescendent(e.target, this.selectId); if (!desc) { if (this.props.inputFocus) this.props.onBlur(); this.handleState(false); } }; _proto.handlePathChange = function handlePathChange(id, data, path, fromClick) { var _this2 = this; var _this$props4 = this.props, childrenKey = _this$props4.childrenKey, finalDismiss = _this$props4.finalDismiss, loader = _this$props4.loader; if (fromClick && data && childrenKey) { var leaf = !data[childrenKey] || data[childrenKey].length === 0; if (loader && typeof loader === 'function' && data[childrenKey] === undefined) { leaf = false; } if (finalDismiss && leaf) this.handleState(false); } if (this.pathChangeTimer) { clearTimeout(this.pathChangeTimer); this.pathChangeTimer = null; } this.pathChangeTimer = setTimeout(function () { _this2.setState({ path: [].concat(path, [id]) }); }, 50); }; _proto.handleFocus = function handleFocus(e) { if (!this.shouldFocus(e.target)) return; this.props.onFocus(e); }; _proto.handleClear = function handleClear() { var _this3 = this; var mode = this.props.mode; this.setState({ path: [] }); if (mode !== undefined) this.datum.setValue([]); this.handleChange([]); // force close setTimeout(function () { return _this3.handleState(false); }, 10); }; _proto.handleRemove = function handleRemove(node) { var onChange = this.props.onChange; this.datum.set(this.datum.getKey(node), 0); if (onChange) onChange(this.datum.getValue(), node); }; _proto.handleState = function handleState(focus, e) { if (this.props.disabled === true) return; if (focus === this.focus) return; // click close icon if (focus && e && e.target.classList.contains(cascaderClass('close'))) return; // if remove node, return if (e && getParent(e.target, "." + cascaderClass('remove-container'))) return; var _this$props5 = this.props, _this$props5$height = _this$props5.height, height = _this$props5$height === void 0 ? DefaultProps.height : _this$props5$height, onCollapse = _this$props5.onCollapse; var position = this.props.position; if (!position) { var windowHeight = docSize.height; var bottom = height + this.element.getBoundingClientRect().bottom; if (bottom > windowHeight) position = 'drop-up'; } if (onCollapse) onCollapse(focus); this.setState({ focus: focus, position: position || 'drop-down' }); if (focus) { this.renderPending = false; } }; _proto.handleKeyDown = function handleKeyDown(e) { if (e.keyCode === 13) { e.preventDefault(); this.handleState(!this.focus); } // fot close the list if (e.keyCode === 9) { this.props.onBlur(); // e.preventDefault() if (this.focus) { this.handleState(false); } } }; _proto.handleChange = function handleChange() { var _this$props6 = this.props, onChange = _this$props6.onChange, onFilter = _this$props6.onFilter, mode = _this$props6.mode, emptyAfterSelect = _this$props6.emptyAfterSelect, filterText = _this$props6.filterText; if (this.input) { this.input.reset(); this.input.focus(); } for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } var value = args[0]; this.lastValue = value; if (onChange) { onChange.apply(void 0, args); } if (onFilter && filterText) { if (!(mode !== undefined && !emptyAfterSelect)) { onFilter(''); } } }; _proto.renderList = function renderList() { var _this4 = this; var _this$props7 = this.props, data = _this$props7.data, keygen = _this$props7.keygen, renderItem = _this$props7.renderItem, mode = _this$props7.mode, loader = _this$props7.loader, expandTrigger = _this$props7.expandTrigger, childrenKey = _this$props7.childrenKey, height = _this$props7.height; var path = this.state.path; var props = { datum: this.datum, renderItem: renderItem, keygen: keygen, loader: loader, onPathChange: this.handlePathChange, onChange: this.handleChange, multiple: mode !== undefined, expandTrigger: expandTrigger, childrenKey: childrenKey, shouldFinal: this.shouldFinal }; var tempData = data; var list = [React.createElement(CascaderList, _extends({}, props, { text: undefined, key: "root", data: tempData, id: path[0], parentId: "", path: [] }))]; var childs = path.map(function (p, i) { tempData = tempData && tempData instanceof Array && tempData.find(function (d) { var nid = _this4.datum.getKey(d, path[i - 1]); return nid === p; }); if (tempData && tempData[childrenKey] && tempData[childrenKey].length > 0) { tempData = tempData[childrenKey]; return React.createElement(CascaderList, _extends({}, props, { key: p, text: undefined, data: tempData, id: path[i + 1], parentId: path[i], path: path.slice(0, i + 1) })); } return null; }); if (childs) { list = list.concat(childs); } var listStyle = data && data.length === 0 ? { height: 'auto', width: '100%' } : { height: height }; return React.createElement("div", { ref: this.bindRef, style: listStyle }, list); }; _proto.renderAbsoluteList = function renderAbsoluteList() { var _this$props8 = this.props, absolute = _this$props8.absolute, zIndex = _this$props8.zIndex, renderOptionList = _this$props8.renderOptionList, loading = _this$props8.loading; var position = this.state.position; var focus = this.focus; var className = classnames(selectClass('options'), cascaderClass('options')); var rootClass = classnames(cascaderClass(focus && 'focus', isRTL() && 'rtl'), selectClass(this.state.position)); if (!focus && !this.isRendered) return null; if (!this.element) { this.shouldUpdateAfterRef = true; return null; } this.isRendered = true; var list = this.renderList(); return React.createElement(OptionList, { autoAdapt: true, rootClass: rootClass, className: className, position: position, absolute: absolute, focus: focus, parentElement: this.element, "data-id": this.selectId, zIndex: zIndex }, renderOptionList ? renderOptionList(list, { loading: !!loading }) : list); }; _proto.renderFilterList = function renderFilterList() { var _this$props9 = this.props, absolute = _this$props9.absolute, onFilter = _this$props9.onFilter, wideMatch = _this$props9.wideMatch, filterText = _this$props9.filterText, zIndex = _this$props9.zIndex, data = _this$props9.data, childrenKey = _this$props9.childrenKey, renderItem = _this$props9.renderItem, expandTrigger = _this$props9.expandTrigger, filterDataChange = _this$props9.filterDataChange, height = _this$props9.height, loading = _this$props9.loading, renderOptionList = _this$props9.renderOptionList; var position = this.state.position; var focus = this.focus; var className = classnames(cascaderClass(focus && 'focus', isRTL() && 'rtl'), selectClass(this.state.position)); return React.createElement(FilterList, { shouldFinal: this.shouldFinal, fixed: "min", rootClass: className, position: position, absolute: absolute, focus: focus, parentElement: this.element, "data-id": this.selectId, zIndex: zIndex, data: data, childrenKey: childrenKey, renderItem: renderItem, expandTrigger: expandTrigger, filterDataChange: filterDataChange, datum: this.datum, onChange: this.handleChange, onPathChange: this.handlePathChange, wideMatch: wideMatch, onFilter: onFilter, filterText: filterText, height: height, loading: loading, renderOptionList: renderOptionList }); }; _proto.renderPanel = function renderPanel() { var _this$props10 = this.props, filterText = _this$props10.filterText, data = _this$props10.data, mode = _this$props10.mode, loading = _this$props10.loading; if (loading) return this.renderFilterList(); if (!filterText || filterText && mode !== undefined || data && data.length === 0) return this.renderAbsoluteList(); return this.renderFilterList(); }; _proto.render = function render() { var _this5 = this; var _this$props11 = this.props, placeholder = _this$props11.placeholder, disabled = _this$props11.disabled, size = _this$props11.size, other = _objectWithoutPropertiesLoose(_this$props11, ["placeholder", "disabled", "size"]); var focus = this.focus; var className = classnames(cascaderClass('_', size, focus && 'focus', other.mode !== undefined && 'multiple', disabled === true && 'disabled', isRTL() && 'rtl'), selectClass(this.state.position, focus && 'focus')); return React.createElement("div", { // eslint-disable-next-line tabIndex: disabled === true ? -1 : 0, className: className, onFocus: this.handleFocus, onClick: this.handleClick, "data-id": this.selectId, onKeyDown: this.handleKeyDown, ref: function ref(el) { _this5.element = el; if (el && _this5.shouldUpdateAfterRef) { _this5.shouldUpdateAfterRef = false; _this5.forceUpdate(); } } }, React.createElement(Result, _extends({}, other, { focus: focus, multiple: other.mode !== undefined, datum: this.datum, placeholder: placeholder, onClear: this.handleClear, onPathChange: this.handlePathChange, bindInput: this.bindInput, handleRemove: this.handleRemove, selectId: this.selectId, showList: this.handleClick, size: size })), this.renderPanel()); }; _createClass(Cascader, [{ key: "focus", get: function get() { if ('open' in this.props) { return !!this.props.open; } return this.state.focus; } }, { key: "shouldFinal", get: function get() { var _this$props12 = this.props, expandTrigger = _this$props12.expandTrigger, final = _this$props12.final; return expandTrigger === 'hover-only' || !!final; } }]); return Cascader; }(PureComponent); _defineProperty(Cascader, "defaultProps", DefaultProps); Cascader.defaultProps = { clearable: true, expandTrigger: 'click', height: 300, data: [], childrenKey: 'children', showArrow: true }; export default Cascader;