UNPKG

ffr-components

Version:

Fiori styled UI components

502 lines (434 loc) 15 kB
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 };