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