zent
Version:
一套前端设计语言和基于React的实现
627 lines (626 loc) • 28.8 kB
JavaScript
import { __assign, __extends, __spreadArray } from "tslib";
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
import cx from 'classnames';
import { Component, createRef } from 'react';
import Popover from '../popover';
import TagList from './TagList';
import Option from './Option';
import Search from './Search';
import { DisabledContext } from '../disabled';
import WindowEventHandler from '../utils/component/WindowEventHandler';
import Icon from '../icon';
import { TextMark } from '../text-mark';
import { InlineLoading } from '../loading/InlineLoading';
import { Pop } from '../pop';
import { I18nReceiver as Receiver } from '../i18n';
import memoize from '../utils/memorize-one';
import uniqueId from '../utils/uniqueId';
import { filterReviver, reviveSelectItem } from './reviver';
var uniqueKey = '__ZENT_SELECT_CREATABLE_KEY__';
var SELECT_CREATABLE_KEY = uniqueId(uniqueKey);
function defaultIsEqual(a, b) {
return a.key === b.key;
}
function defaultFilter(keyword, option) {
if (typeof option.text !== 'string') {
return true;
}
return option.text.toLowerCase().includes(keyword.toLowerCase());
}
function defaultRenderOptionList(options, renderOption) {
return options.map(renderOption);
}
function getExtraOptions(value) {
var _a, _b;
if (!Array.isArray(value)) {
if (((_b = (_a = value === null || value === void 0 ? void 0 : value.key) === null || _a === void 0 ? void 0 : _a.toString()) === null || _b === void 0 ? void 0 : _b.indexOf(uniqueKey)) > -1) {
return [value];
}
return [];
}
return value.reduce(function (v, next) {
var _a, _b;
if (((_b = (_a = next === null || next === void 0 ? void 0 : next.key) === null || _a === void 0 ? void 0 : _a.toString()) === null || _b === void 0 ? void 0 : _b.indexOf(uniqueKey)) > -1) {
return __spreadArray(__spreadArray([], v), [next]);
}
return v;
}, []);
}
function isSelectable(item) {
return !!item && !item.disabled && !item.type;
}
function findNextSelectableOption(options, start) {
for (var i = start; i < options.length; i += 1) {
if (isSelectable(options[i])) {
return i;
}
}
return null;
}
function findPrevSelectableOption(options, start) {
for (var i = start; i >= 0; i -= 1) {
if (isSelectable(options[i])) {
return i;
}
}
return null;
}
function defaultHighlight(keyword, option) {
if (typeof option.text !== 'string') {
return option.text;
}
return (_jsx(TextMark, { searchWords: [keyword], textToHighlight: option.text, highlightStyle: { backgroundColor: 'initial', color: '#155bd4' }, autoEscape: true }, void 0));
}
var DEFAULT_LOADING = (_jsx("div", __assign({ className: "zent-select-v2-popup-loading", "data-zv": '10.0.17' }, { children: _jsx(InlineLoading, { loading: true, icon: "circle", iconSize: 18, iconText: "\u52A0\u8F7D\u4E2D\u2026", textPosition: "right", colorPreset: "grey" }, void 0) }), void 0));
function defaultIsValidNewOption(keyword, options) {
return options.every(function (it) {
return (typeof it.text === 'string' ? it.text.toLowerCase() : it.text) !==
keyword.toLowerCase();
});
}
var DEFAULT_TRIGGER_WIDTH = 240;
var DEFAULT_SIZE_WIDTH = 116;
var DEFAULT_PADDING_WIDTH = 8;
var SIZE_MAP = {
xs: DEFAULT_SIZE_WIDTH,
s: DEFAULT_SIZE_WIDTH * 2 + DEFAULT_PADDING_WIDTH,
m: DEFAULT_SIZE_WIDTH * 3 + DEFAULT_PADDING_WIDTH * 2,
l: DEFAULT_SIZE_WIDTH * 4 + DEFAULT_PADDING_WIDTH * 3,
xl: DEFAULT_SIZE_WIDTH * 5 + DEFAULT_PADDING_WIDTH * 4,
};
var Select = (function (_super) {
__extends(Select, _super);
function Select(props) {
var _a, _b;
var _this = _super.call(this, props) || this;
_this.triggerRef = createRef();
_this.popoverRef = createRef();
_this.inputRef = createRef();
_this.onVisibleChange = function (open) {
if (_this.disabled) {
return;
}
var onOpenChange = _this.props.onOpenChange;
if (onOpenChange) {
onOpenChange(open);
}
else {
_this.setState({
open: open,
active: open,
activeIndex: null,
});
}
if (open === false) {
_this.resetKeyword('popup-close');
}
};
_this.onSelect = function (item) {
if (!item || item.disabled || item.type || _this.disabled) {
return;
}
var onCreate = _this.props.onCreate;
var isCreate = item.key === SELECT_CREATABLE_KEY;
if (isCreate && onCreate) {
_this.onCreateClick();
return;
}
isCreate && _this.resetKeyword('option-create');
var valueItem = isCreate ? __assign(__assign({}, item), { key: uniqueId(uniqueKey) }) : item;
if (_this.props.multiple === true) {
var _a = _this.props, onChange = _a.onChange, isEqual_1 = _a.isEqual;
var value = _this.state.value;
var valueIndex_1 = value.findIndex(function (it) { return isEqual_1(it, item); });
_this.focusSearchInput();
var nextValue = valueIndex_1 >= 0
? value.filter(function (_it, index) { return index !== valueIndex_1; })
: value.concat([valueItem]);
if (onChange) {
onChange(nextValue);
}
else {
_this.setState({ value: nextValue });
}
}
else {
_this.onVisibleChange(false);
var onChange = _this.props.onChange;
if (onChange) {
onChange(valueItem);
}
else {
_this.setState({ value: valueItem });
}
}
};
_this.onKeywordChange = function (e) {
if (_this.disabled) {
return;
}
_this.setKeyword(e.target.value, 'user-change');
};
_this.onRemove = function (item) {
if (_this.disabled) {
return;
}
var value = _this.state.value;
var _a = _this.props, onChange = _a.onChange, isEqual = _a.isEqual;
var nextValue = value.filter(function (it) { return !isEqual(item, it); });
_this.focusSearchInput();
if (onChange) {
onChange(nextValue);
}
else {
_this.setState({
value: nextValue,
});
}
};
_this.onOptionMouseEnter = function (index) {
if (_this.disabled) {
return;
}
_this.setState({
activeIndex: index,
});
};
_this.onOptionMouseLeave = function (index) {
if (_this.disabled) {
return;
}
_this.setState(function (state) {
return state.activeIndex === index
? {
activeIndex: null,
}
: null;
});
};
_this.selectCurrentIndex = function () {
var _a;
if (_this.disabled) {
return;
}
var _b = _this.state, activeIndex = _b.activeIndex, keyword = _b.keyword, value = _b.value;
var _c = _this.props, creatable = _c.creatable, _options = _c.options, filter = _c.filter, isValidNewOption = _c.isValidNewOption;
var options = _this.filterOptions(keyword, _options, filter, creatable, isValidNewOption, value);
if (activeIndex !== null) {
_this.onSelect(options[activeIndex]);
}
else {
if (options.length && ((_a = options[0]) === null || _a === void 0 ? void 0 : _a.key) === SELECT_CREATABLE_KEY) {
_this.onSelect(options[0]);
}
}
};
_this.renderOption = function (option, index) {
var _a = _this.props, isEqual = _a.isEqual, multiple = _a.multiple, renderOptionContent = _a.renderOptionContent, highlight = _a.highlight, filter = _a.filter;
var _b = _this.state, value = _b.value, activeIndex = _b.activeIndex, creating = _b.creating;
var selected = !!value &&
(multiple
? value.findIndex(function (it) { return isEqual(it, option); }) >= 0
: isEqual(value, option));
var optionContent = null;
var loading = false;
if (option.key === SELECT_CREATABLE_KEY) {
loading = creating;
optionContent = (_jsx(Receiver, __assign({ componentName: "Select" }, { children: function (i18n) { return (_jsxs("span", __assign({ className: "zent-select-v2-option-text-highlight", "data-zv": '10.0.17' }, { children: [i18n.create, option.text] }), void 0)); } }), void 0));
}
else if (renderOptionContent) {
optionContent = renderOptionContent(option);
}
else {
var keyword = _this.state.keyword.trim();
optionContent =
filter !== false && keyword.length > 0
? highlight === null || highlight === void 0 ? void 0 : highlight(keyword, option)
: option.text;
}
return (_jsx(Option, __assign({ value: option, selected: selected, active: index === activeIndex, onSelect: _this.onSelect, index: index, onMouseEnter: _this.onOptionMouseEnter, onMouseLeave: _this.onOptionMouseLeave, multiple: multiple, loading: loading }, { children: optionContent }), option.key));
};
_this.globalClick = function (e) {
var _a;
if (_this.disabled ||
_this.state.open ||
!_this.state.active ||
!_this.triggerRef.current ||
!_this.popoverRef.current) {
return;
}
if (!((_a = _this.triggerRef.current) === null || _a === void 0 ? void 0 : _a.contains(e.target))) {
_this.setState({
active: false,
});
}
};
_this.onIndexChange = function (delta) {
if (_this.disabled) {
return;
}
_this.setState(function (state, _a) {
var _options = _a.options, creatable = _a.creatable, filter = _a.filter, isValidNewOption = _a.isValidNewOption;
var options = _this.filterOptions(state.keyword, _options, filter, creatable, isValidNewOption, state.value);
var nextIndex;
if (state.activeIndex === null) {
if (delta < 0) {
nextIndex = options.length - 1;
}
else {
nextIndex = 0;
}
}
else {
nextIndex = (state.activeIndex + delta) % options.length;
}
if (nextIndex >= options.length) {
nextIndex = options.length - 1;
}
if (nextIndex < 0) {
nextIndex = 0;
}
if (!isSelectable(options[nextIndex])) {
var enabled = void 0;
if (delta > 0) {
enabled = findNextSelectableOption(options, nextIndex);
}
else {
enabled = findPrevSelectableOption(options, nextIndex);
}
if (!enabled) {
return null;
}
nextIndex = enabled;
}
if (state.activeIndex === nextIndex) {
return null;
}
return {
activeIndex: nextIndex,
};
});
};
_this.onClear = function (e) {
e.stopPropagation();
var keyword = _this.state.keyword;
_this.focusSearchInput();
if (keyword) {
_this.resetKeyword('user-clear');
return;
}
if (_this.props.multiple) {
var onChange = _this.props.onChange;
var value = [];
if (onChange) {
onChange(value);
}
else {
_this.setState({
value: value,
});
}
}
else {
var onChange = _this.props.onChange;
var value = null;
if (onChange) {
onChange(value);
}
else {
_this.setState({
value: value,
});
}
}
};
_this.onCreateClick = function () {
var _a = _this.props, onCreate = _a.onCreate, multiple = _a.multiple;
var keyword = _this.state.keyword;
if (onCreate) {
_this.setState({ creating: true });
onCreate(keyword.trim())
.then(function () {
if (multiple) {
_this.focusSearchInput();
}
else {
_this.onVisibleChange(false);
}
_this.resetKeyword('option-create');
})
.finally(function () {
_this.setState({ creating: false });
});
}
};
_this.filterOptions = memoize(function (keyword, options, filter, creatable, isValidNewOption, value) {
if (options === void 0) { options = []; }
var extraOptions = creatable ? getExtraOptions(value) : [];
var mergedOptions = __spreadArray(__spreadArray([], options), extraOptions);
var filtered = filter !== false && keyword
? mergedOptions.filter(function (it) { return filter === null || filter === void 0 ? void 0 : filter(keyword, it); })
: mergedOptions;
var pendingCreateOption = creatable && keyword && (isValidNewOption === null || isValidNewOption === void 0 ? void 0 : isValidNewOption(keyword, mergedOptions))
? [
{
key: SELECT_CREATABLE_KEY,
text: keyword,
},
]
: [];
return pendingCreateOption.concat(filtered);
});
_this.focusSearchInput = function () {
var _a, _b;
(_b = (_a = _this.inputRef) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.focus();
};
var value;
if (props.multiple) {
value = filterReviver((_a = props.value) !== null && _a !== void 0 ? _a : []);
}
else {
value = filterReviver((_b = props.value) !== null && _b !== void 0 ? _b : null);
}
var keyword = props.keyword, width = props.width, options = props.options, size = props.size;
_this.state = {
keyword: keyword !== null && keyword !== void 0 ? keyword : '',
value: value,
open: false,
active: false,
activeIndex: null,
prevOptions: options,
creating: false,
triggerWidth: width !== null && width !== void 0 ? width : (SIZE_MAP[size] || DEFAULT_TRIGGER_WIDTH),
};
_this.tryReviveOption(props);
return _this;
}
Select.getDerivedStateFromProps = function (props, state) {
var _a;
var nextState = {
prevOptions: props.options,
};
if (typeof props.keyword === 'string') {
nextState.keyword = props.keyword;
}
if (typeof props.open === 'boolean') {
nextState.open = props.open;
nextState.active = props.open;
}
if (props.multiple) {
if (Array.isArray(props.value)) {
nextState.value = filterReviver(props.value);
}
}
else {
if ('value' in props) {
nextState.value = filterReviver((_a = props.value) !== null && _a !== void 0 ? _a : null);
}
}
if (props.options !== state.prevOptions && state.activeIndex !== null) {
if (!props.options.length) {
nextState.activeIndex = null;
}
else {
if (state.activeIndex >= props.options.length) {
nextState.activeIndex = props.options.length - 1;
}
}
}
return nextState;
};
Select.prototype.componentDidMount = function () {
var _a;
if ('popupWidth' in this.props) {
return;
}
var _b = this.props, size = _b.size, width = _b.width;
var sizeWidth = SIZE_MAP[size] || DEFAULT_TRIGGER_WIDTH;
var useWidth = typeof width === 'number' ? width : sizeWidth;
var triggerWidth = ((_a = this.triggerRef.current) === null || _a === void 0 ? void 0 : _a.offsetWidth) || useWidth;
this.setState({
triggerWidth: triggerWidth,
});
};
Select.prototype.componentDidUpdate = function (prevProps) {
if (this.props.options !== prevProps.options ||
this.props.value !== prevProps.value) {
this.tryReviveOption(this.props);
}
};
Object.defineProperty(Select.prototype, "disabled", {
get: function () {
var _a = this.props.disabled, disabled = _a === void 0 ? this.context.value : _a;
return disabled;
},
enumerable: false,
configurable: true
});
Select.prototype.tryReviveOption = function (props) {
var _a, _b, _c, _d;
var options = props.options;
if (props.multiple) {
var value = (_a = props.value) !== null && _a !== void 0 ? _a : [];
var revived_1 = false;
var newValue = value.map(function (v) {
var _a;
if (v.type === 'reviver') {
for (var _i = 0, options_2 = options; _i < options_2.length; _i++) {
var opt = options_2[_i];
var revivedOpt = (_a = v.reviver) === null || _a === void 0 ? void 0 : _a.call(v, opt);
if (revivedOpt) {
revived_1 = true;
return revivedOpt;
}
}
}
return v;
});
if (revived_1) {
if (props.onChange) {
props.onChange(newValue);
}
else {
this.setState({ value: newValue });
}
}
}
else if (props.multiple === false) {
var value = (_b = props.value) !== null && _b !== void 0 ? _b : null;
if ((value === null || value === void 0 ? void 0 : value.type) === 'reviver') {
var revivedOpt = null;
for (var _i = 0, options_1 = options; _i < options_1.length; _i++) {
var opt = options_1[_i];
revivedOpt = (_c = value.reviver) === null || _c === void 0 ? void 0 : _c.call(value, opt);
if (revivedOpt) {
break;
}
}
if (revivedOpt) {
if (props.onChange) {
(_d = props.onChange) === null || _d === void 0 ? void 0 : _d.call(props, revivedOpt);
}
else {
this.setState({ value: revivedOpt });
}
}
}
}
};
Select.prototype.resetKeyword = function (source) {
this.setKeyword('', source);
};
Select.prototype.setKeyword = function (keyword, source) {
var onKeywordChange = this.props.onKeywordChange;
if (onKeywordChange) {
onKeywordChange(keyword, { source: source });
}
else {
this.setState({
keyword: keyword,
});
}
};
Select.prototype.renderValue = function (i18n) {
var _a = this.props, placeholder = _a.placeholder, renderValue = _a.renderValue, multiple = _a.multiple;
var open = this.state.open;
if (multiple) {
var value = this.state.value;
if ((value === null || value === void 0 ? void 0 : value.length) > 0) {
return this.renderTagList(value, i18n);
}
if (open) {
return null;
}
}
else {
if (open) {
return null;
}
var value = this.state.value;
if (value) {
return renderValue ? (renderValue(value)) : (_jsx("span", __assign({ className: "zent-select-v2-text", title: typeof value.text === 'string' ? value.text : '', "data-zv": '10.0.17' }, { children: value.text }), void 0));
}
}
return _jsx("span", __assign({ className: "zent-select-v2-placeholder", "data-zv": '10.0.17' }, { children: placeholder }), void 0);
};
Select.prototype.renderTagCollapsedTrigger = function (value) {
return (_jsxs("span", __assign({ className: "zent-select-v2-tag-collapsed-trigger", "data-zv": '10.0.17' }, { children: ["+", value.length] }), void 0));
};
Select.prototype.renderTagList = function (value, i18n) {
var _a = this.props, renderValue = _a.renderValue, renderTagList = _a.renderTagList, collapsable = _a.collapsable, hideCollapsePop = _a.hideCollapsePop, _b = _a.collapseAt, collapseAt = _b === void 0 ? 1 : _b, renderCollapsedContent = _a.renderCollapsedContent;
var tagsValue = collapsable ? value.slice(0, collapseAt) : value;
var collapsedValue = value.slice(collapseAt);
return (_jsxs(_Fragment, { children: [typeof renderTagList === 'function' ? (renderTagList({
list: value,
onRemove: this.onRemove,
renderValue: renderValue,
})) : (_jsx(TagList, { list: tagsValue, onRemove: this.onRemove, renderValue: renderValue }, void 0)), collapsable &&
collapsedValue.length > 0 &&
(!hideCollapsePop ? (_jsx(Pop, __assign({ trigger: "hover", position: "auto-top-center", cushion: 15, content: _jsx("div", __assign({ className: "zent-select-v2-tag-collapsed-content", "data-zv": '10.0.17' }, { children: _jsx("div", __assign({ "data-zv": '10.0.17' }, { children: typeof renderCollapsedContent === 'function'
? renderCollapsedContent(collapsedValue)
: collapsedValue.map(function (item, index) {
return (_jsxs("span", __assign({ "data-zv": '10.0.17' }, { children: [renderValue ? renderValue(item) : item.text, index !== collapsedValue.length - 1 &&
i18n.tagSeparator] }), item.key));
}) }), void 0) }), void 0) }, { children: this.renderTagCollapsedTrigger(collapsedValue) }), void 0)) : (this.renderTagCollapsedTrigger(collapsedValue)))] }, void 0));
};
Select.prototype.getSearchPlaceholder = function () {
var placeholder = this.props.placeholder;
if (this.props.multiple) {
if (this.state.value.length) {
return '';
}
return placeholder !== null && placeholder !== void 0 ? placeholder : '';
}
var value = this.state.value;
if (!value || typeof value.text !== 'string') {
return placeholder !== null && placeholder !== void 0 ? placeholder : '';
}
return value.text;
};
Select.prototype.renderPopoverContent = function (i18n) {
var _a = this.props, notFoundContent = _a.notFoundContent, renderOptionList = _a.renderOptionList, loading = _a.loading, creatable = _a.creatable, options = _a.options, filter = _a.filter, isValidNewOption = _a.isValidNewOption;
var keyword = this.state.keyword.trim();
var value = this.state.value;
if (loading) {
return DEFAULT_LOADING;
}
var filtered = this.filterOptions(keyword, options, filter, creatable, isValidNewOption, value);
return (filtered === null || filtered === void 0 ? void 0 : filtered.length) ? (renderOptionList(filtered, this.renderOption)) : (_jsx("div", __assign({ className: "zent-select-v2-popup-empty", "data-zv": '10.0.17' }, { children: notFoundContent !== null && notFoundContent !== void 0 ? notFoundContent : i18n.empty }), void 0));
};
Select.prototype.render = function () {
var _this = this;
var _a = this.state, keyword = _a.keyword, visible = _a.open, active = _a.active, value = _a.value, triggerWidth = _a.triggerWidth;
var _b = this.props, inline = _b.inline, width = _b.width, clearable = _b.clearable, multiple = _b.multiple, popupWidth = _b.popupWidth, collapsable = _b.collapsable, className = _b.className, disableSearch = _b.disableSearch, size = _b.size, collapseAt = _b.collapseAt;
var notEmpty = multiple
? Array.isArray(value) && value.length > 0
: value;
var showClear = clearable && !this.disabled && (keyword || notEmpty);
return (_jsxs(_Fragment, { children: [_jsx(Receiver, __assign({ componentName: "Select" }, { children: function (i18n) { return (_jsxs(Popover, __assign({ ref: _this.popoverRef, position: Popover.Position.AutoBottomLeft, visible: visible, onVisibleChange: _this.onVisibleChange, className: "zent-select-v2-popup", style: { width: popupWidth !== null && popupWidth !== void 0 ? popupWidth : triggerWidth }, cushion: 4 }, { children: [_jsx(Popover.Trigger.Click, { children: _jsxs("div", __assign({ ref: _this.triggerRef, className: cx('zent-select-v2', "zent-select-v2-" + size, className, {
'zent-select-v2-inline': inline,
'zent-select-v2-active': active,
'zent-select-v2-visible': visible,
'zent-select-v2-disabled': _this.disabled,
'zent-select-v2-clearable': showClear,
'zent-select-v2-multiple': multiple,
'zent-select-v2-collapsable': collapsable,
'zent-select-v2-collapsable-single': collapseAt === 1,
}), style: { width: width }, onClick: _this.focusSearchInput, "data-zv": '10.0.17' }, { children: [_this.renderValue(i18n), showClear && (_jsx(Icon, { type: "close-circle", onClick: _this.onClear }, void 0)), !disableSearch && visible && (_jsx(Search, { placeholder: _this.getSearchPlaceholder(), value: keyword, autoWidth: multiple, onChange: _this.onKeywordChange, onIndexChange: _this.onIndexChange, onEnter: _this.selectCurrentIndex, ref: _this.inputRef }, void 0)), _jsx(Icon, { type: "down" }, void 0)] }), void 0) }, void 0), _jsx(Popover.Content, { children: _this.renderPopoverContent(i18n) }, void 0)] }), void 0)); } }), void 0), _jsx(WindowEventHandler, { eventName: "click", listener: this.globalClick, options: { capture: true } }, void 0)] }, void 0));
};
Select.defaultProps = {
isEqual: defaultIsEqual,
renderOptionList: defaultRenderOptionList,
filter: defaultFilter,
isValidNewOption: defaultIsValidNewOption,
highlight: defaultHighlight,
size: 's',
multiple: false,
clearable: false,
loading: false,
creatable: false,
};
Select.contextType = DisabledContext;
Select.reviveValue = reviveSelectItem;
return Select;
}(Component));
export { Select };
export default Select;