@guardian/threads
Version:
183 lines • 8.79 kB
JavaScript
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