UNPKG

@guardian/threads

Version:
185 lines 8.48 kB
import { __extends } from "tslib"; import React, { createRef } from 'react'; import AutosizeInput from 'react-input-autosize'; import { InputChip } from './abstract/InputChip'; import { selectKeyDownHandler, } from './SelectChip'; import { PopOver } from '../../../PopOver/PopOver'; import { Menu } from '../../../Menu/Menu'; import { MenuItem } from '../../../Menu/MenuItem'; import inputSupperStyes from '../InputSupper.module.css'; import selectAsyncChipStyles from './SelectAsyncChip.module.css'; export var getSelectAsyncChipWrapperTestId = function (index) { return "select-async-chip-wrapper-" + index; }; export var getSelectAsyncChipTestId = function (index) { return "select-async-chip-" + index; }; export var getEditButtonTestId = function (index) { return "select-async-chip-edit-btn-" + index; }; var SelectAsyncChip = /** @class */ (function (_super) { __extends(SelectAsyncChip, _super); function SelectAsyncChip() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { isMounted: false, isFetching: false, isOptionsMenuOpen: false, isEditing: false, searchInputValue: '', currentIndex: 0, options: [], }; _this.selectRef = createRef(); _this.focus = function () { if (!_this.textInput) { return; } _this.enterEditMode(); var input = _this.textInput; input.focus(); input.selectionStart = 0; input.selectionEnd = input.value.length; }; _this.select = _this.focus; _this.onKeyDown = function (e) { if (_this.state.isEditing) { return _this.onKeyDownForEditMode(e); } selectKeyDownHandler(e, _this.props); }; _this.getInputValue = function () { if (!_this.state.isEditing && _this.props.value) { return _this.props.label || ''; } return _this.state.searchInputValue; }; _this.onBlur = function () { if (_this.state.isOptionsMenuOpen) { return _this.onSelect(_this.state.currentIndex); } _this.exitEditMode(); }; _this.enterEditMode = function () { _this.setState({ isEditing: true, searchInputValue: _this.props.label ? _this.props.label : _this.state.searchInputValue, }); }; _this.exitEditMode = function () { _this.setState({ currentIndex: 0, isOptionsMenuOpen: false, isEditing: false, }); }; _this.onChange = function (_a) { var value = _a.target.value; _this.setState({ searchInputValue: value, isFetching: true, isOptionsMenuOpen: true, }); return _this.props .onInputChange(value) .then(function (options) { return _this.state.isMounted && _this.setState({ options: options }); }) .finally(function () { return _this.state.isMounted && _this.setState({ isFetching: false }); }); }; _this.onSelect = function (index) { var option = _this.state.options[index]; if (!option) { _this.exitEditMode(); return; } var value = option.value, label = option.label; _this.props.onUpdate(_this.props.index, value, label); _this.exitEditMode(); }; _this.getPopoverCoords = function () { if (!_this.textInput) { return { top: 0, left: 0 }; } var _a = _this.selectRef.current.getBoundingClientRect(), bottom = _a.bottom, left = _a.left; return { top: bottom, left: left }; }; // If we're not mounted, we won't have co-ords for Popover, which only reads them on mount. _this.shouldDisplayOptionsMenu = function () { return _this.state.isOptionsMenuOpen && _this.state.isMounted && _this.state.isEditing; }; _this.shouldDisplayLoadingState = function () { return _this.state.isFetching && !_this.state.options.length; }; _this.onKeyDownForEditMode = function (e) { var input = e.currentTarget; var inputStart = input.selectionStart; var inputEnd = input.selectionEnd; var valueLength = input.value.length; var noValue = valueLength === 0; var atEnd = inputStart === valueLength; var noSelection = inputStart === inputEnd; switch (e.key) { case 'ArrowDown': _this.setState({ currentIndex: Math.min(_this.state.currentIndex + 1, _this.state.options.length - 1), }); break; case 'ArrowUp': _this.setState({ currentIndex: Math.max(_this.state.currentIndex - 1, 0), }); break; case 'ArrowLeft': if (inputStart === 0 && noSelection) { e.preventDefault(); _this.props.focusElement(_this.props.index - 1, true); } break; case 'ArrowRight': if (atEnd && noSelection) { e.preventDefault(); _this.props.focusElement(_this.props.index + 1, false); } break; case 'Delete': case 'Backspace': if (noValue) { e.preventDefault(); _this.props.deleteChip(_this.props.index); } break; case 'Enter': { _this.onSelect(_this.state.currentIndex); _this.props.focusElement(_this.props.index + 1, false); break; } } }; return _this; } SelectAsyncChip.prototype.componentDidMount = function () { this.setState({ isMounted: true }); }; SelectAsyncChip.prototype.componentWillUnmount = function () { this.setState({ isMounted: false }); }; SelectAsyncChip.prototype.render = function () { var _this = this; var _a = this.getPopoverCoords(), top = _a.top, left = _a.left; var _b = this.state, isEditing = _b.isEditing, options = _b.options, currentIndex = _b.currentIndex; var _c = this.props, index = _c.index, value = _c.value; return (React.createElement("div", { className: selectAsyncChipStyles.selectAsyncChipWrapper, "data-invalid": !isEditing && !value ? true : null, "data-testid": getSelectAsyncChipWrapperTestId(index), ref: this.selectRef }, React.createElement(AutosizeInput, { inputRef: this.setTextInputRef, type: "text", inputClassName: inputSupperStyes.inlineInputChip, value: this.getInputValue(), onChange: this.onChange, onKeyDown: this.onKeyDown, onFocus: this.enterEditMode, onBlur: this.onBlur, "data-testid": getSelectAsyncChipTestId(index), spellCheck: false }), this.shouldDisplayOptionsMenu() && (React.createElement(PopOver, { top: top, left: left, origin: "left", onClose: function () { return _this.setState({ isOptionsMenuOpen: false }); } }, React.createElement(Menu, { isPopover: true }, this.shouldDisplayLoadingState() && (React.createElement(MenuItem, { key: "@loadingState", label: "Loading ...", disabled: true })), !this.shouldDisplayLoadingState() && !options.length && (React.createElement(MenuItem, { key: "@noOptionsState", label: "No results", disabled: true })), options.map(function (s, idx) { return (React.createElement(MenuItem, { key: s.value, emulateHover: currentIndex === idx, label: s.label, onClick: function () { return _this.onSelect(idx); }, checked: s.value === value })); })))))); }; return SelectAsyncChip; }(InputChip)); export { SelectAsyncChip }; //# sourceMappingURL=SelectAsyncChip.js.map