Skip to content

Instantly share code, notes, and snippets.

@kmelve
Last active February 18, 2019 21:54
Show Gist options
  • Select an option

  • Save kmelve/0ad0cbc3428289f6bfbf6b54d1a13e3e to your computer and use it in GitHub Desktop.

Select an option

Save kmelve/0ad0cbc3428289f6bfbf6b54d1a13e3e to your computer and use it in GitHub Desktop.
Rough Example of Custom spotify input
import PropTypes from 'prop-types'
import React from 'react'
import Fieldset from 'part:@sanity/components/fieldsets/default'
import { PatchEvent, setIfMissing, set } from 'part:@sanity/form-builder/patch-event'
import { FormBuilderInput } from 'part:@sanity/form-builder'
import { render } from 'react-dom'
import Downshift from 'downshift'
export default class CustomObjectInput extends React.PureComponent {
static propTypes = {
type: PropTypes.shape({
title: PropTypes.string,
name: PropTypes.string
}).isRequired,
level: PropTypes.number,
value: PropTypes.shape({
_type: PropTypes.string
}),
focusPath: PropTypes.array.isRequired,
onFocus: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onBlur: PropTypes.func.isRequired
}
state = {
tracks: []
}
firstFieldInput = React.createRef()
handleSearch = async ({ target }) => {
const { value } = target
if (value.length > 3) {
const { tracks = [] } = await fetch(
`https://api.spotify.com/v1/search?q=${value}&type=track`,
{
method: 'GET',
headers: {
Authorization:
'Bearer <YouToken>'
}
}
).then(res => res.json())
this.setState({ tracks: tracks.items })
}
}
handleSelect = (value) => {
console.log({value})
const { id, album, artists, name, uri } = value
const artist = (artists[0] || {}).name || ''
const artwork = album.images.length ? album.images[0].url : ''
const { onChange, type } = this.props
onChange(
PatchEvent.from(
setIfMissing({_type: 'object'}),
set(artist, ['artist']),
set(name, ['name'] ),
set(artwork, ['artwork'] ),
set(uri, ['uri'] ),
)
)
}
handleFieldChange = (field, fieldPatchEvent) => {
const { onChange, type } = this.props
// Whenever the field input emits a patch event, we need to make sure to each of the included patches
// are prefixed with its field name, e.g. going from:
// {path: [], set: <nextvalue>} to {path: [<fieldName>], set: <nextValue>}
// and ensure this input's value exists
onChange(
fieldPatchEvent
.prefixAll(field.name)
.prepend(setIfMissing({ _type: type.name }))
)
}
focus() {
this.firstFieldInput.current.focus()
}
render() {
const { type, value, level, focusPath, onFocus, onBlur } = this.props
const { tracks = [] } = this.state || {}
return (
<div>
<Downshift
onChange={this.handleSelect}
itemToString={item => (item ? item.value : '')}
>
{({
getInputProps,
getItemProps,
getLabelProps,
getMenuProps,
isOpen,
inputValue,
highlightedIndex,
selectedItem
}) => (
<div>
<label {...getLabelProps()}>Search Artist</label>
<input
{...getInputProps({
onChange: this.handleSearch
})}
/>
<ul {...getMenuProps()}>
{tracks && isOpen
? tracks
/* .filter(
({name}) => !inputValue || name.includes(inputValue)
) */
.map((item, index) => console.log(item) || (
<li
{...getItemProps({
key: item.id,
index,
item,
style: {
backgroundColor:
highlightedIndex === index
? 'lightgray'
: 'white',
fontWeight:
selectedItem === item ? 'bold' : 'normal'
}
})}
>
<div><img width="50" src={item.album.images.length > 0 && item.album.images[0].url} />{item.name}</div>
</li>
))
: null}
</ul>
</div>
)}
</Downshift>
<Fieldset
level={level}
legend={type.title}
description={type.description}
>
<div>
{type.fields.map((field, i) => (
// Delegate to the generic FormBuilderInput. It will resolve and insert the actual input component
// for the given field type
<FormBuilderInput
level={level + 1}
ref={i === 0 ? this.firstFieldInput : null}
key={field.name}
type={field.type}
value={value && value[field.name]}
onChange={patchEvent =>
this.handleFieldChange(field, patchEvent)
}
path={[field.name]}
focusPath={focusPath}
onFocus={onFocus}
onBlur={onBlur}
/>
))}
</div>
</Fieldset>
</div>
)
}
}
import React from 'react'
import spotifyDropdown from '../components/spotifyDropdown'
import {withDocument} from 'part:@sanity/form-builder'
import SpotifyPlayer from 'react-spotify-player';
export default {
name: 'spotify',
type: 'document',
title: 'Spotify',
fields: [
{
name: 'metadata',
type: 'object',
title: 'Metadata',
inputComponent: spotifyDropdown,
fields: [
{
name: 'artist',
type: 'string',
title: 'Artist',
},
{
name: 'name',
type: 'string',
title: 'Name',
},
{
name: 'artwork',
type: 'string',
title: 'artwork',
inputComponent: ({value}) => value ? <div><img style={{margin: '1em 0',width: '100%'}} src={value} /></div> : <div></div>
},
{
name: 'uri',
type: 'string',
title: 'URI',
},
]
},
{
name: 'preview',
type: 'string',
title: 'Preview',
inputComponent: withDocument(Preview)
}
],
preview: {
select: {
metadata: 'metadata'
},
prepare({metadata}) {
console.log(metadata)
const { name, artist, artwork} = metadata
return {
title: name,
subtitle: artist,
media: () => <img src={artwork} />
}
}
}
}
function Preview({document}) {
const { metadata = {}} = document
const value = metadata.uri
if (!value) {
return <div></div>
}
return <div><SpotifyPlayer
uri={value}
size={{
width: '100%',
height: 300,
}}
view="coverart"
theme="white"
/></div>
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment