├── .babelrc
├── .editorconfig
├── .eslintrc
├── .gitignore
├── .npmignore
├── .vscode
└── settings.json
├── LICENSE.md
├── README.md
├── demo.gif
├── demos
├── 1_quickstart
│ ├── Demo.css
│ ├── Demo.js
│ ├── index.html
│ └── index.js
└── 2_barebones
│ ├── Demo.css
│ ├── Demo.js
│ ├── index.html
│ └── index.js
├── package.json
├── postcss.config.js
├── src
├── DefaultGeoInput.css
├── DefaultGeoInput.js
├── GeoAddressInput.css
├── GeoAddressInput.js
├── PredictiveInput.css
├── PredictiveInput.js
├── createGeoInput.js
├── index.js
└── utils.js
├── webpack.config.js
├── webpack.demo.config.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "react", "stage-1"],
3 | "plugins": ["transform-object-rest-spread", "transform-class-properties"]
4 | }
5 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | trim_trailing_whitespace = true
10 |
--------------------------------------------------------------------------------
/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "airbnb",
3 | "env": {
4 | "node": true,
5 | "mocha": true,
6 | "browser": true
7 | },
8 | "globals": {
9 | "expect": true,
10 | "sinon": true
11 | },
12 | "parser": "babel-eslint",
13 | "rules": {
14 | "react/jsx-filename-extension": 0,
15 | "react/forbid-prop-types": 0,
16 | "react/no-multi-comp": 0,
17 | "import/no-extraneous-dependencies": 0,
18 | "import/no-unresolved": 0,
19 | "import/extensions": 0,
20 | "react/require-default-props": 0,
21 | "jsx-a11y/no-static-element-interactions": 0,
22 | "jsx-a11y/href-no-hash": "off"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | lib
3 | *.log
4 | .DS_Store
5 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | demos
2 | docs
3 | .babelrc
4 | .eslint*
5 | .editorconfig
6 | .npmignore
7 | webpack.*
8 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "search.exclude": {
3 | "**/node_modules": true,
4 | "lib": true
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2017 Wolt Enterprises
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # react-geoinput
2 |
3 | :warning: This library has been deprecated and is being no longer maintained :warning:
4 |
5 | [](https://badge.fury.io/js/react-geoinput)
6 | [](https://npmjs.org/package/react-geoinput)
7 |
8 | > Redux-form compatible geolocation suggestions and coordinates with Google Maps API.
9 |
10 |
11 |
12 | ## Features
13 |
14 | * Suggestion of locations with Google Maps API
15 | * Address geocoding with Google Maps API
16 | * Customizable debounced input
17 | * Customizable suggestion serialization and rendering
18 | * Customizable geo destination serialization and rendering
19 | * Standard `input` interface (compatible with `redux-form`)
20 |
21 | ## Install
22 |
23 | 1. add `react-geoinput` as dependency
24 | ```
25 | npm install --save react-geoinput
26 | ```
27 |
28 | 2. include Google Maps API
29 |
30 | Make `window.google.maps` available e.g. with:
31 |
32 | ```html
33 |
34 | ```
35 |
36 | link: [Google Maps JavaScript API
37 | / get API key](https://developers.google.com/maps/documentation/javascript/get-api-key)
38 |
39 | ## Try demos locally
40 |
41 | ```
42 | $ git clone https://github.com/woltapp/react-geoinput.git
43 | $ cd react-geoinput
44 | $ yarn
45 | $ yarn start
46 | ```
47 |
48 | * `1_quickstart` demonstrates the use of `DefaultGeoInput`
49 | * `2_barebones` uses only `createGeoInput` and demonstrates how to use the API to create your own input
50 |
51 | ## What problem does the library solve?
52 |
53 | React-geoinput makes it a breeze to combine both __geolocation suggestion__
54 | and __geocoding an address__. Generally other libraries do only either at once. A good use case for this library is to be able to turn an address into coordinates and verify that the interpreted address was correct in textual format. Moreover, this library allows complete customization of the UI, and only provides components to get you quickly started!
55 |
56 | ## Examples
57 |
58 | ### Quick start
59 |
60 | ```jsx
61 | import React, { Component } from 'react';
62 | import { createGeoInput, DefaultGeoInput } from 'react-geoinput';
63 |
64 | const SimpleInput = createGeoInput(DefaultGeoInput);
65 |
66 | class Example extends Component {
67 | state = {
68 | address: '',
69 | geoDestination: '',
70 | }
71 |
72 | onAddressChange = value => this.setState({ address: value })
73 | onGeoDestinationChange = value => this.setState({ geoDestination: value })
74 |
75 | render() {
76 | return (
77 |
78 |
88 |
89 | );
90 | }
91 | }
92 | ```
93 |
94 | ### Usage with Redux-form
95 |
96 | ```jsx
97 | import React from 'react';
98 | import { Fields } from 'redux-form';
99 | import { createGeoInput, DefaultGeoInput } from 'react-geoinput';
100 |
101 | const GeoInput = createGeoInput(DefaultGeoInput);
102 |
103 | const GeoField = fields => (
104 |
108 | );
109 | ```
110 |
111 | Use with `redux-form`'s `Fields` component:
112 |
113 | ```jsx
114 |
115 | ```
116 |
117 |
118 |
119 | ## API Documentation
120 |
121 | ### Overview
122 |
123 | React-geoinput exposes one higher order component (`createGeoInput`) and three regular
124 | stateless React components (`DefaultGeoInput`, `GeoAddressInput`, `PredictiveInput`).
125 |
126 | `createGeoInput` contains the main logic to handle fetching location
127 | suggestions from the Google Maps API and to geocode the typed
128 | address to a location object, which includes e.g. coordinates and parsed
129 | location fields. In fact, `createGeoInput` provides __two__ inputs simultaneously:
130 | typed address and geocoded location. Generally you'll want to store the information
131 | separately, since address is the arbitrary string typed by user and location
132 | is the accurate exact geolocation.
133 |
134 | `DefaultGeoInput` exists to get you quickly started with the library. It contains
135 | opinionated styles and structure, which is a good starting point. If it works
136 | for you, you can customize it via the props, otherwise you can use
137 | it simply as a starting point to create your own completely custom input component.
138 | `DefaultGeoInput` uses `GeoAddressInput` underneath to provide the bare-bones
139 | input with predictions (=suggestions).
140 |
141 | `GeoAddressInput` is provided as a convenience component, which simply maps
142 | the predictions (suggestions) from `createGeoInput()` to `PredictiveInput`.
143 |
144 | `PredictiveInput` is provided as a utility component to provide a simple
145 | input field with predictions -- it is not coupled to geocoding or locations anyhow.
146 | It should be applicable for most cases and supports styling via props.
147 | `PredictiveInput` uses `DebounceInput` from `react-debounce-input` to reduce
148 | the amount of requests made to the Google Maps API.
149 |
150 | ### `createGeoInput(input: Component, )`
151 |
152 | `createGeoInput` is a higher order component that takes two arguments, first of which is your custom input (or `DefaultGeoInput`),
153 | and the second one is options object. It can be wrapped with a custom input component, such as with the provided `DefaultGeoInput`. The beef of this library's logic is in this HoC; thus you are encouraged to make a custom implementation of the input.
154 |
155 | ##### The following options can be set:
156 |
157 | * __`serializePrediction`__ _(Function)_: A function that takes `prediction` object
158 | from the Google Maps API as an argument and turns it into a string that is suggested.
159 | The structure of the `prediction` object is not included in this documentation.
160 |
161 | * __`serializeGeoDestination`__ _(Function)_: A function that takes `geoDestination` object
162 | from the Google Maps API as an argument and turns it to another object. By default it maps
163 | the `geoDestination` keys as following: `route->street`, `street_number->streetNumber`,
164 | `subpremise->subpremise`, `locality->city`, `country->country`, `postal_code->postalCode`,
165 | `{ geometry }->{ lat, lng},viewport`. The structure of the `geoDestination` object is not
166 | included in this documentation.
167 |
168 | > _Note: you won't need to change these options unless you know you are missing
169 | an important value from the Google Maps API._
170 |
171 |
172 | ### `DefaultGeoInput`
173 |
174 | `DefaultGeoInput` displays an input for typing the address. Predictions (=suggestions) will
175 | be shown for the address with `PredictiveInput`. On predicted address selection the `geoDestionation`
176 | will be also rendered.
177 |
178 | > _Note: a good way to get started with your completely custom input is to copy the implementation of
179 | `DefaultGeoInput` and modify it._
180 |
181 | #### Props
182 |
183 | * `activeIndex (number)`: control the selected index of location suggestion
184 | * `addressInput (object.isRequired)`: input controls, such as `onChange`, `value`
185 | * `className (string)`
186 | * `geoDestinationInput (object.isRequired)`: input controls, such as `onChange`, `value`
187 | * `geoDestinationClassName (string)`
188 | * `geoDestinationTableClassName (string)`
189 | * `loadingElement (node)`: element to display while loading geo destination
190 | * `loadingGeoDestination (bool)`: control when to show `loadingElement`
191 | * `onPredictionClick (func.isRequired)`: handle suggestion click, takes prediction `index`
192 | * `predictions (array.isRequired)`: array of predictions from Google Maps API
193 | * `style (object)`
194 |
195 | ### `GeoAddressInput`
196 |
197 | #### Props
198 |
199 | * `activeIndex (number)`: control the selected index of location suggestion
200 | * `className (string)`
201 | * `onPredictionClick (func.isRequired)`: handles prediction click, takes prediction `index`
202 | * `onChange (func.isRequired)`: handle for address input change
203 | * `predictions (array.isRequired)`: array of predictions from Google Maps API
204 | * `style (object)`
205 |
206 |
207 | ### `PredictiveInput`
208 |
209 | #### Props
210 |
211 | * `className (string)`
212 | * `containerClassName (string)`:
213 | * `containerStyle (object)`:
214 | * `debounceTimeout (number)`: time for debounce in ms
215 | * `activePredictionId (string|number)`: control active prediction
216 | * `predictions (arrayOf(predictionPropType))`: array of predictions (see below)
217 | * `predictionsClassName (string)`
218 | * `predictionItemClassName (string)`
219 |
220 | ```js
221 | predictionPropType = PropTypes.shape({
222 | id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
223 | label: PropTypes.node,
224 | onClick: PropTypes.func,
225 | })
226 | ```
227 |
228 | ## License
229 |
230 | MIT
231 |
--------------------------------------------------------------------------------
/demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/woltapp/react-geoinput/728a72ec8207a64e144e0f3d9f9d9774876f36a3/demo.gif
--------------------------------------------------------------------------------
/demos/1_quickstart/Demo.css:
--------------------------------------------------------------------------------
1 | .addressInput {
2 | font-size: 13px;
3 | border-radius: 3px;
4 | border: 1px solid #ccc;
5 | outline: none;
6 | padding: 5px 8px;
7 | width: 240px;
8 | }
9 |
10 | .geoDestination {
11 | font-size: 15px;
12 | border-radius: 3px;
13 | }
14 |
15 | .loadingContainer {
16 | margin-top: 10px;
17 | font-size: 15px;
18 | }
19 |
--------------------------------------------------------------------------------
/demos/1_quickstart/Demo.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { createGeoInput, DefaultGeoInput } from 'react-geoinput';
3 |
4 | import styles from './Demo.css';
5 |
6 | const DemoInput = createGeoInput(DefaultGeoInput);
7 |
8 | class DemoView extends Component {
9 | state = {
10 | address: '',
11 | geoDestination: '',
12 | }
13 |
14 | onAddressChange = value => this.setState({ address: value })
15 |
16 | onGeoDestinationChange = value => this.setState({ geoDestination: value })
17 |
18 | render() {
19 | return (
20 |