├── .gitignore
├── src
├── __tests__
│ ├── __snapshots__
│ │ └── index.js.snap
│ └── index.js
└── index.js
├── .travis.yml
├── .babelrc
├── rollup.config.js
├── CONTRIBUTING.md
├── LICENSE
├── CHANGELOG.md
├── package.json
├── README.md
└── compositor.json
/.gitignore:
--------------------------------------------------------------------------------
1 | /coverage
2 | /demo/dist
3 | /dist
4 | /lib
5 | /es
6 | /node_modules
7 | /umd
8 | /es
9 | npm-debug.log
10 | .idea
11 | yarn.lock
12 | package-lock.json
13 |
--------------------------------------------------------------------------------
/src/__tests__/__snapshots__/index.js.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`react-geolocation renders 1`] = `null`;
4 |
5 | exports[`react-geolocation renders with children 1`] = `null`;
6 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - "7"
5 |
6 | cache:
7 | directories:
8 | - node_modules
9 |
10 | before_install:
11 | - npm install codecov
12 |
13 | after_success:
14 | - cat ./coverage/lcov.info | ./node_modules/codecov/bin/codecov
15 |
16 | cache:
17 | directories:
18 | - node_modules
19 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "env",
5 | {
6 | "modules": false,
7 | "loose": true
8 | }
9 | ],
10 | "stage-2",
11 | "react"
12 | ],
13 | "env": {
14 | "test": {
15 | "presets": [
16 | [
17 | "env",
18 | {
19 | "loose": true
20 | }
21 | ],
22 | "stage-2",
23 | "react"
24 | ]
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import babel from 'rollup-plugin-babel';
2 | import fs from 'fs'
3 |
4 | const pkg = JSON.parse(fs.readFileSync('./package.json'))
5 |
6 | export default {
7 | entry: 'src/index.js',
8 | external: ['react'],
9 | exports: 'named',
10 | globals: { react: 'React' },
11 | useStrict: false,
12 | sourceMap: true,
13 | plugins: [babel({
14 | exclude: 'node_modules/**'
15 | })],
16 | targets: [
17 | {dest: pkg.main, format: 'cjs'},
18 | {dest: pkg.module, format: 'es'},
19 | {dest: pkg['umd:main'], format: 'umd', moduleName: pkg.name}
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | ## Prerequisites
2 |
3 | [Node.js](http://nodejs.org/) >= v4 must be installed.
4 |
5 | ## Installation
6 |
7 | - Running `npm install` in the module's root directory will install everything you need for development.
8 |
9 | ## Running Tests
10 |
11 | - `npm test` will run the tests once.
12 |
13 | - `npm run test:coverage` will run the tests and produce a coverage report in `coverage/`.
14 |
15 | - `npm run test:watch` will run the tests on every change.
16 |
17 | ## Building
18 |
19 | - `npm run build` will build the module for publishing to npm.
20 |
21 | - `npm run clean` will delete built resources.
22 |
--------------------------------------------------------------------------------
/src/__tests__/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-env jest */
2 | // eslint-disable-next-line no-unused-vars
3 | import React from 'react'
4 | import Geolocation from '../index'
5 | import renderer from 'react-test-renderer'
6 | const TestUtils = require('react-dom/test-utils')
7 |
8 | describe('react-geolocation', () => {
9 | test('renders', () => {
10 | const tree = renderer.create().toJSON()
11 | expect(tree).toMatchSnapshot()
12 | })
13 |
14 | test('renders with children', () => {
15 | const renderCallback = result => {
16 | return (
17 |
18 | {JSON.stringify(result)}
19 |
20 | )
21 | }
22 | const tree = renderer
23 | .create(
24 |
25 | {renderCallback}
26 |
27 | )
28 | .toJSON()
29 | expect(tree).toMatchSnapshot()
30 | })
31 |
32 | test('can render with no children', () => {
33 | TestUtils.renderIntoDocument()
34 | })
35 | })
36 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2016 Kye Hohenberger
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | Changelog
2 | ------------
3 |
4 | ##### 2.0.0
5 | * Action creators now receive ONE arguement, `store`.
6 | This expands what is possible in an action handler
7 |
8 | * Renamed `addReducer` to `handleActions` (inspired by redux-actions)
9 | The name no longer made sense. Returning a _new_ state from the handler is no longer required.
10 |
11 | * Added `createActions` (inspired by redux-actions)
12 |
13 | Allows developer to create actions and have them available directly from the store
14 | ```js
15 | store.createActions({
16 | startMediaStream: (constraints) => async store => {
17 | try {
18 | const stream = await navigator.mediaDevices.getUserMedia(constraints)
19 | store.actions.mediaStreamSuccess(stream)
20 | } catch (err) {
21 | store.actions.mediaStreamError(err)
22 | }
23 | },
24 | addImage: 'camera/ADD_IMAGE'
25 | })
26 |
27 | // ...later
28 | store.actions.startMediaStream({ audio: true, video: true })
29 | store.actions.addImage(image)
30 | ```
31 |
32 | If the property of the action creator is a plain string like `addImage: 'camera/ADD_IMAGE'` you can use the name in your reducer.
33 |
34 | ```js
35 | store.handleActions({
36 | [store.actions.addImage]: (state, image) => {
37 | state.camera.images.push(image)
38 | }
39 | })
40 | ```
41 |
42 | * Reserved event types with the prefix `$$store:`
43 | `$$store:state:change` is fired after an action handler is called
44 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import PropTypes from 'prop-types'
3 |
4 | export default class Geolocation extends React.Component {
5 | constructor (props) {
6 | super(props)
7 |
8 | this.state = {
9 | fetchingPosition: false,
10 | position: undefined,
11 | error: undefined
12 | }
13 | }
14 |
15 | componentWillMount () {
16 | if (typeof window !== 'object') {
17 | return
18 | }
19 |
20 | if (!('geolocation' in window.navigator)) {
21 | return
22 | }
23 |
24 | if (this.props.lazy) {
25 | return
26 | }
27 |
28 | this.getCurrentPosition()
29 | }
30 |
31 | componentWillUnmount () {
32 | this.willUnmount = true
33 | }
34 |
35 | getCurrentPosition = () => {
36 | const {
37 | enableHighAccuracy,
38 | timeout,
39 | maximumAge,
40 | onSuccess,
41 | onError
42 | } = this.props
43 |
44 | this.setState({ fetchingPosition: true })
45 |
46 | return window.navigator.geolocation.getCurrentPosition(
47 | position => {
48 | if (this.willUnmount) return
49 |
50 | this.setState({ position, fetchingPosition: false }, () =>
51 | onSuccess(position)
52 | )
53 | },
54 | error => {
55 | if (this.willUnmount) return
56 |
57 | this.setState({ error, fetchingPosition: false }, () => onError(error))
58 | },
59 | { enableHighAccuracy, timeout, maximumAge }
60 | )
61 | }
62 |
63 | render () {
64 | if (!this.props.render) {
65 | return null
66 | }
67 | return (
68 | this.props.render({
69 | getCurrentPosition: this.getCurrentPosition,
70 | fetchingPosition: this.state.fetchingPosition,
71 | position: this.state.position,
72 | error: this.state.error
73 | }) || null
74 | )
75 | }
76 | }
77 |
78 | Geolocation.propTypes = {
79 | // https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions
80 | enableHighAccuracy: PropTypes.bool,
81 | timeout: PropTypes.number,
82 | maximumAge: PropTypes.number,
83 | // https://developer.mozilla.org/en-US/docs/Web/API/Geolocation/getCurrentPosition
84 | onSuccess: PropTypes.func,
85 | onError: PropTypes.func,
86 | // Do not call getCurrentPosition on mount
87 | lazy: PropTypes.bool
88 | }
89 |
90 | Geolocation.defaultProps = {
91 | enableHighAccuracy: false,
92 | timeout: Infinity,
93 | maximumAge: 0,
94 | onSuccess: pos => {},
95 | // eslint-disable-next-line handle-callback-err
96 | onError: err => {},
97 | lazy: false
98 | }
99 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-geolocation",
3 | "version": "1.0.4",
4 | "description": "Declarative geolocation in React",
5 | "jsnext:main": "dist/react-geolocation.es.js",
6 | "module": "dist/react-geolocation.es.js",
7 | "main": "dist/react-geolocation.js",
8 | "umd:main": "dist/react-geolocation.umd.js",
9 | "files": [
10 | "dist"
11 | ],
12 | "scripts": {
13 | "build": "npm-run-all clean -p rollup -p minify:* -s size",
14 | "clean": "rimraf dist",
15 | "test": "standard src test && jest --coverage",
16 | "test:watch": "jest --watch",
17 | "rollup": "rollup -c",
18 | "minify:cjs": "uglifyjs $npm_package_main -cm toplevel -o $npm_package_main -p relative --in-source-map ${npm_package_main}.map --source-map ${npm_package_main}.map",
19 | "minify:umd": "uglifyjs $npm_package_umd_main -cm -o $npm_package_umd_main -p relative --in-source-map ${npm_package_umd_main}.map --source-map ${npm_package_umd_main}.map",
20 | "size": "echo \"Gzipped Size: $(strip-json-comments --no-whitespace $npm_package_main | gzip-size)\"",
21 | "release": "npm run test && npm run build && npm version patch && npm publish && git push --tags"
22 | },
23 | "dependencies": {},
24 | "peerDependencies": {
25 | "react": ">=14"
26 | },
27 | "devDependencies": {
28 | "babel-eslint": "^7.2.3",
29 | "babel-jest": "^20.0.3",
30 | "babel-polyfill": "^6.23.0",
31 | "babel-preset-env": "^1.4.0",
32 | "babel-preset-react": "^6.24.1",
33 | "babel-preset-stage-2": "^6.24.1",
34 | "gzip-size-cli": "^2.0.0",
35 | "hapi": "^16.1.0",
36 | "jest": "^20.0.4",
37 | "npm-run-all": "^4.0.2",
38 | "pretty-bytes-cli": "^2.0.0",
39 | "prop-types": "^15.5.8",
40 | "raw-loader": "^0.5.1",
41 | "react": "^15.5.4",
42 | "react-addons-test-utils": "^15.5.1",
43 | "react-dom": "^15.5.4",
44 | "react-test-renderer": "^15.6.1",
45 | "rimraf": "^2.6.1",
46 | "rollup": "^0.47.2",
47 | "rollup-plugin-babel": "^3.0.1",
48 | "standard": "^10.0.2",
49 | "strip-json-comments-cli": "^1.0.1",
50 | "uglify-js": "^2.8.22"
51 | },
52 | "author": "Kye Hohenberger",
53 | "homepage": "https://github.com/tkh44/react-geolocation#readme",
54 | "license": "MIT",
55 | "repository": {
56 | "type": "git",
57 | "url": "git+https://github.com/tkh44/react-geolocation.git"
58 | },
59 | "directories": {
60 | "test": "tests"
61 | },
62 | "keywords": [
63 | "react-component",
64 | "react",
65 | "geolocation",
66 | "react-geolocation"
67 | ],
68 | "eslintConfig": {
69 | "extends": "standard",
70 | "parser": "babel-eslint"
71 | },
72 | "standard": {
73 | "parser": "babel-eslint",
74 | "ignore": [
75 | "/dist/"
76 | ]
77 | },
78 | "bugs": {
79 | "url": "https://github.com/tkh44/react-geolocation/issues"
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # react-geolocation
4 | 🌎🛰 Declarative geolocation in React
5 |
6 | [](https://badge.fury.io/js/react-geolocation)
7 | [](https://travis-ci.org/tkh44/react-geolocation)
8 | [](https://codecov.io/gh/tkh44/react-geolocation)
9 |
10 | - [Install](#install)
11 | - [Basic Usage](#basic-usage)
12 | - [Props](#props)
13 |
14 | ## Install
15 |
16 | ```bash
17 | npm install -S react-geolocation
18 | ```
19 |
20 | ## Basic Usage
21 | ```javascript
22 |
29 |
30 |
31 | {error &&
32 |
33 | {error.message}
34 |
}
35 |
36 | latitude: {latitude}
37 | longitude: {longitude}
38 |
39 |
}
40 | />
41 | ```
42 |
43 | ## Props
44 |
45 | ### [enableHighAccuracy `boolean`](https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions/enableHighAccuracy)
46 |
47 |
48 | ### [timeout `number`](https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions/timeout)
49 |
50 |
51 | ### [maximumAge `number`](https://developer.mozilla.org/en-US/docs/Web/API/PositionOptions/maximumAge)
52 |
53 |
54 | ### render `function`
55 |
56 | `render` is a function that receives an object as its only argument.
57 |
58 | The object contains the following keys:
59 |
60 | - fetchingPosition: `bool`
61 | - [position](https://developer.mozilla.org/en-US/docs/Web/API/Position): `object`
62 | - [error](https://developer.mozilla.org/en-US/docs/Web/API/PositionError): `object`
63 | - getCurrentPosition: `function`
64 |
65 |
66 | ### lazy `boolean`
67 |
68 | If true then the component will **not** perform the fetch on mount.
69 | You must use the `getCurrentPosition` named argument in order to initiate the request.
70 |
71 | ```javascript
72 | (
75 |
76 |
77 |
Fetching Position: {fetchingPosition}
78 |
79 | )}
80 | />
81 | // renders "Fetching Position: false" until the button is clicked
82 | ```
83 |
84 |
85 | ### onSuccess `function`
86 |
87 | callback called on success. Its only argument is `position`
88 |
89 | - https://developer.mozilla.org/en-US/docs/Web/API/Position
90 |
91 | ### onError `function`
92 |
93 | callback called on error. Its only argument is `error`
94 |
95 | - https://developer.mozilla.org/en-US/docs/Web/API/PositionError
96 |
97 |
--------------------------------------------------------------------------------
/compositor.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "tkh44/react-geolocation",
3 | "version": "0.1.4",
4 | "libraries": {
5 | "xv": "^1.1.25"
6 | },
7 | "title": "react-geolocation",
8 | "branch": "master",
9 | "style": {
10 | "name": "Future",
11 | "componentSet": {
12 | "nav": "nav/BasicNav",
13 | "header": "header/BannerHeader",
14 | "article": "article/BasicArticle",
15 | "footer": "footer/BasicFooter"
16 | },
17 | "fontFamily": "\"Avenir Next\", Helvetica, sans-serif",
18 | "heading": {
19 | "fontWeight": 500,
20 | "textTransform": "uppercase",
21 | "letterSpacing": "0.2em"
22 | },
23 | "alternativeText": {
24 | "textTransform": "uppercase",
25 | "fontWeight": 400,
26 | "letterSpacing": "0.2em",
27 | "opacity": 0.75
28 | },
29 | "colors": {
30 | "text": "#333",
31 | "background": "#fff",
32 | "primary": "#666",
33 | "secondary": "#888",
34 | "highlight": "#1f80ff",
35 | "muted": "#f6f6f6",
36 | "border": "#eee"
37 | },
38 | "layout": {
39 | "centered": true,
40 | "maxWidth": 1024,
41 | "bannerHeight": "80vh"
42 | }
43 | },
44 | "content": [
45 | {
46 | "component": "nav",
47 | "links": [
48 | {
49 | "href": "https://github.com/tkh44/react-geolocation",
50 | "text": "GitHub"
51 | },
52 | {
53 | "href": "https://npmjs.com/package/react-geolocation",
54 | "text": "npm"
55 | }
56 | ]
57 | },
58 | {
59 | "component": "header",
60 | "heading": "react-geolocation",
61 | "subhead": "🌎🛰 Declarative geolocation for React",
62 | "children": [
63 | {
64 | "component": "ui/TweetButton",
65 | "text": "react-geolocation: 🌎🛰 Declarative geolocation for React",
66 | "url": ""
67 | },
68 | {
69 | "component": "ui/GithubButton",
70 | "user": "tkh44",
71 | "repo": "react-geolocation"
72 | }
73 | ],
74 | "text": "v1.0.2",
75 | "backgroundImage": "",
76 | "image": ""
77 | },
78 | {
79 | "component": "article",
80 | "metadata": {
81 | "source": "github.readme"
82 | },
83 | "html": "\n\n
\n
\n
\n\nInstall
\nnpm install -S react-geolocation
Basic Usage
\n<Geolocation\n render={({\n fetchingPosition,\n position: { coords: { latitude, longitude } = {} } = {},\n error,\n getCurrentPosition\n }) =>\n <div>\n <button onClick={getCurrentPosition}>Get Position</button>\n {error &&\n <div>\n {error.message}\n </div>}\n <pre>\n latitude: {latitude}\n longitude: {longitude}\n </pre>\n </div>}\n/>Props
\n\n\n\nrender function
\nrender is a function that receives an object as its only argument.
\nThe object contains the following keys:
\n\n- fetchingPosition:
bool \n- position:
object \n- error:
object \n- getCurrentPosition:
function \n
\nlazy boolean
\nIf true then the component will not perform the fetch on mount. \nYou must use the getCurrentPosition named argument in order to initiate the request.
\n<Geolocation \n lazy \n render={({getCurrentPosition, fetchingPosition}) => (\n <div>\n <button onClick={getCurrentPosition}>Get Current Position</button>\n <div>Fetching Position: {fetchingPosition}</div>\n </div>\n )}\n/> \nonSuccess function
\ncallback called on success. Its only argument is position
\n\nonError function
\ncallback called on error. Its only argument is error
\n\n"
84 | },
85 | {
86 | "component": "footer",
87 | "links": [
88 | {
89 | "href": "https://github.com/tkh44/react-geolocation",
90 | "text": "GitHub"
91 | },
92 | {
93 | "href": "https://github.com/tkh44",
94 | "text": "tkh44"
95 | }
96 | ]
97 | }
98 | ]
99 | }
--------------------------------------------------------------------------------