Last active
February 18, 2019 21:54
-
-
Save kmelve/0ad0cbc3428289f6bfbf6b54d1a13e3e to your computer and use it in GitHub Desktop.
Rough Example of Custom spotify input
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 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> | |
| ) | |
| } | |
| } |
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 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