From 49d58c21ddf154f184a7662a9614721c313323dc Mon Sep 17 00:00:00 2001 From: Smile Date: Tue, 18 Oct 2016 15:13:22 +0200 Subject: [PATCH] Inital commit --- .babelrc | 4 + .eslintrc | 191 +++++++++++++++++++++++++++ .gitignore | 31 +++++ .npmignore | 5 + README.md | 43 ++++++ package.json | 59 +++++++++ src/GooglePlaceAutocomplete.js | 83 ++++++++++++ src/index.js | 3 + test/.setup.js | 20 +++ test/GooglePlaceAutocomplete.spec.js | 25 ++++ webpack.config.js | 48 +++++++ 11 files changed, 512 insertions(+) create mode 100755 .babelrc create mode 100755 .eslintrc create mode 100755 .gitignore create mode 100644 .npmignore create mode 100755 README.md create mode 100644 package.json create mode 100644 src/GooglePlaceAutocomplete.js create mode 100755 src/index.js create mode 100644 test/.setup.js create mode 100644 test/GooglePlaceAutocomplete.spec.js create mode 100755 webpack.config.js diff --git a/.babelrc b/.babelrc new file mode 100755 index 0000000..84b396f --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ["react", "es2015"], + "plugins": ["babel-plugin-add-module-exports"] +} diff --git a/.eslintrc b/.eslintrc new file mode 100755 index 0000000..c8aa9e2 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,191 @@ +{ + "ecmaFeatures": { + "globalReturn": true, + "jsx": true, + "modules": true + }, + + "env": { + "browser": true, + "es6": true, + "node": true + }, + + "globals": { + "document": false, + "escape": false, + "navigator": false, + "unescape": false, + "window": false, + "describe": true, + "before": true, + "it": true, + "expect": true, + "sinon": true + }, + + "parser": "babel-eslint", + + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "modules": true, + "jsx": true + } + }, + + "plugins": [ + "react" + ], + + "rules": { + "block-scoped-var": 2, + "brace-style": [2, "1tbs", { "allowSingleLine": true }], + "camelcase": [2, { "properties": "always" }], + "comma-dangle": [2, "never"], + "comma-spacing": [2, { "before": false, "after": true }], + "comma-style": [2, "last"], + "complexity": 0, + "consistent-this": 0, + "curly": [2, "multi-line"], + "default-case": 0, + "dot-location": [2, "property"], + "dot-notation": 0, + "eol-last": 2, + "eqeqeq": [2, "allow-null"], + "func-names": 0, + "func-style": 0, + "generator-star-spacing": [2, "both"], + "guard-for-in": 0, + "handle-callback-err": [2, "^(err|error|anySpecificError)$" ], + "indent": [2, 2, { "SwitchCase": 1 }], + "react/jsx-uses-vars": 1, + "key-spacing": [2, { "beforeColon": false, "afterColon": true }], + "linebreak-style": 0, + "max-depth": 0, + "max-len": [2, 120, 4], + "max-nested-callbacks": 0, + "max-params": 0, + "max-statements": 0, + "new-cap": [2, { "newIsCap": true, "capIsNew": false }], + "newline-after-var": [2, "always"], + "new-parens": 2, + "no-alert": 0, + "no-array-constructor": 2, + "no-bitwise": 0, + "no-caller": 2, + "no-catch-shadow": 0, + "no-cond-assign": 2, + "no-console": 0, + "no-constant-condition": 0, + "no-continue": 0, + "no-control-regex": 2, + "no-debugger": 2, + "no-delete-var": 2, + "no-div-regex": 0, + "no-dupe-args": 2, + "no-dupe-keys": 2, + "no-duplicate-case": 2, + "no-else-return": 2, + "no-empty": 0, + "no-empty-character-class": 2, + "no-eq-null": 0, + "no-eval": 2, + "no-ex-assign": 2, + "no-extend-native": 2, + "no-extra-bind": 2, + "no-extra-boolean-cast": 2, + "no-extra-parens": 0, + "no-extra-semi": 0, + "no-extra-strict": 0, + "no-fallthrough": 2, + "no-floating-decimal": 2, + "no-func-assign": 2, + "no-implied-eval": 2, + "no-inline-comments": 0, + "no-inner-declarations": [2, "functions"], + "no-invalid-regexp": 2, + "no-irregular-whitespace": 2, + "no-iterator": 2, + "no-label-var": 2, + "no-labels": 2, + "no-lone-blocks": 0, + "no-lonely-if": 0, + "no-loop-func": 0, + "no-mixed-requires": 0, + "no-mixed-spaces-and-tabs": [2, false], + "no-multi-spaces": 2, + "no-multi-str": 2, + "no-multiple-empty-lines": [2, { "max": 1 }], + "no-native-reassign": 2, + "no-negated-in-lhs": 2, + "no-nested-ternary": 0, + "no-new": 2, + "no-new-func": 2, + "no-new-object": 2, + "no-new-require": 2, + "no-new-wrappers": 2, + "no-obj-calls": 2, + "no-octal": 2, + "no-octal-escape": 2, + "no-path-concat": 0, + "no-plusplus": 0, + "no-process-env": 0, + "no-process-exit": 0, + "no-proto": 2, + "no-redeclare": 2, + "no-regex-spaces": 2, + "no-reserved-keys": 0, + "no-restricted-modules": 0, + "no-return-assign": 2, + "no-script-url": 0, + "no-self-compare": 2, + "no-sequences": 2, + "no-shadow": 0, + "no-shadow-restricted-names": 2, + "no-spaced-func": 2, + "no-sparse-arrays": 2, + "no-sync": 0, + "no-ternary": 0, + "no-throw-literal": 2, + "no-trailing-spaces": 2, + "no-undef": 2, + "no-undef-init": 2, + "no-undefined": 0, + "no-underscore-dangle": 0, + "no-unneeded-ternary": 2, + "no-unreachable": 2, + "no-unused-expressions": 0, + "no-unused-vars": [2, { "vars": "all", "args": "none" }], + "no-use-before-define": 2, + "no-var": 0, + "no-void": 0, + "no-warning-comments": 0, + "no-with": 2, + "one-var": 0, + "operator-assignment": 0, + "operator-linebreak": [2, "before"], + "padded-blocks": 0, + "quote-props": 0, + "quotes": [2, "single", "avoid-escape"], + "semi": [2, "always"], + "semi-spacing": 0, + "sort-vars": 0, + "space-before-blocks": [2, "always"], + "space-before-function-paren": [2, {"anonymous": "always", "named": "never"}], + "space-in-brackets": 0, + "space-in-parens": [2, "never"], + "space-infix-ops": 2, + "space-unary-ops": [2, { "words": true, "nonwords": false }], + "spaced-comment": [2, "always"], + "strict": 0, + "use-isnan": 2, + "valid-jsdoc": 0, + "valid-typeof": 2, + "vars-on-top": 2, + "wrap-iife": [2, "any"], + "wrap-regex": 0, + "yoda": [2, "never"] + } +} diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..3be3759 --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git +node_modules + +.DS_Store + +lib diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..9ce3e87 --- /dev/null +++ b/.npmignore @@ -0,0 +1,5 @@ +src +test +webpack.* +.babelrc +.eslintrc diff --git a/README.md b/README.md new file mode 100755 index 0000000..c280a0b --- /dev/null +++ b/README.md @@ -0,0 +1,43 @@ +# GooglePlaceAutocomplete component for ReactJS + +Wrapper on top of the material-ui AutoComplete component that use google place api + +## Installation + +Add this script to your html page: +```html + + + +``` + +``` + npm install googlePlaceAutocomplete +``` + +## Features + +* AutoComplete that auto-load google places + +## Getting started + + +```jsx + +``` +### Props: + +* Same as AutoComplete material-ui component (http://www.material-ui.com/#/components/auto-complete) + +* onNewRequest: function -> (selectedData, searchedText, selectedDataIndex) + + +## Development + +* `npm run build` - produces production version +* `npm run dev` - produces development version +* `npm test` - run the tests diff --git a/package.json b/package.json new file mode 100644 index 0000000..d1e75d3 --- /dev/null +++ b/package.json @@ -0,0 +1,59 @@ +{ + "name": "googlePlaceAutocomplete", + "version": "1.0.2", + "description": "Wrapper on top of the material-ui AutoComplete component that use google place api", + "main": "lib/GooglePlaceAutocomplete.min.js", + "scripts": { + "build": "webpack --mode=build", + "dev": "webpack --progress --colors --watch --mode=dev", + "test": "mocha ./test/.setup.js ./test/**/*.spec.js" + }, + "devDependencies": { + "babel": "6.3.13", + "babel-cli": "^6.16.0", + "babel-core": "6.1.18", + "babel-eslint": "7.0.0", + "babel-loader": "6.1.0", + "babel-plugin-add-module-exports": "0.1.2", + "babel-preset-es2015": "6.3.13", + "babel-preset-react": "^6.16.0", + "babel-register": "^6.16.3", + "chai": "3.4.1", + "enzyme": "^2.4.1", + "eslint": "3.7.1", + "eslint-loader": "1.5.0", + "eslint-plugin-react": "^6.4.1", + "jsdom": "^9.6.0", + "material-ui": "^0.16.0", + "react-tap-event-plugin": "^1.0.0", + "mocha": "2.3.4", + "react": "^15.3.2", + "react-addons-test-utils": "^15.3.2", + "react-dom": "^15.3.2", + "sinon": "^1.17.6", + "webpack": "1.12.9", + "yargs": "3.32.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/ydeshayes/googlePlaceAutocomplete.git" + }, + "keywords": [ + "google place", + "place", + "location", + "autoComplete", + "material-ui", + "React", + "ReactJS", + "select", + "google api" + ], + "author": "Yann Deshayes", + "bugs": { + "url": "https://github.com/ydeshayes/googlePlaceAutocomplete/issues" + }, + "homepage": "https://github.com/ydeshayes/googlePlaceAutocomplete", + "dependencies": { + } +} diff --git a/src/GooglePlaceAutocomplete.js b/src/GooglePlaceAutocomplete.js new file mode 100644 index 0000000..44bae70 --- /dev/null +++ b/src/GooglePlaceAutocomplete.js @@ -0,0 +1,83 @@ +/* global google*/ + +import AutoComplete from 'material-ui/AutoComplete'; +import React, { Component } from 'react'; + +class GooglePlaceAutocomplete extends Component { + constructor(props) { + super(props); + this.state = { + dataSource: [], + data: [] + }; + } + + componentDidMount() { + this.setState({ + autocompleteService: new google.maps.places.AutocompleteService() + }); + } + + componentWillReceiveProps(nextProps) { + if(this.props.searchText !== nextProps.searchText) { + this.onUpdateInput(nextProps.searchText, this.state.dataSource); + this.onInputChange(nextProps.searchText); + } + } + + updateDatasource(data) { + if(!data || !data.length) { + return false; + } + + this.setState({ + dataSource: data.map(place => place.description), + data + }); + } + + onUpdateInput(searchText, dataSource) { + if (!searchText.length || !this.state.autocompleteService) { + return false; + } + + this.state.autocompleteService.getPlacePredictions({ + input: searchText, + location: this.props.location || new google.maps.LatLng(0, 0), + radius: this.props.radius || 0 + }, data => this.updateDatasource(data)); + } + + onNewRequest(searchText, index) { + // The index in dataSource of the list item selected, or -1 if enter is pressed in the TextField + if(index === -1) { + return false; + } + + this.props.onNewRequest(this.state.data[index], searchText, index); + } + + onInputChange(searchText) { + this.props.onChange({target: {value: searchText}}); + } + + render() { + return ( + + ); + } +} + +GooglePlaceAutocomplete.propTypes = { + location: React.PropTypes.object, + radius: React.PropTypes.number, + onNewRequest: React.PropTypes.func, + getRef: React.PropTypes.func +}; + +export default GooglePlaceAutocomplete; diff --git a/src/index.js b/src/index.js new file mode 100755 index 0000000..3770847 --- /dev/null +++ b/src/index.js @@ -0,0 +1,3 @@ +import GooglePlaceAutocomplete from './GooglePlaceAutocomplete'; + +export default GooglePlaceAutocomplete; diff --git a/test/.setup.js b/test/.setup.js new file mode 100644 index 0000000..718f402 --- /dev/null +++ b/test/.setup.js @@ -0,0 +1,20 @@ +require('babel-register')(); + +var jsdom = require('jsdom').jsdom; + +var exposedProperties = ['window', 'navigator', 'document']; + +global.document = jsdom(''); +global.window = document.defaultView; +Object.keys(document.defaultView).forEach((property) => { + if (typeof global[property] === 'undefined') { + exposedProperties.push(property); + global[property] = document.defaultView[property]; + } +}); + +global.navigator = { + userAgent: 'node.js' +}; + +documentRef = document; diff --git a/test/GooglePlaceAutocomplete.spec.js b/test/GooglePlaceAutocomplete.spec.js new file mode 100644 index 0000000..5d8290c --- /dev/null +++ b/test/GooglePlaceAutocomplete.spec.js @@ -0,0 +1,25 @@ +/* global expect*/ + +import sinon from 'sinon'; +import React from 'react'; +import { expect } from 'chai'; +import { shallow } from 'enzyme'; + +import GooglePlaceAutocomplete from '../src'; + +describe('', () => { + + it('Render GooglePlaceAutocomplete', () => { + + const onNewRequest = sinon.spy(); + + const onChange = sinon.spy(); + + let wrapper = shallow(); + }); + +}); diff --git a/webpack.config.js b/webpack.config.js new file mode 100755 index 0000000..2709414 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,48 @@ +var webpack = require('webpack'); +var UglifyJsPlugin = webpack.optimize.UglifyJsPlugin; +var path = require('path'); +var env = require('yargs').argv.mode; + +var libraryName = 'GooglePlaceAutocomplete'; + +var plugins = [], outputFile; + +if (env === 'build') { + plugins.push(new UglifyJsPlugin({ minimize: true })); + outputFile = libraryName + '.min.js'; +} else { + outputFile = libraryName + '.js'; +} + +var config = { + entry: __dirname + '/src/index.js', + devtool: 'source-map', + output: { + path: __dirname + '/lib', + filename: outputFile, + library: libraryName, + libraryTarget: 'umd', + umdNamedDefine: true + }, + module: { + loaders: [ + { + test: /(\.jsx|\.js)$/, + loader: 'babel', + exclude: /(node_modules|bower_components)/ + }, + { + test: /(\.jsx|\.js)$/, + loader: "eslint-loader", + exclude: /node_modules/ + } + ] + }, + resolve: { + root: path.resolve('./src'), + extensions: ['', '.js'] + }, + plugins: plugins +}; + +module.exports = config;