@recogito/recogito-client-core
Advanced tools
Comparing version 0.2.1 to 0.2.2
{ | ||
"name": "@recogito/recogito-client-core", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"description": "Core functions, classes and components for RecogitoJS", | ||
@@ -5,0 +5,0 @@ "main": "src/index.js", |
@@ -153,3 +153,2 @@ import React from 'preact/compat'; | ||
readOnly : props.readOnly, | ||
config: props.config, | ||
env: props.env, | ||
@@ -156,0 +155,0 @@ onAppendBody, |
@@ -1,86 +0,97 @@ | ||
import React, { useState, useRef } from 'react' | ||
import React, { Component, createRef } from 'react' | ||
import { useCombobox } from 'downshift' | ||
const Autocomplete = props => { | ||
export default class Autocomplete extends Component { | ||
const element = useRef(); | ||
constructor(props) { | ||
super(props); | ||
const [ inputItems, setInputItems ] = useState(props.vocabulary); | ||
this.element = createRef(); | ||
this.state = { | ||
inputItems: props.vocabulary || [] | ||
} | ||
} | ||
componentDidMount() { | ||
if (this.props.initialValue && this.element.current) | ||
this.element.current.querySelector('input').value = this.props.initialValue; | ||
} | ||
const onInputValueChange = ({ inputValue }) => { | ||
onInputValueChange = ({ inputValue }) => { | ||
if (inputValue.length > 0) { | ||
const prefixMatches = props.vocabulary.filter(item => { | ||
const prefixMatches = this.props.vocabulary.filter(item => { | ||
return item.toLowerCase().startsWith(inputValue.toLowerCase()); | ||
}); | ||
setInputItems(prefixMatches); | ||
this.setState({ inputItems: prefixMatches }); | ||
} else { | ||
// ...or none, if the input is empty | ||
setInputItems([]); | ||
this.setState({ inputItems: [] }); | ||
} | ||
} | ||
const { | ||
isOpen, | ||
getMenuProps, | ||
getInputProps, | ||
getComboboxProps, | ||
highlightedIndex, | ||
getItemProps, | ||
setInputValue | ||
} = useCombobox({ | ||
items: inputItems, | ||
onInputValueChange, | ||
onSelectedItemChange: ({ inputValue }) => { | ||
onSubmit(inputValue); | ||
setInputValue(''); | ||
} | ||
}); | ||
const onSubmit = inputValue => { | ||
setInputValue(''); | ||
if (inputValue.trim().length > 0) | ||
props.onSubmit(inputValue); | ||
} | ||
render() { | ||
const onKeyDown = evt => { | ||
const { value } = evt.target; | ||
if (evt.which == 13 && highlightedIndex == -1) { | ||
onSubmit(value); | ||
} else if (evt.which == 40 && value.length == 0) { | ||
setInputItems(props.vocabulary); // Show all options on key down | ||
} else if (evt.which == 27) { | ||
props.onCancel && props.onCancel(); | ||
const { | ||
isOpen, | ||
getMenuProps, | ||
getInputProps, | ||
getComboboxProps, | ||
highlightedIndex, | ||
getItemProps, | ||
setInputValue | ||
} = useCombobox({ | ||
items: this.state.inputItems, | ||
onInputValueChange: this.onInputValueChange, | ||
onSelectedItemChange: ({ inputValue }) => { | ||
onSubmit(inputValue); | ||
setInputValue(''); | ||
} | ||
}); | ||
const onSubmit = inputValue => { | ||
setInputValue(''); | ||
if (inputValue.trim().length > 0) | ||
this.props.onSubmit(inputValue); | ||
} | ||
} | ||
return ( | ||
<div ref={element} className="r6o-autocomplete"> | ||
<div {...getComboboxProps()}> | ||
<input | ||
{...getInputProps({ onKeyDown })} | ||
onChange={evt => props.onChange && props.onChange(evt)} | ||
placeholder={props.placeholder} | ||
defaultValue={props.initialValue} | ||
/> | ||
const onKeyUp = evt => { | ||
const { value } = evt.target; | ||
if (evt.which == 13 && highlightedIndex == -1) { | ||
onSubmit(value); | ||
} else if (evt.which == 40 && value.length == 0) { | ||
setInputItems(this.props.vocabulary); // Show all options on key down | ||
} else if (evt.which == 27) { | ||
this.props.onCancel && this.props.onCancel(); | ||
} else { | ||
this.props.onChange && this.props.onChange(value); | ||
} | ||
} | ||
return ( | ||
<div className="r6o-autocomplete" ref={this.element}> | ||
<div {...getComboboxProps()}> | ||
<input | ||
{...getInputProps({ onKeyUp })} | ||
placeholder={this.props.placeholder} /> | ||
</div> | ||
<ul {...getMenuProps()}> | ||
{isOpen && this.state.inputItems.map((item, index) => ( | ||
<li style={ | ||
highlightedIndex === index | ||
? { backgroundColor: '#bde4ff' } | ||
: {} | ||
} | ||
key={`${item}${index}`} | ||
{...getItemProps({ item, index })}> | ||
{item} | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
<ul {...getMenuProps()}> | ||
{isOpen && inputItems.map((item, index) => ( | ||
<li style={ | ||
highlightedIndex === index | ||
? { backgroundColor: '#bde4ff' } | ||
: {} | ||
} | ||
key={`${item}${index}`} | ||
{...getItemProps({ item, index })}> | ||
{item} | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
) | ||
) | ||
} | ||
} | ||
export default Autocomplete; |
@@ -40,5 +40,5 @@ import React from 'preact/compat'; | ||
const onDraftChange = evt => { | ||
const onDraftChange = value => { | ||
const prev = draftTag.value.trim(); | ||
const updated = evt.target.value.trim(); | ||
const updated = value.trim(); | ||
@@ -55,5 +55,8 @@ if (prev.length === 0 && updated.length > 0) { | ||
const onSubmit = tag => { | ||
// Just 'undraft' the current draft tag | ||
const { draft, ...undrafted } = draftTag; | ||
props.onUpdateBody(draftTag, undrafted); | ||
const { draft, ...toSubmit } = { ...draftTag, value: tag }; | ||
if (draftTag.value.trim().length === 0) { | ||
props.onAppendBody(toSubmit); | ||
} else { | ||
props.onUpdateBody(draftTag, toSubmit); | ||
} | ||
} | ||
@@ -60,0 +63,0 @@ |
@@ -18,2 +18,3 @@ import React, { Component } from 'preact/compat'; | ||
readOnly: next.readOnly, | ||
...this.props.config, | ||
onAppendBody: body => next.onAppendBody(body), | ||
@@ -20,0 +21,0 @@ onUpdateBody: (previous, updated) => next.onUpdateBody(previous, updated), |
@@ -270,2 +270,3 @@ import React, { Component } from 'preact/compat'; | ||
config={this.props.config} | ||
env={this.props.env} | ||
applyTemplate={this.state.applyTemplate} | ||
@@ -272,0 +273,0 @@ onAnnotationCreated={this.onCreateOrUpdateAnnotation('onAnnotationCreated')} |
1212490
68
2704