Tag autocomplete behavior fix
This commit is contained in:
parent
89809ad197
commit
b75564b29f
|
@ -5,19 +5,26 @@ const Autocomplete = props => {
|
||||||
|
|
||||||
const element = useRef();
|
const element = useRef();
|
||||||
|
|
||||||
|
const [ value, setValue ] = useState('');
|
||||||
|
|
||||||
const [ inputItems, setInputItems ] = useState(props.vocabulary);
|
const [ inputItems, setInputItems ] = useState(props.vocabulary);
|
||||||
|
|
||||||
useEffect(() =>
|
useEffect(() => element.current?.querySelector('input')?.focus(), []);
|
||||||
element.current?.querySelector('input').focus(), []);
|
|
||||||
|
|
||||||
|
const onSubmit = inputValue => {
|
||||||
|
setValue('');
|
||||||
|
setInputItems([]); // Force-hide the popup
|
||||||
|
if (inputValue.trim().length > 0)
|
||||||
|
props.onSubmit(inputValue);
|
||||||
|
}
|
||||||
|
|
||||||
const onInputValueChange = ({ inputValue }) => {
|
const onInputValueChange = ({ inputValue }) => {
|
||||||
props.onChange(inputValue);
|
setValue(inputValue);
|
||||||
|
|
||||||
setInputItems(
|
setInputItems(
|
||||||
props.vocabulary.filter(item =>
|
props.vocabulary.filter(item =>
|
||||||
item.toLowerCase().startsWith(inputValue.toLowerCase())))
|
item.toLowerCase().startsWith(inputValue.toLowerCase())))
|
||||||
}
|
}
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isOpen,
|
isOpen,
|
||||||
getMenuProps,
|
getMenuProps,
|
||||||
|
@ -25,19 +32,23 @@ const Autocomplete = props => {
|
||||||
getComboboxProps,
|
getComboboxProps,
|
||||||
highlightedIndex,
|
highlightedIndex,
|
||||||
getItemProps,
|
getItemProps,
|
||||||
} = useCombobox({ items: inputItems, onInputValueChange });
|
setInputValue
|
||||||
|
} = useCombobox({
|
||||||
|
items: inputItems,
|
||||||
|
onInputValueChange,
|
||||||
|
onSelectedItemChange: ({ inputValue }) => {
|
||||||
|
onSubmit(inputValue);
|
||||||
|
setInputValue('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// TODO onEnter?
|
|
||||||
const onKeyDown = evt => {
|
const onKeyDown = evt => {
|
||||||
if (evt.which == 13) {
|
if (evt.which == 13 && highlightedIndex == -1)
|
||||||
if (!isOpen || highlightedIndex == -1) {
|
onSubmit(value);
|
||||||
setInputItems([]); // To prevent the popup from showing up afterwards
|
else if (evt.which == 40 && value.length == 0)
|
||||||
props.onKeyDown(evt);
|
setInputItems(props.vocabulary); // Show all options on key down
|
||||||
}
|
else if (evt.which == 27)
|
||||||
} else if (evt.which == 40 && props.content.length == 0) {
|
props.onCancel && props.onCancel();
|
||||||
// To make options appear on key down
|
|
||||||
setInputItems(props.vocabulary);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -45,8 +56,9 @@ const Autocomplete = props => {
|
||||||
<div {...getComboboxProps()}>
|
<div {...getComboboxProps()}>
|
||||||
<input
|
<input
|
||||||
{...getInputProps({ onKeyDown })}
|
{...getInputProps({ onKeyDown })}
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder}
|
||||||
value={props.content} />
|
defaultValue={props.initialValue}
|
||||||
|
value={value} />
|
||||||
</div>
|
</div>
|
||||||
<ul {...getMenuProps()}>
|
<ul {...getMenuProps()}>
|
||||||
{isOpen && inputItems.map((item, index) => (
|
{isOpen && inputItems.map((item, index) => (
|
||||||
|
|
|
@ -9,7 +9,6 @@ import Autocomplete from '../Autocomplete';
|
||||||
const TagWidget = props => {
|
const TagWidget = props => {
|
||||||
|
|
||||||
const [ showDelete, setShowDelete ] = useState(false);
|
const [ showDelete, setShowDelete ] = useState(false);
|
||||||
const [ newTag, setNewTag ] = useState('');
|
|
||||||
|
|
||||||
// Every body with a 'tagging' purpose is considered a tag
|
// Every body with a 'tagging' purpose is considered a tag
|
||||||
const tagBodies = props.annotation ?
|
const tagBodies = props.annotation ?
|
||||||
|
@ -27,11 +26,8 @@ const TagWidget = props => {
|
||||||
props.onRemoveBody(tag);
|
props.onRemoveBody(tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
const onKeyDown = evt => {
|
const onSubmit = tag => {
|
||||||
if (evt.which === 13) { // Enter
|
props.onAppendBody({ type: 'TextualBody', purpose: 'tagging', value: tag.trim() });
|
||||||
props.onAppendBody({ type: 'TextualBody', purpose: 'tagging', value: newTag.trim() });
|
|
||||||
setNewTag(''); // Clear the input
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -58,10 +54,8 @@ const TagWidget = props => {
|
||||||
|
|
||||||
{ !props.readOnly &&
|
{ !props.readOnly &&
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
content={newTag}
|
|
||||||
placeholder={i18n.t('Add tag...')}
|
placeholder={i18n.t('Add tag...')}
|
||||||
onChange={setNewTag}
|
onSubmit={onSubmit}
|
||||||
onKeyDown={onKeyDown}
|
|
||||||
vocabulary={props.vocabulary || []} />
|
vocabulary={props.vocabulary || []} />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -26,11 +26,6 @@ export default class RelationEditor extends Component {
|
||||||
|
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
|
||||||
content: getContent(props.relation)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.element = React.createRef();
|
this.element = React.createRef();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,11 +37,6 @@ export default class RelationEditor extends Component {
|
||||||
this.setPosition();
|
this.setPosition();
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(next) {
|
|
||||||
if (this.props.relation !== next.relation)
|
|
||||||
this.setState({ content : getContent(next.relation) });
|
|
||||||
}
|
|
||||||
|
|
||||||
setPosition() {
|
setPosition() {
|
||||||
if (this.element.current) {
|
if (this.element.current) {
|
||||||
const el = this.element.current;
|
const el = this.element.current;
|
||||||
|
@ -56,33 +46,20 @@ export default class RelationEditor extends Component {
|
||||||
el.style.left = `${midX}px`;
|
el.style.left = `${midX}px`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange = value =>
|
|
||||||
this.setState({ content: value });
|
|
||||||
|
|
||||||
onKeyDown = evt => {
|
|
||||||
if (evt.which === 13) { // Enter = Submit
|
|
||||||
evt.preventDefault();
|
|
||||||
this.onSubmit();
|
|
||||||
} else if (evt.which === 27) {
|
|
||||||
this.props.onCancel();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
onSubmit = () => {
|
onSubmit = value => {
|
||||||
const updatedAnnotation = this.props.relation.annotation.clone({
|
const updatedAnnotation = this.props.relation.annotation.clone({
|
||||||
motivation: 'linking',
|
motivation: 'linking',
|
||||||
body: [{
|
body: [{
|
||||||
type: 'TextualBody',
|
type: 'TextualBody',
|
||||||
value: this.state.content,
|
value,
|
||||||
purpose: 'tagging'
|
purpose: 'tagging'
|
||||||
}]
|
}]
|
||||||
});
|
});
|
||||||
|
|
||||||
const updatedRelation = { ...this.props.relation, annotation: updatedAnnotation };
|
const updatedRelation = { ...this.props.relation, annotation: updatedAnnotation };
|
||||||
|
|
||||||
|
|
||||||
if (this.state.content) {
|
if (value) {
|
||||||
// Fire create or update event
|
// Fire create or update event
|
||||||
if (this.props.relation.annotation.bodies.length === 0)
|
if (this.props.relation.annotation.bodies.length === 0)
|
||||||
this.props.onRelationCreated(updatedRelation, this.props.relation);
|
this.props.onRelationCreated(updatedRelation, this.props.relation);
|
||||||
|
@ -102,10 +79,10 @@ export default class RelationEditor extends Component {
|
||||||
<div className="r6o-relation-editor" ref={this.element}>
|
<div className="r6o-relation-editor" ref={this.element}>
|
||||||
<div className="input-wrapper">
|
<div className="input-wrapper">
|
||||||
<Autocomplete
|
<Autocomplete
|
||||||
content={this.state.content}
|
initialValue={getContent(this.props.relation)}
|
||||||
placeholder="Tag..."
|
placeholder="Tag..."
|
||||||
onChange={this.onChange}
|
onSubmit={this.onSubmit}
|
||||||
onKeyDown={this.onKeyDown}
|
onCancel={this.props.onCancel}
|
||||||
vocabulary={this.props.vocabulary || []} />
|
vocabulary={this.props.vocabulary || []} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue