Skip to content

Instantly share code, notes, and snippets.

@mornir
Last active September 20, 2019 19:19
Show Gist options
  • Save mornir/d280a6c5e0eaf7ef2885aee9ef0a3c4e to your computer and use it in GitHub Desktop.
Save mornir/d280a6c5e0eaf7ef2885aee9ef0a3c4e to your computer and use it in GitHub Desktop.
A Sanity custom input component for generating furigana from kanji
import React from 'react'
import TextInput from 'part:@sanity/components/textinputs/default'
import FormField from 'part:@sanity/components/formfields/default'
import Button from 'part:@sanity/components/buttons/default'
import PropTypes from 'prop-types'
import ky from './ky'
const Furigana = require('gem-furigana').Furigana
import {
PatchEvent,
set,
setIfMissing,
unset,
} from 'part:@sanity/form-builder/patch-event'
export default class FuriganaInput extends React.Component {
static propTypes = {
value: PropTypes.string,
onChange: PropTypes.func.isRequired,
}
inputRef = React.createRef()
state = {
isGenerating: false,
displayedFurigana: {
__html: '',
},
}
componentDidMount() {
this.setState({
displayedFurigana: this.props.value
? this.displayFurigana(this.props.value)
: { __html: '' },
})
}
handleChange = event => {
const value = event.currentTarget.value
this.props.onChange(PatchEvent.from(value ? set(value) : unset()))
this.setState({
displayedFurigana: this.displayFurigana(value),
})
}
focus() {
if (this.inputRef) {
this.inputRef.current.focus()
}
}
displayFurigana = gemSyntax => {
const furigana = new Furigana(gemSyntax)
return { __html: furigana.ReadingHtml }
}
generateFurigana = async () => {
const value = this.props.value
if (!value || !value.trim()) return
this.setState({ isGenerating: true })
try {
const furigana = await ky
.get('https://endpoint-for-generating-furigana/' + value.trim())
.text()
const cleanFurigana = furigana.replace(/\[ \]\s?/g, '')
this.props.onChange(PatchEvent.from(set(cleanFurigana)))
this.setState({
displayedFurigana: this.displayFurigana(cleanFurigana),
})
} catch (e) {
console.log(e)
} finally {
this.setState({ isGenerating: false })
}
}
render() {
const { value, type, markers, level, onFocus } = this.props
const validation = markers.filter(marker => marker.type === 'validation')
const errors = validation.filter(marker => marker.level === 'error')
const { isGenerating, displayedFurigana } = this.state
return (
<React.Fragment>
<FormField
markers={markers}
level={level}
label={type.title}
description={type.description}
>
<div style={{ display: 'flex' }}>
<div style={{ flexGrow: 1 }}>
<TextInput
customValidity={errors.length > 0 ? errors[0].item.message : ''}
type="text"
value={value}
placeholder={type.placeholder}
onChange={this.handleChange}
onFocus={onFocus}
ref={this.inputRef}
/>
</div>
<Button
loading={isGenerating}
inverted
onClick={this.generateFurigana}
>
Get Furigana
</Button>
</div>
</FormField>
<p dangerouslySetInnerHTML={displayedFurigana} />
</React.Fragment>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment