@douyinfe/semi-ui
Version:
A modern, comprehensive, flexible design system and UI library. Connect DesignOps & DevOps. Quickly build beautiful React apps. Maintained by Douyin-fe team.
389 lines (388 loc) • 13.6 kB
JavaScript
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _includes2 = _interopRequireDefault(require("lodash/includes"));
var _react = _interopRequireWildcard(require("react"));
var _classnames = _interopRequireDefault(require("classnames"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _constants = require("@douyinfe/semi-foundation/lib/cjs/cascader/constants");
var _isEnterPress = _interopRequireDefault(require("@douyinfe/semi-foundation/lib/cjs/utils/isEnterPress"));
var _context = _interopRequireDefault(require("../configProvider/context"));
var _localeConsumer = _interopRequireDefault(require("../locale/localeConsumer"));
var _semiIcons = require("@douyinfe/semi-icons");
var _spin = _interopRequireDefault(require("../spin"));
var _checkbox = _interopRequireDefault(require("../checkbox"));
var _reactWindow = require("react-window");
var _virtualRow = _interopRequireDefault(require("./virtualRow"));
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const prefixcls = _constants.cssClasses.PREFIX_OPTION;
class Item extends _react.PureComponent {
constructor() {
var _this;
super(...arguments);
_this = this;
this.onClick = (e, item) => {
const {
onItemClick
} = this.props;
if (item.data.disabled || 'disabled' in item && item.disabled) {
return;
}
onItemClick(e, item);
};
/**
* A11y: simulate item click
*/
this.handleItemEnterPress = (keyboardEvent, item) => {
if ((0, _isEnterPress.default)(keyboardEvent)) {
this.onClick(keyboardEvent, item);
}
};
this.onHover = (e, item) => {
const {
showNext,
onItemHover
} = this.props;
if (item.data.disabled) {
return;
}
if (showNext === _constants.strings.SHOW_NEXT_BY_HOVER) {
onItemHover(e, item);
}
};
this.onCheckboxChange = (e, item) => {
const {
onItemCheckboxClick
} = this.props;
// Prevent Checkbox's click event bubbling to trigger the li click event
e.stopPropagation();
if (e.nativeEvent && typeof e.nativeEvent.stopImmediatePropagation === 'function') {
e.nativeEvent.stopImmediatePropagation();
}
onItemCheckboxClick(item);
};
this.getItemStatus = key => {
const {
activeKeys,
selectedKeys,
loadedKeys,
loadingKeys
} = this.props;
const state = {
active: false,
selected: false,
loading: false
};
if (activeKeys.has(key)) {
state.active = true;
}
if (selectedKeys.has(key)) {
state.selected = true;
}
if (loadingKeys.has(key) && !loadedKeys.has(key)) {
state.loading = true;
}
return state;
};
this.renderIcon = function (type) {
let haveMarginLeft = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
const finalCls = style => {
return style + (haveMarginLeft ? ` ${prefixcls}-icon-left` : '');
};
switch (type) {
case 'child':
const {
expandIcon
} = _this.props;
if (expandIcon) {
return expandIcon;
}
return /*#__PURE__*/_react.default.createElement(_semiIcons.IconChevronRight, {
className: finalCls(`${prefixcls}-icon ${prefixcls}-icon-expand`)
});
case 'tick':
return /*#__PURE__*/_react.default.createElement(_semiIcons.IconTick, {
className: finalCls(`${prefixcls}-icon ${prefixcls}-icon-active`)
});
case 'loading':
return /*#__PURE__*/_react.default.createElement(_spin.default, {
wrapperClassName: finalCls(`${prefixcls}-spin-icon`)
});
case 'empty':
return /*#__PURE__*/_react.default.createElement("span", {
"aria-hidden": true,
className: finalCls(`${prefixcls}-icon ${prefixcls}-icon-empty`)
});
default:
return null;
}
};
this.highlight = searchText => {
const content = [];
const {
keyword,
separator
} = this.props;
searchText.forEach((item, idx) => {
if (typeof item === 'string' && (0, _includes2.default)(item, keyword)) {
item.split(keyword).forEach((node, index) => {
if (index > 0) {
content.push(/*#__PURE__*/_react.default.createElement("span", {
className: `${prefixcls}-label-highlight`,
key: `${index}-${idx}`
}, keyword));
}
content.push(node);
});
} else {
content.push(item);
}
if (idx !== searchText.length - 1) {
content.push(separator);
}
});
return content;
};
this.renderFlattenOptionItem = (data, index, style) => {
var _a;
const {
multiple,
selectedKeys,
checkedKeys,
halfCheckedKeys,
keyword,
filterRender,
virtualize
} = this.props;
const {
searchText,
key,
disabled,
pathData
} = data;
const selected = selectedKeys.has(key);
const className = (0, _classnames.default)(prefixcls, {
[`${prefixcls}-flatten`]: true && !filterRender,
[`${prefixcls}-disabled`]: disabled,
[`${prefixcls}-select`]: selected && !multiple
});
const onClick = e => {
this.onClick(e, data);
};
const onKeyPress = e => this.handleItemEnterPress(e, data);
const onCheck = e => this.onCheckboxChange(e, data);
if (filterRender) {
const props = {
className,
inputValue: keyword,
disabled,
data: pathData,
checkStatus: {
checked: checkedKeys.has(data.key),
halfChecked: halfCheckedKeys.has(data.key)
},
selected,
onClick,
onCheck
};
const item = filterRender(props);
const otherProps = virtualize ? {
key,
style: Object.assign(Object.assign({}, (_a = item.props.style) !== null && _a !== void 0 ? _a : {}), style)
} : {
key
};
return /*#__PURE__*/_react.default.cloneElement(item, otherProps);
}
return /*#__PURE__*/_react.default.createElement("li", {
role: 'menuitem',
className: className,
style: style,
key: key,
onClick: onClick,
onKeyPress: onKeyPress
}, /*#__PURE__*/_react.default.createElement("span", {
className: `${prefixcls}-label`
}, !multiple && this.renderIcon('empty'), multiple && (/*#__PURE__*/_react.default.createElement(_checkbox.default, {
onChange: onCheck,
disabled: disabled,
indeterminate: halfCheckedKeys.has(data.key),
checked: checkedKeys.has(data.key),
className: `${prefixcls}-label-checkbox`
})), this.highlight(searchText)));
};
this.renderFlattenOption = data => {
const {
virtualize
} = this.props;
const content = /*#__PURE__*/_react.default.createElement("ul", {
className: `${prefixcls}-list`,
key: 'flatten-list'
}, virtualize ? this.renderVirtualizeList(data) : data.map(item => this.renderFlattenOptionItem(item)));
return content;
};
this.renderVirtualizeList = visibleOptions => {
var _a;
const {
direction
} = this.context;
const {
virtualize
} = this.props;
return /*#__PURE__*/_react.default.createElement(_reactWindow.FixedSizeList, {
height: virtualize.height,
itemCount: visibleOptions.length,
itemSize: virtualize.itemSize,
itemData: {
visibleOptions,
renderOption: this.renderFlattenOptionItem
},
width: (_a = virtualize.width) !== null && _a !== void 0 ? _a : '100%',
style: {
direction
}
}, _virtualRow.default);
};
}
renderItem(renderData) {
let content = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
const {
multiple,
checkedKeys,
halfCheckedKeys
} = this.props;
let showChildItem;
const ind = content.length;
content.push(/*#__PURE__*/_react.default.createElement("ul", {
role: 'menu',
className: `${prefixcls}-list`,
key: renderData[0].key,
onScroll: e => this.props.onListScroll(e, ind)
}, renderData.map(item => {
const {
data,
key,
parentKey
} = item;
const {
children,
label,
disabled,
isLeaf
} = data;
const {
active,
selected,
loading
} = this.getItemStatus(key);
const hasChild = Boolean(children) && children.length;
const showExpand = hasChild || this.props.loadData && !isLeaf;
if (active && hasChild) {
showChildItem = item;
}
const className = (0, _classnames.default)(prefixcls, {
[`${prefixcls}-active`]: active && !selected,
[`${prefixcls}-select`]: selected && !multiple,
[`${prefixcls}-disabled`]: disabled
});
const otherAriaProps = parentKey ? {
['aria-owns']: `cascaderItem-${parentKey}`
} : {};
return /*#__PURE__*/_react.default.createElement("li", Object.assign({
role: 'menuitem',
id: `cascaderItem-${key}`,
"aria-expanded": active,
"aria-haspopup": Boolean(showExpand),
"aria-disabled": disabled
}, otherAriaProps, {
className: className,
key: key,
onClick: e => {
this.onClick(e, item);
},
onKeyPress: e => this.handleItemEnterPress(e, item),
onMouseEnter: e => {
this.onHover(e, item);
}
}), /*#__PURE__*/_react.default.createElement("span", {
className: `${prefixcls}-label`
}, selected && !multiple && this.renderIcon('tick'), !selected && !multiple && this.renderIcon('empty'), multiple && (/*#__PURE__*/_react.default.createElement(_checkbox.default, {
onChange: e => this.onCheckboxChange(e, item),
disabled: disabled,
indeterminate: halfCheckedKeys.has(item.key),
checked: checkedKeys.has(item.key),
className: `${prefixcls}-label-checkbox`
})), /*#__PURE__*/_react.default.createElement("span", null, label)), showExpand ? this.renderIcon(loading ? 'loading' : 'child', true) : null);
})));
if (showChildItem) {
content.concat(this.renderItem(showChildItem.children, content));
}
return content;
}
renderEmpty() {
const {
emptyContent
} = this.props;
if (emptyContent === null) {
return null;
}
return /*#__PURE__*/_react.default.createElement(_localeConsumer.default, {
componentName: "Cascader"
}, locale => (/*#__PURE__*/_react.default.createElement("ul", {
className: `${prefixcls} ${prefixcls}-empty`,
key: 'empty-list'
}, /*#__PURE__*/_react.default.createElement("span", {
className: `${prefixcls}-label`,
"x-semi-prop": "emptyContent"
}, emptyContent || locale.emptyText))));
}
render() {
const {
data,
searchable
} = this.props;
const {
direction
} = this.context;
const isEmpty = !data || !data.length;
let content;
const listsCls = (0, _classnames.default)({
[`${prefixcls}-lists`]: true,
[`${prefixcls}-lists-rtl`]: direction === 'rtl',
[`${prefixcls}-lists-empty`]: isEmpty
});
if (isEmpty) {
content = this.renderEmpty();
} else {
content = searchable ? this.renderFlattenOption(data) : this.renderItem(data);
}
return /*#__PURE__*/_react.default.createElement("div", {
className: listsCls
}, content);
}
}
exports.default = Item;
Item.contextType = _context.default;
Item.propTypes = {
data: _propTypes.default.array,
emptyContent: _propTypes.default.node,
searchable: _propTypes.default.bool,
onItemClick: _propTypes.default.func,
onItemHover: _propTypes.default.func,
multiple: _propTypes.default.bool,
showNext: _propTypes.default.oneOf([_constants.strings.SHOW_NEXT_BY_CLICK, _constants.strings.SHOW_NEXT_BY_HOVER]),
checkedKeys: _propTypes.default.object,
halfCheckedKeys: _propTypes.default.object,
onItemCheckboxClick: _propTypes.default.func,
separator: _propTypes.default.string,
keyword: _propTypes.default.string,
virtualize: _propTypes.default.object,
expandIcon: _propTypes.default.node
};
Item.defaultProps = {
empty: false
};
;