312 lines
10 KiB
JavaScript
312 lines
10 KiB
JavaScript
import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose";
|
|
import _extends from "@babel/runtime/helpers/esm/extends";
|
|
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 '../utils/shallowEqual';
|
|
import { getUnhandledProps, prefix, defaultProps } from '../utils';
|
|
import DropdownMenuGroup from './DropdownMenuGroup';
|
|
import { KEY_GROUP, KEY_GROUP_TITLE } from '../utils/getDataGroupBy';
|
|
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,
|
|
listProps: PropTypes.object
|
|
};
|
|
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[KEY_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[KEY_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
|
|
*/
|
|
|
|
if (group && item[KEY_GROUP]) {
|
|
var groupValue = item[KEY_GROUP_TITLE];
|
|
return React.createElement(DropdownMenuGroup, {
|
|
style: style,
|
|
classPrefix: this.addPrefix('group'),
|
|
className: classNames({
|
|
folded: foldedGroupKeys.some(function (key) {
|
|
return key === groupValue;
|
|
})
|
|
}),
|
|
key: "group-" + groupValue,
|
|
"data-key": "group-" + groupValue,
|
|
onClick: this.handleGroupTitleClick.bind(null, groupValue)
|
|
}, renderMenuGroup ? renderMenuGroup(groupValue, item) : groupValue);
|
|
} else if (_isUndefined(value) && !_isUndefined(item[KEY_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, {
|
|
"data-key": itemKey,
|
|
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,
|
|
listProps = _this$props4.listProps;
|
|
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[KEY_GROUP_TITLE]);
|
|
}));
|
|
}) : 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, _extends({}, listProps, {
|
|
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); |