rsuite
Version:
A suite of react components
306 lines (263 loc) • 10.5 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
import _inheritsLoose from "@babel/runtime/helpers/esm/inheritsLoose";
import _findIndex from "lodash/findIndex";
import _isNumber from "lodash/isNumber";
import _isString from "lodash/isString";
import _isUndefined from "lodash/isUndefined";
import * as React from 'react';
import PropTypes from 'prop-types';
import { getPosition, scrollTop, getHeight } from 'dom-lib';
import classNames from 'classnames';
import List from 'react-virtualized/dist/commonjs/List';
import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer';
import { shallowEqual } from 'rsuite-utils/lib/utils';
import { getUnhandledProps, prefix, defaultProps } from '../utils';
import DropdownMenuGroup from './DropdownMenuGroup';
export var dropdownMenuPropTypes = {
classPrefix: PropTypes.string,
className: PropTypes.string,
dropdownMenuItemComponentClass: PropTypes.elementType,
dropdownMenuItemClassPrefix: PropTypes.string,
data: PropTypes.array,
group: PropTypes.bool,
disabledItemValues: PropTypes.array,
activeItemValues: PropTypes.array,
focusItemValue: PropTypes.any,
maxHeight: PropTypes.number,
valueKey: PropTypes.string,
labelKey: PropTypes.string,
style: PropTypes.object,
renderMenuItem: PropTypes.func,
renderMenuGroup: PropTypes.func,
onSelect: PropTypes.func,
onGroupTitleClick: PropTypes.func,
virtualized: PropTypes.bool
};
var ROW_HEIGHT = 36;
var DropdownMenu =
/*#__PURE__*/
function (_React$Component) {
_inheritsLoose(DropdownMenu, _React$Component);
function DropdownMenu(props) {
var _this;
_this = _React$Component.call(this, props) || this;
_this.menuBodyContainerRef = void 0;
_this.addPrefix = function (name) {
return prefix(_this.props.classPrefix)(name);
};
_this.handleSelect = function (item, value, event, checked) {
var _this$props$onSelect, _this$props;
(_this$props$onSelect = (_this$props = _this.props).onSelect) === null || _this$props$onSelect === void 0 ? void 0 : _this$props$onSelect.call(_this$props, value, item, event, checked);
};
_this.getItemData = function (itemData) {
return itemData;
};
_this.menuItems = {};
_this.bindMenuItems = function (disabled, key, ref) {
if (ref && !disabled) {
_this.menuItems[key] = ref;
}
};
_this.handleGroupTitleClick = function (key, event) {
var _this$props$onGroupTi, _this$props2;
var foldedGroupKeys = _this.state.foldedGroupKeys;
var nextGroupKeys = foldedGroupKeys.filter(function (item) {
return item !== key;
});
if (nextGroupKeys.length === foldedGroupKeys.length) {
nextGroupKeys.push(key);
}
_this.setState({
foldedGroupKeys: nextGroupKeys
});
(_this$props$onGroupTi = (_this$props2 = _this.props).onGroupTitleClick) === null || _this$props$onGroupTi === void 0 ? void 0 : _this$props$onGroupTi.call(_this$props2, event);
};
_this.menuBodyContainerRef = React.createRef();
_this.state = {
foldedGroupKeys: []
};
return _this;
}
var _proto = DropdownMenu.prototype;
_proto.componentDidMount = function componentDidMount() {
this.updateScrollPoistion();
};
_proto.componentDidUpdate = function componentDidUpdate(prevProps) {
if (!shallowEqual(prevProps.focusItemValue, this.props.focusItemValue)) {
this.updateScrollPoistion();
}
};
_proto.updateScrollPoistion = function updateScrollPoistion() {
var container = this.menuBodyContainerRef.current;
var activeItem = container.querySelector("." + this.addPrefix('item-focus'));
if (!activeItem) {
activeItem = container.querySelector("." + this.addPrefix('item-active'));
}
if (!activeItem) {
return;
}
var position = getPosition(activeItem, container);
var sTop = scrollTop(container);
var sHeight = getHeight(container);
if (sTop > position.top) {
scrollTop(container, Math.max(0, position.top - 20));
} else if (position.top > sTop + sHeight) {
scrollTop(container, Math.max(0, position.top - sHeight + 32));
}
};
_proto.getRowHeight = function getRowHeight(list, _ref) {
var index = _ref.index;
var item = list[index];
if (this.props.group && item.group && index !== 0) {
return 48;
}
return ROW_HEIGHT;
}
/**
* public: Provided to Picker calls, support keyboard operation to get focus.
*/
;
_proto.renderItem = function renderItem(list, _ref2) {
var index = _ref2.index,
style = _ref2.style;
var _this$props3 = this.props,
valueKey = _this$props3.valueKey,
labelKey = _this$props3.labelKey,
group = _this$props3.group,
renderMenuGroup = _this$props3.renderMenuGroup,
disabledItemValues = _this$props3.disabledItemValues,
activeItemValues = _this$props3.activeItemValues,
focusItemValue = _this$props3.focusItemValue,
renderMenuItem = _this$props3.renderMenuItem,
dropdownMenuItemClassPrefix = _this$props3.dropdownMenuItemClassPrefix,
DropdownMenuItem = _this$props3.dropdownMenuItemComponentClass;
var foldedGroupKeys = this.state.foldedGroupKeys;
var item = list[index];
var value = item[valueKey];
var label = item[labelKey];
if (_isUndefined(label) && !item.group) {
throw Error("labelKey \"" + labelKey + "\" is not defined in \"data\" : " + index);
} // Use `value` in keys when If `value` is string or number
var itemKey = _isString(value) || _isNumber(value) ? value : index;
/**
* Render <DropdownMenuGroup>
* when if `group` is enabled and `itme.children` is array
*/
if (group && item.group) {
return React.createElement(DropdownMenuGroup, {
style: style,
classPrefix: this.addPrefix('group'),
className: classNames({
folded: foldedGroupKeys.some(function (key) {
return key === item.groupTitle;
})
}),
key: item.groupTitle,
onClick: this.handleGroupTitleClick.bind(null, item.groupTitle)
}, renderMenuGroup ? renderMenuGroup(item.groupTitle, item) : item.groupTitle);
} else if (_isUndefined(value) && !_isUndefined(item.group)) {
throw Error("valueKey \"" + valueKey + "\" is not defined in \"data\" : " + index + " ");
}
var disabled = disabledItemValues === null || disabledItemValues === void 0 ? void 0 : disabledItemValues.some(function (disabledValue) {
return shallowEqual(disabledValue, value);
});
var active = activeItemValues === null || activeItemValues === void 0 ? void 0 : activeItemValues.some(function (v) {
return shallowEqual(v, value);
});
var focus = !_isUndefined(focusItemValue) && shallowEqual(focusItemValue, value);
return React.createElement(DropdownMenuItem, {
style: style,
key: itemKey,
disabled: disabled,
active: active,
focus: focus,
value: value,
classPrefix: dropdownMenuItemClassPrefix,
getItemData: this.getItemData.bind(this, item),
ref: this.bindMenuItems.bind(this, disabled, itemKey),
onSelect: this.handleSelect.bind(this, item)
}, renderMenuItem ? renderMenuItem(label, item) : label);
};
_proto.renderMenuItems = function renderMenuItems() {
var _this2 = this;
this.menuItems = {};
var _this$props4 = this.props,
_this$props4$data = _this$props4.data,
data = _this$props4$data === void 0 ? [] : _this$props4$data,
group = _this$props4.group,
maxHeight = _this$props4.maxHeight,
activeItemValues = _this$props4.activeItemValues,
valueKey = _this$props4.valueKey,
virtualized = _this$props4.virtualized;
var foldedGroupKeys = this.state.foldedGroupKeys;
var filteredItems = group ? data.filter(function (item) {
return !(foldedGroupKeys === null || foldedGroupKeys === void 0 ? void 0 : foldedGroupKeys.some(function (key) {
var _item$parent;
return key === ((_item$parent = item.parent) === null || _item$parent === void 0 ? void 0 : _item$parent.groupTitle);
}));
}) : data;
var rowCount = filteredItems.length;
if (virtualized && rowCount * ROW_HEIGHT > maxHeight) {
return React.createElement(AutoSizer, {
defaultHeight: maxHeight,
style: {
width: 'auto',
height: 'auto'
}
}, function (_ref3) {
var height = _ref3.height,
width = _ref3.width;
return React.createElement(List, {
width: width,
height: height || maxHeight,
scrollToIndex: _findIndex(data, function (item) {
return item[valueKey] === (activeItemValues === null || activeItemValues === void 0 ? void 0 : activeItemValues[0]);
}),
rowCount: rowCount,
rowHeight: _this2.getRowHeight.bind(_this2, filteredItems),
rowRenderer: _this2.renderItem.bind(_this2, filteredItems)
});
});
}
return React.createElement(React.Fragment, null, filteredItems.map(function (_item, index) {
return _this2.renderItem(filteredItems, {
index: index
});
}));
};
_proto.render = function render() {
var _this$props5 = this.props,
maxHeight = _this$props5.maxHeight,
className = _this$props5.className,
style = _this$props5.style,
group = _this$props5.group,
rest = _objectWithoutPropertiesLoose(_this$props5, ["maxHeight", "className", "style", "group"]);
var classes = classNames(className, this.addPrefix('items'), {
grouped: group
});
var unhandled = getUnhandledProps(DropdownMenu, rest);
var styles = _extends({}, style, {
maxHeight: maxHeight
});
return React.createElement("div", _extends({
role: "list",
className: classes,
ref: this.menuBodyContainerRef,
style: styles
}, unhandled), this.renderMenuItems());
};
return DropdownMenu;
}(React.Component);
DropdownMenu.propTypes = dropdownMenuPropTypes;
DropdownMenu.defaultProps = {
data: [],
activeItemValues: [],
disabledItemValues: [],
maxHeight: 320,
valueKey: 'value',
labelKey: 'label'
};
export default defaultProps({
classPrefix: 'dropdown-menu'
})(DropdownMenu);