├── .gitignore ├── .travis.yml ├── README.md ├── demo └── src │ └── index.js ├── nwb.config.js ├── package.json ├── src └── index.js └── tests ├── .eslintrc └── index-test.js /.gitignore: -------------------------------------------------------------------------------- 1 | /coverage 2 | /demo/dist 3 | /es6 4 | /lib 5 | /node_modules 6 | /umd 7 | npm-debug.log 8 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | 3 | language: node_js 4 | node_js: 5 | - 4.2 6 | 7 | cache: 8 | directories: 9 | - node_modules 10 | 11 | before_install: 12 | - npm install codecov.io coveralls 13 | 14 | after_success: 15 | - cat ./coverage/lcov.info | ./node_modules/codecov.io/bin/codecov.io.js 16 | - cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js 17 | 18 | branches: 19 | only: 20 | - master 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # material-ui-youtube-autocomplete 2 | 3 | A React.js Autcomplete complete component inspired by Material-UI. 4 | 5 | 6 | ## Demo 7 | 8 | See this [compenent in action](https://videonotepad.com) 9 | 10 | ## Installation 11 | 12 | `npm install --save material-ui-youtube-autocomplete` 13 | 14 | 15 | ## Features 16 | 17 | - Material-UI stylized search input 18 | - Auto-suggest drop-down as user types (suggested results come from Youtube) 19 | - Retrieve collection of video search results from Youtube 20 | 21 | 22 | ## Usage 23 | 24 | ```js 25 | import YoutubeAutcomplete from 'material-ui-youtube-autocomplete'; 26 | 27 | 50. Number of video search results you want 30 | placeHolder={string} // defaults -> "Search Youtube" 31 | callback={function} // callback to execute when search results are retrieved 32 | /> 33 | ``` 34 | 35 | ## Example 36 | 37 | ```js 38 | import YoutubeAutocomplete from 'material-ui-youtube-autocomplete'; 39 | 40 | class Example extends React.Component { 41 | render() { 42 | return ( 43 | 49 | ); 50 | } 51 | 52 | _onSearchResultsFound(results) { 53 | // Results is an array of retreived search results from Youtube. 54 | // Do what you want with the results here. 55 | } 56 | } 57 | ``` 58 | 59 | ## License 60 | 61 | MIT 62 | 63 | ## Course 64 | 65 | Are you looking to build a professional app for the Web using React & Redux? 66 | 67 | Check out my course ["How to Write a Single Page Application".](http://www.singlepageapplication.com) 68 | 69 | www.singlepageapplication.com -------------------------------------------------------------------------------- /demo/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import {render} from 'react-dom' 3 | 4 | import Component from '../../src' 5 | 6 | let Demo = React.createClass({ 7 | yourCallback(searchResults) { 8 | console.log('searchResults are: ', searchResults); 9 | }, 10 | 11 | render() { 12 | return
13 | 18 |
19 | } 20 | }) 21 | 22 | render(, document.querySelector('#demo')) 23 | -------------------------------------------------------------------------------- /nwb.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // Let nwb know this is a React component module when generic build commands 3 | // are used. 4 | type: 'react-component', 5 | 6 | // Should nwb create a UMD build for this module? 7 | umd: true, 8 | // The name of the global variable the UMD build of this module will export 9 | global: 'material-ui-youtube-autocomplete', 10 | // Mapping from the npm package names of this module's peerDependencies to the 11 | // global variables they're expected to be available as for use by the UMD 12 | // build. 13 | externals: { 14 | 'react': 'React' 15 | }, 16 | 17 | // Should nwb create a build with untranspiled ES6 modules for tree-shaking 18 | // module bundlers? If you change your mind later, add or remove this line in 19 | // package.json: "jsnext:main": "es6/index.js" 20 | jsNext: true 21 | } 22 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "material-ui-youtube-autocomplete", 3 | "version": "1.2.1", 4 | "description": "material-ui-youtube-autocomplete React component", 5 | "main": "lib/index.js", 6 | "jsnext:main": "es6/index.js", 7 | "files": [ 8 | "css", 9 | "es6", 10 | "lib", 11 | "umd" 12 | ], 13 | "scripts": { 14 | "build": "nwb build", 15 | "clean": "nwb clean", 16 | "start": "nwb serve", 17 | "test": "nwb test" 18 | }, 19 | "dependencies": { 20 | "jsonp": "^0.2.0", 21 | "material-ui": "^0.15.1", 22 | "react": "^15.1.0", 23 | "react-dom": "^15.1.0", 24 | "react-tap-event-plugin": "^1.0.0", 25 | "youtube-finder": "^1.0.0" 26 | }, 27 | "devDependencies": { 28 | "nwb": "0.7.x" 29 | }, 30 | "author": "", 31 | "homepage": "", 32 | "license": "MIT", 33 | "repository": "https://github.com/hackingbeauty/material-ui-youtube-autocomplete", 34 | "keywords": [ 35 | "react-component" 36 | ] 37 | } 38 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import React, { Component } from 'react' 2 | import { AutoComplete } from 'material-ui'; 3 | import JSONP from 'jsonp'; 4 | import YoutubeFinder from 'youtube-finder'; 5 | import getMuiTheme from 'material-ui/styles/getMuiTheme'; 6 | import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'; 7 | import injectTapEventPlugin from 'react-tap-event-plugin'; 8 | 9 | injectTapEventPlugin(); 10 | 11 | const googleAutoSuggestURL = '//suggestqueries.google.com/complete/search?client=youtube&ds=yt&q='; 12 | 13 | class MaterialUIAutocomplete extends Component { 14 | constructor(props) { 15 | super(props); 16 | this.onUpdateInput = this.onUpdateInput.bind(this); 17 | this.onNewRequest = this.onNewRequest.bind(this); 18 | this.YoutubeClient = YoutubeFinder.createClient({ key: this.props.apiKey }); 19 | this.state = { 20 | dataSource : [], 21 | inputValue : '' 22 | } 23 | } 24 | 25 | performSearch() { 26 | const 27 | self = this, 28 | url = googleAutoSuggestURL + this.state.inputValue; 29 | 30 | if(this.state.inputValue !== '') { 31 | JSONP(url, function(error, data) { 32 | let searchResults, retrievedSearchTerms; 33 | 34 | if(error) return console.log(error); 35 | 36 | searchResults = data[1]; 37 | 38 | retrievedSearchTerms = searchResults.map(function(result) { 39 | return result[0]; 40 | }); 41 | 42 | self.setState({ 43 | dataSource : retrievedSearchTerms 44 | }); 45 | }); 46 | } 47 | } 48 | 49 | onUpdateInput(inputValue) { 50 | const self = this; 51 | 52 | this.setState({ 53 | inputValue : inputValue 54 | },function(){ 55 | self.performSearch(); 56 | }); 57 | } 58 | 59 | onNewRequest(searchTerm) { 60 | const 61 | self = this, 62 | params = { 63 | part : 'id,snippet', 64 | type : 'video', 65 | q : this.state.inputValue, 66 | maxResults : this.props.maxResults <= 50 ? this.props.maxResults : '50' 67 | } 68 | 69 | this.YoutubeClient.search(params, function(error,results) { 70 | if(error) return console.log(error); 71 | self.props.callback(results.items,searchTerm); 72 | self.setState({ 73 | dataSource : [], 74 | inputValue : '' 75 | }); 76 | }); 77 | } 78 | 79 | render() { 80 | return 81 | 89 | 90 | } 91 | } 92 | 93 | 94 | export default MaterialUIAutocomplete; 95 | -------------------------------------------------------------------------------- /tests/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /tests/index-test.js: -------------------------------------------------------------------------------- 1 | import expect from 'expect' 2 | import React from 'react' 3 | import {render, unmountComponentAtNode} from 'react-dom' 4 | 5 | import Component from 'src/' 6 | 7 | describe('Component', () => { 8 | let node 9 | 10 | beforeEach(() => { 11 | node = document.createElement('div') 12 | }) 13 | 14 | afterEach(() => { 15 | unmountComponentAtNode(node) 16 | }) 17 | 18 | it('displays a welcome message', () => { 19 | render(, node, () => { 20 | expect(node.innerHTML).toContain('Welcome to React components') 21 | }) 22 | }) 23 | }) 24 | --------------------------------------------------------------------------------