Created
May 3, 2021 15:33
-
-
Save PetterRuud/9e96665c87592571a45f5d00b5eb0a0c to your computer and use it in GitHub Desktop.
ExternalDataInput.js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import React from 'react' | |
import SearchableSelect from 'part:@sanity/components/selects/searchable' | |
import FormField from 'part:@sanity/components/formfields/default' | |
import {PatchEvent, set, unset} from 'part:@sanity/form-builder/patch-event' | |
const STREET_NAMES = [ | |
'Thorvald Meyers gate', | |
'Champs-Élysées', | |
'Lombard Street', | |
'Abbey Road', | |
'Fifth Avenue', | |
'Santa Monica Boulevard', | |
'Ginza', | |
'Beale Street', | |
'Bourbon Street' | |
] | |
const delay = ms => new Promise(resolve => setTimeout(resolve, ms)) | |
const searchExternalAPI = keyword => | |
delay(100).then(() => | |
STREET_NAMES.filter(name => name.toLowerCase().startsWith(keyword.toLowerCase())) | |
) | |
export default class ExternalDataInput extends React.Component { | |
state = { | |
hits: [], | |
isFetching: false, | |
inputValue: null | |
} | |
_lastQuery = null | |
inputRef = React.createRef() | |
handleFocus = () => { | |
if (this._lastQuery) { | |
this.search(this._lastQuery) | |
this.setState({inputValue: this._lastQuery}) | |
} | |
if (this.props.onFocus) { | |
this.props.onFocus() | |
} | |
} | |
handleBlur = () => { | |
this.setState({inputValue: null}) | |
if (this.props.onBlur) { | |
this.props.onBlur() | |
} | |
} | |
handleChange = hit => { | |
const {onChange} = this.props | |
onChange(PatchEvent.from(set(hit))) | |
this._lastQuery = null | |
this.setState({inputValue: null}) | |
} | |
handleClear = () => { | |
this.props.onChange(PatchEvent.from(unset())) | |
} | |
handleSearch = query => { | |
this.search(query) | |
} | |
handleOpen = () => { | |
this.search('') | |
} | |
search = query => { | |
this._lastQuery = query | |
this.setState({inputValue: query, isFetching: true}) | |
searchExternalAPI(query).then(hits => { | |
if (this._lastQuery === query) { | |
this.setState({hits, isFetching: false}) | |
} | |
}) | |
} | |
focus() { | |
if (this.inputRef) { | |
this.inputRef.current.focus() | |
} | |
} | |
render() { | |
const {type, value, level, markers, readOnly, onBlur, onSearch} = this.props | |
const {hits, inputValue, isFetching} = this.state | |
const validation = markers.filter(marker => marker.type === 'validation') | |
const errors = validation.filter(marker => marker.level === 'error') | |
return ( | |
<FormField markers={markers} label={type.title} level={level} description={type.description}> | |
<SearchableSelect | |
placeholder="Type to search…" | |
title={inputValue} | |
customValidity={errors.length > 0 ? errors[0].item.message : ''} | |
onOpen={this.handleOpen} | |
onFocus={this.handleFocus} | |
onBlur={this.handleBlur} | |
onSearch={this.handleSearch} | |
onChange={this.handleChange} | |
onClear={this.handleClear} | |
openItemElement={this.renderOpenItemElement} | |
value={value} | |
inputValue={inputValue === null ? value : inputValue} | |
renderItem={this.renderHit} | |
isLoading={isFetching} | |
items={hits} | |
ref={this.inputRef} | |
readOnly={readOnly} | |
/> | |
</FormField> | |
) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment