UNPKG

@guardian/threads

Version:
183 lines 8.79 kB
import { __extends } from "tslib"; import React from 'react'; import AutosizeInput from 'react-input-autosize'; import { ChipSuggestions } from './ChipSuggestions'; import { InputChip } from './Chip/abstract/InputChip'; import _inRange from 'lodash.inrange'; import styles from './InlineInput.module.css'; export var getInlineInputTestId = function (index) { return "text-chip-" + index; }; var InlineInput = /** @class */ (function (_super) { __extends(InlineInput, _super); function InlineInput() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { isFocused: false, shouldRenderSuggestions: false, }; // We override the onKeyDown which comes from input chip because we need to do more stuff // in the InlineInput such as spawn chips and navigate the suggested filter menu _this.onKeyDown = function (e) { if (_this.textInput) { var input = _this.textInput; var inputStart = input.selectionStart || 0; var inputEnd = input.selectionEnd; var noSelection = inputStart === inputEnd; if (!noSelection) { return; } var _a = _this.props, value = _a.value, index = _a.index; var valueLength = value.length; if (e.key === 'ArrowLeft') { if (inputStart === 0) { e.preventDefault(); _this.props.focusElement(index - 1, true); } else { _this.checkForFilters(value, inputStart - 1); } } else if (e.key === 'ArrowRight') { if (inputStart === valueLength) { e.preventDefault(); _this.props.focusElement(index + 1, false); } else { _this.checkForFilters(value, inputStart + 1); } } else if (e.key === 'Backspace' && inputStart === 0) { e.preventDefault(); _this.props.deleteChip(index - 1); } else if (e.key === 'Delete' && inputStart === valueLength) { e.preventDefault(); _this.props.deleteChip(index + 1); } else if (e.key === 'ArrowUp') { e.preventDefault(); _this.moveSuggestions(-1); } else if (e.key === 'ArrowDown') { e.preventDefault(); _this.moveSuggestions(1); } else if (e.key === 'Enter') { var suggestionIndex = _this.state.suggestionIndex; if (suggestionIndex !== undefined) { _this.createChip(suggestionIndex); } } } }; _this.moveSuggestions = function (step) { var _a = _this.state, suggestionIndex = _a.suggestionIndex, filteredSuggestions = _a.filteredSuggestions; if (suggestionIndex !== undefined && filteredSuggestions) { var i = suggestionIndex + step; var len = filteredSuggestions.length; _this.setState({ suggestionIndex: ((i % len) + len) % len, }); } }; _this.setSuggestionIndex = function (i) { _this.setState({ suggestionIndex: i, }); }; _this.onUpdate = function (e) { var text = e.target.value; _this.props.onUpdate(_this.props.index, text); _this.checkForFilters(text, e.target.selectionStart || 0); }; _this.checkForFilters = function (text, cursorPosition) { var textToCursor = text.substring(0, cursorPosition); var lastChipStart = Math.max(textToCursor.lastIndexOf('+'), textToCursor.lastIndexOf('-')); if (lastChipStart > -1) { var potentialChipSearch_1 = text.substring(lastChipStart + 1, cursorPosition); var filteredSuggestions = _this.props.availableFilters.filter(function (s) { return s.name .toLowerCase() .startsWith(potentialChipSearch_1.toLowerCase()); }); if (filteredSuggestions.length > 0) { var isNegated = textToCursor[lastChipStart] === '-'; var suggestionIndex = _this.state.suggestionIndex; var newSuggestionIndex = suggestionIndex !== undefined && _inRange(suggestionIndex, filteredSuggestions.length) ? suggestionIndex : 0; _this.setState({ suggestionIndex: newSuggestionIndex, chipStartIndex: lastChipStart, shouldRenderSuggestions: true, filteredSuggestions: filteredSuggestions, isNegated: isNegated, }); } else { _this.wipeSuggestions(); } } else { _this.wipeSuggestions(); } }; _this.wipeSuggestions = function () { _this.setState({ filteredSuggestions: undefined, isNegated: undefined, suggestionIndex: undefined, chipStartIndex: undefined, shouldRenderSuggestions: false, }); }; // Create chip - shared for keyboard creation (return key) and clicking a suggestion // Hence the index is an argument _this.createChip = function (suggestionIndex) { var _a = _this.state, filteredSuggestions = _a.filteredSuggestions, isNegated = _a.isNegated, chipStartIndex = _a.chipStartIndex; var input = _this.textInput; if (input && filteredSuggestions && chipStartIndex !== undefined && isNegated !== undefined) { var cursorIndex = input.selectionEnd || 0; _this.props.spawnChip(_this.props.index, { cursorIndex: cursorIndex, startIndex: chipStartIndex }, filteredSuggestions[suggestionIndex], isNegated); _this.wipeSuggestions(); } }; _this.onClickInput = function (e) { if (_this.textInput) { _this.textInput.focus(); // Have to stop propagation to prevent the extender span from refocusing e.stopPropagation(); } }; _this.dropFocus = function () { if (_this.textInput && _this.textInput !== document.activeElement) { _this.setState({ isFocused: false }); } }; return _this; } InlineInput.prototype.renderSuggestions = function () { var _a = this.state, isFocused = _a.isFocused, suggestionIndex = _a.suggestionIndex, filteredSuggestions = _a.filteredSuggestions; if (isFocused && filteredSuggestions && suggestionIndex !== undefined && this.textInput) { var top_1 = this.textInput.getBoundingClientRect().bottom; var left = this.textInput.getBoundingClientRect().right; return (React.createElement(ChipSuggestions, { top: top_1, left: left, currentIndex: suggestionIndex, filteredSuggestions: filteredSuggestions, onSuggestionClicked: this.createChip, setSuggestionIndex: this.setSuggestionIndex })); } return null; }; InlineInput.prototype.render = function () { var _this = this; return (React.createElement("span", { className: styles.inputWrapper, onClick: function () { return _this.focus(true); }, onDoubleClick: this.select }, React.createElement(AutosizeInput, { inputRef: this.setTextInputRef, inputClassName: styles.inlineInput, type: "text", onChange: this.onUpdate, value: this.props.value, onKeyDown: this.onKeyDown, onClick: this.onClickInput, onFocus: function () { return _this.setState({ isFocused: true }); }, onBlur: function () { return window.setTimeout(_this.dropFocus, 500); }, "data-testid": getInlineInputTestId(this.props.index) }), this.state.shouldRenderSuggestions && this.renderSuggestions())); }; return InlineInput; }(InputChip)); export { InlineInput }; //# sourceMappingURL=InlineInput.js.map