ffr-components
Version:
Fiori styled UI components
502 lines (434 loc) • 15 kB
JavaScript
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _possibleConstructorReturn from "@babel/runtime/helpers/esm/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime/helpers/esm/getPrototypeOf";
import _inherits from "@babel/runtime/helpers/esm/inherits";
import React, { Component } from 'react';
import classnames from 'classnames';
import Modal from '../modal-dialog';
import ComboboxInput from '../combobox-input';
import ListGroup from '../list-group';
import Button from '../button';
import { FocusConsumer } from '../modal-dialog';
import util, { isMobile, isClickedKey, KeyCode } from '../utils';
import "./style.css";
import "../theme/theme.css";
export var MODE = {
combobox: 'combobox',
select: 'select'
};
var Combobox =
/*#__PURE__*/
function (_Component) {
_inherits(Combobox, _Component);
function Combobox(props) {
var _this;
_classCallCheck(this, Combobox);
_this = _possibleConstructorReturn(this, _getPrototypeOf(Combobox).call(this, props));
_this.findSelectedContent = function (id) {
var itemList = _this.props.itemList;
if (id) {
var selectedItem = itemList.find(function (item) {
return item.id === id;
});
return selectedItem ? selectedItem.text : '';
}
return '';
};
_this.inputKeyDownHandler = function (e) {
if (e.nativeEvent.altKey && (e.keyCode === KeyCode.DOWN || e.keyCode === KeyCode.UP)) {
e.preventDefault();
_this.trigger(e);
_this.popoverRef.current.triggerBody();
} else {
if (_this.groupRef.current) {
if ([KeyCode.DOWN, KeyCode.UP].indexOf(e.keyCode) >= 0) {
// this.groupRef.current.moveDownFocus();
var currentIndex = e.keyCode === KeyCode.UP ? _this.shownList.length - 1 : 0;
_this.groupRef.current.focusToList(currentIndex);
_this.setState({
inputValue: _this.shownList[currentIndex].text
});
} else if (e.keyCode === KeyCode.ENTER) {
if (e.target.tagName.toLowerCase() !== 'button') {
_this._onClose();
}
}
}
}
};
_this.onSelect = function (e, cnt) {
var onChange = _this.props.onChange;
if (_this.isMobile) {
_this.currentMobileSelection = cnt;
_this.setState({
disableChoose: false
});
} else {
_this.setState({
inputValue: cnt.text
});
_this._onClose();
_this.inputRef.current.focus();
if (onChange) {
onChange(e, cnt.id);
}
}
};
_this.onChooseOnMobile = function (e) {
e.stopPropagation();
var onChange = _this.props.onChange;
if (_this.currentMobileSelection) {
_this.setState({
inputValue: _this.currentMobileSelection.text,
showMobileMode: false,
disableChoose: true
});
if (onChange) {
onChange(e, _this.currentMobileSelection.id);
}
_this.currentMobileSelection = null;
}
};
_this.onInputChange = function (e) {
var mode = _this.props.mode;
if (mode === MODE.combobox) {
var value = e.target.value;
if (value !== _this.state.inputValue) {
_this.setState({
inputValue: value
});
if (!_this.groupRef.current) {
_this.popoverRef.current.triggerBody();
}
_this.filterList(value);
}
}
};
_this.trigger = function (e) {
// dynamic change list maxHeight
var disabled = _this.props.disabled;
if (disabled) return;
if (_this.isMobile) {
_this.setState({
showMobileMode: true
});
} else {
var delta = 50;
var target = e.currentTarget;
var clientHeight = window.innerHeight;
var _target$getBoundingCl = target.getBoundingClientRect(),
upper = _target$getBoundingCl.top,
height = _target$getBoundingCl.height;
var maxLength = Math.max(clientHeight - upper - height, upper) - delta;
maxLength = Math.abs(maxLength);
var inputRef = _this.inputRef.current;
var _inputRef$parentNode = inputRef.parentNode,
clientWidth = _inputRef$parentNode.clientWidth,
scrollWidth = _inputRef$parentNode.scrollWidth;
var menuWidth = Math.max(clientWidth, scrollWidth);
_this.setState({
menuMaxHeight: maxLength,
menuWidth: menuWidth
});
}
};
_this.onKeyTriggerMobile = function (e) {
if (isClickedKey(e.keyCode)) {
_this.trigger(e);
}
};
_this.onCloseMobile = function () {
if (_this.isMobile) {
_this.setState({
showMobileMode: false,
disableChoose: true
});
_this.currentMobileSelection = null;
}
};
_this._onClose = function () {
_this.popoverRef.current.handleOutsideClick();
};
_this.handleListKeyDown = function (e, keyCode, currentIndex) {
if ([KeyCode.UP, KeyCode.DOWN].indexOf(keyCode) >= 0) {
_this.setState({
inputValue: _this.shownList[currentIndex].text
});
} else if (keyCode === KeyCode.ENTER) {
_this.onSelect(e, _this.shownList[currentIndex]);
}
};
_this.shouldFilterText = function (mode, val) {
return !_this.isMobile && mode === MODE.combobox && !util.isUndefined(val);
};
_this.filterList = function (inputValue) {
var _this$props = _this.props,
itemList = _this$props.itemList,
mode = _this$props.mode;
if (!_this.shouldFilterText(mode, inputValue)) {
_this.shownList = itemList;
} else {
_this.shownList = itemList.filter(function (item) {
if (util.isFunction(item.filter) && item.filter(inputValue)) {
return true;
}
if (!util.isUndefined(item.text) && String(item.text).startsWith(inputValue)) {
return true;
}
return false;
});
}
};
_this.renderList = function (width) {
var value = _this.props.value;
var menuMaxHeight = _this.state.menuMaxHeight;
var style = width ? {
width: width,
maxHeight: "".concat(menuMaxHeight, "px"),
overflow: 'auto'
} : undefined;
var showValue = value;
return React.createElement(ListGroup, {
ref: _this.groupRef,
style: style,
currentSelection: !_this.isMobile ? showValue : null,
handleKeyDown: _this.handleListKeyDown,
className: "ffr-combobox"
}, _this.shownList.map(function (item) {
var id = item.id,
text = item.text,
renderer = item.renderer;
if (util.isUndefined(id) && util.isFunction(renderer)) {
var _item2 = renderer();
if (_item2.props.action) {
var originClick = _item2.props.onClick;
return React.createElement(ListGroup.Item, null, React.cloneElement(_item2, {
onClick: function onClick(e) {
if (!_this.isMobile) {
_this._onClose();
}
originClick && originClick(e);
}
}));
}
}
var _item = {
id: id,
text: text
};
var className = classnames({
selected: _this.currentMobileSelection && _this.currentMobileSelection.id === id
});
var _onSelect = function _onSelect(e) {
_this.onSelect(e, _item);
};
if (!renderer) {
return React.createElement(ListGroup.Item, {
className: className,
key: id,
onClick: _onSelect
}, text);
} else {
return React.createElement(ListGroup.Item, {
key: id,
onClick: _onSelect
}, renderer(text));
}
}));
};
_this.handleToggleMenu = function (consumer) {
return function (status) {
var _this$props2 = _this.props,
toggleMenu = _this$props2.toggleMenu,
value = _this$props2.value,
itemList = _this$props2.itemList;
if (consumer && consumer.pauseTrap) {
consumer.pauseTrap(status);
}
if (toggleMenu) {
toggleMenu(status);
}
if (!status) {
_this.inputRef.current.focus();
var inputValue = _this.state.inputValue;
var current = itemList.find(function (item) {
return item.id === value;
});
if (current && current.text !== inputValue) {
_this.setState({
inputValue: current.text
});
}
_this.shownList = itemList;
}
};
};
var _value = props.value,
_itemList = props.itemList;
_this.state = {
menuMaxHeight: 500,
menuWidth: null,
showMobileMode: false,
disableChoose: true,
inputValue: _this.findSelectedContent(_value)
}; // this.originInputValue = null; // used to record inout value when navigate via up/down key
_this.popoverRef = React.createRef();
_this.inputRef = React.createRef();
_this.groupRef = React.createRef();
_this.isMobile = isMobile();
_this.currentMobileSelection = null;
_this.shownList = _itemList;
return _this;
}
_createClass(Combobox, [{
key: "componentDidUpdate",
value: function componentDidUpdate(prevProps, prevState) {
var preVal = prevProps.value,
_prevProps$itemList = prevProps.itemList,
preItemList = _prevProps$itemList === void 0 ? [] : _prevProps$itemList;
var _this$props3 = this.props,
value = _this$props3.value,
_this$props3$itemList = _this$props3.itemList,
itemList = _this$props3$itemList === void 0 ? [] : _this$props3$itemList;
if (preItemList !== itemList || preItemList.length !== itemList.length) {
this.shownList = itemList;
}
if (preVal === value) {
return;
}
this.onCloseMobile(); // when set new value to combobox, call thie method to close popup
if (util.isUndefined(value)) {
this.setState({
inputValue: ''
});
}
var inputValue = this.findSelectedContent(value);
if (inputValue !== this.state.inputValue) {
this.setState({
inputValue: this.findSelectedContent(value)
});
}
}
}, {
key: "renderMobileCombobox",
value: function renderMobileCombobox() {
var _this$props4 = this.props,
compact = _this$props4.compact,
placeholder = _this$props4.placeholder,
popTitle = _this$props4.popTitle,
className = _this$props4.className,
disabled = _this$props4.disabled,
textForConfirmButton = _this$props4.textForConfirmButton;
var _this$state = this.state,
showMobileMode = _this$state.showMobileMode,
disableChoose = _this$state.disableChoose,
inputValue = _this$state.inputValue;
var comboboxPopoverClasses = classnames('fd-input-group', 'fd-input-group--after', {
'fd-input-group--compact': compact
});
var comboboxPopoverInputClasses = classnames('fd-input', {
'fd-input--compact': compact
});
var comboboxFrameClasses = classnames(className, {
'combo-disabled': disabled
});
return React.createElement("div", {
className: "combo-frame fd-combobox-input ".concat(comboboxFrameClasses)
}, React.createElement("div", {
className: comboboxPopoverClasses,
onClick: this.trigger,
onKeyDown: this.onKeyTriggerMobile,
role: "button",
tabIndex: "0"
}, React.createElement("input", {
disabled: disabled,
className: comboboxPopoverInputClasses,
placeholder: placeholder,
type: "text",
onChange: this.onInputChange,
value: inputValue
}), React.createElement("span", {
className: "fd-input-group__addon fd-input-group__addon--after fd-input-group__addon--button"
}, React.createElement("button", {
type: "button",
disabled: disabled,
className: " fd-button--light sap-icon--navigation-down-arrow"
}))), React.createElement(Modal, {
className: "ffr-combo-mobile",
title: popTitle,
show: showMobileMode,
onClose: this.onCloseMobile,
closeProps: {
type: 'button'
},
actions: React.createElement(Button, {
typeAttr: "button",
disabled: disableChoose,
onClick: this.onChooseOnMobile
}, textForConfirmButton)
}, this.renderList()));
}
}, {
key: "renderWebCombobox",
value: function renderWebCombobox() {
var _this2 = this;
var _this$state2 = this.state,
menuWidth = _this$state2.menuWidth,
inputValue = _this$state2.inputValue;
var _this$props5 = this.props,
disabled = _this$props5.disabled,
classNameProp = _this$props5.className,
mode = _this$props5.mode,
_this$props5$placehol = _this$props5.placeholder,
placeholder = _this$props5$placehol === void 0 ? '' : _this$props5$placehol;
var className = classnames(classNameProp, {
'combo-disabled': disabled
});
return React.createElement(FocusConsumer, null, function (consumer) {
return React.createElement(ComboboxInput, {
placeholder: placeholder,
disabled: disabled,
className: className,
toggleMenu: _this2.handleToggleMenu(consumer),
buttonProps: {
onClick: _this2.trigger,
disabled: disabled,
type: 'button',
tabIndex: -1
},
popoverProps: {
ref: _this2.popoverRef,
disabled: disabled
},
suggestUpdate: _this2.shouldFilterText(mode, inputValue),
inputProps: {
value: inputValue,
ref: _this2.inputRef,
onClick: _this2.trigger,
onKeyDown: _this2.inputKeyDownHandler,
disabled: disabled,
onChange: _this2.onInputChange
},
menu: _this2.renderList(menuWidth)
});
});
}
}, {
key: "render",
value: function render() {
return this.isMobile ? this.renderMobileCombobox() : this.renderWebCombobox();
}
}]);
return Combobox;
}(Component);
Combobox.defaultProps = {
compact: false,
disabled: false,
textForConfirmButton: '',
itemList: [],
mode: MODE.combobox
};
Combobox.displayName = 'Combobox';
Combobox.Item = ListGroup.Item;
export { Combobox as default };