├── .babelrc.js ├── .eslintignore ├── .eslintrc.js ├── .github ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── publish.yml │ └── verify.yml ├── .gitignore ├── .husky └── pre-commit ├── .npmignore ├── .yarn └── releases │ └── yarn-4.2.1.cjs ├── .yarnrc.yml ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── config.json ├── examples └── basic │ ├── index.html │ └── react-google-button.js ├── index.d.ts ├── package.json ├── src ├── GoogleButton.js ├── icons.js ├── index.js └── styles.js ├── test ├── .eslintrc ├── mocha.opts ├── setup.js └── unit │ └── index.spec.js ├── webpack.config.js └── yarn.lock /.babelrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | "@babel/preset-react", 4 | [ 5 | "@babel/preset-env", 6 | { 7 | "targets": { 8 | "chrome": 52, 9 | "browsers": [ 10 | "last 2 versions", 11 | "safari >= 7" 12 | ] 13 | } 14 | } 15 | ] 16 | ], 17 | plugins: [ 18 | "@babel/plugin-proposal-export-default-from", 19 | "@babel/plugin-proposal-class-properties" 20 | ], 21 | env: { 22 | test: { 23 | sourceMaps: 'both' 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | examples/** 2 | coverage/** 3 | node_modules/** 4 | _book/** 5 | _site/** 6 | test/mocha.opts 7 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parser: 'babel-eslint', 4 | extends: [ 'standard', 'standard-react', 'prettier', 'prettier/react' ], 5 | plugins: [ 'babel', 'react', 'prettier' ], 6 | env: { browser: true }, 7 | settings: { 8 | react: { 9 | version: 'detect', 10 | } 11 | }, 12 | rules: { 13 | semi: [ 2, 'never' ], 14 | 'no-console': 'error', 15 | 'react/jsx-no-bind': [ 2, { allowArrowFunctions: true } ], 16 | 'react/jsx-handler-names': 0, 17 | 'prettier/prettier': 18 | [ 'error', { 19 | singleQuote: true, 20 | trailingComma: 'none', 21 | semi: false, 22 | bracketSpacing: true, 23 | jsxBracketSameLine: false, 24 | printWidth: 80, 25 | tabWidth: 2, 26 | useTabs: false 27 | }] 28 | } 29 | } -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing Guidelines 2 | 3 | Thanks for taking the time to look into contributing! Below are some basic conventions for contributing to this project. 4 | 5 | ### General 6 | 7 | Please make sure that there aren't existing pull requests attempting to address the issue mentioned. Likewise, please check for issues related to update, as someone else may be working on the issue in a branch or fork. 8 | 9 | ### Commit Message Format 10 | 11 | Each commit message should include a **type**, a **scope** and a **subject**: 12 | 13 | ``` 14 | (): 15 | ``` 16 | 17 | Lines should not exceed 100 characters. This allows the message to be easier to read on github as well as in various git tools and produces a nice, neat commit log ie: 18 | 19 | ``` 20 | #218 docs(example): allow user to configure webpack stats output 21 | #271 feat(standard): add style config and refactor to match 22 | #270 fix(config): only override publicPath when served by webpack 23 | #269 feat(eslint-config-defaults): replace eslint-config-airbnb 24 | #268 feat(config): allow user to configure webpack stats output 25 | ``` 26 | 27 | #### Type 28 | 29 | Must be one of the following: 30 | 31 | * **feat**: A new feature 32 | * **fix**: A bug fix 33 | * **docs**: Documentation only changes 34 | * **style**: Changes that do not affect the meaning of the code (white-space, formatting, missing 35 | semi-colons, etc) 36 | * **refactor**: A code change that neither fixes a bug or adds a feature 37 | * **test**: Adding missing tests 38 | * **chore**: Changes to the build process or auxiliary tools and libraries such as documentation 39 | generation 40 | 41 | #### Scope 42 | 43 | The scope could be anything specifying place of the commit change. For example `webpack`, 44 | `babel`, `redux` etc... 45 | 46 | #### Subject 47 | 48 | The subject contains succinct description of the change: 49 | 50 | * use the imperative, present tense: "change" not "changed" nor "changes" 51 | * don't capitalize first letter 52 | * no dot (.) at the end 53 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **Do you want to request a *feature* or report a *bug*?** 2 | 3 | 4 | **What is the current behavior?** 5 | 6 | 7 | **What is the expected behavior?** 8 | 9 | 10 | **Which versions of dependencies, and which browser are affected by this issue? Did this work in previous versions or setups?** 11 | 12 | 13 | **Steps to reproduce and if possible a minimal demo of the problem via [codepen](https://codepen.io/) or similar.** 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Description 2 | 3 | 4 | ### Check List 5 | If not relevant to pull request, check off as complete 6 | 7 | - [ ] All tests passing 8 | - [ ] Docs updated with any changes or examples if applicable 9 | - [ ] Added tests to ensure new feature(s) work properly 10 | 11 | ### Relevant Issues 12 | 13 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: NPM Package Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - next 8 | 9 | jobs: 10 | build: 11 | name: Build 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout Code 15 | uses: actions/checkout@v4 16 | 17 | - name: Setup Node 20 18 | uses: actions/setup-node@v4 19 | with: 20 | node-version: 20 21 | registry-url: https://registry.npmjs.org/ 22 | cache: 'yarn' 23 | 24 | - name: Configure package manager 25 | run: | 26 | npm config set '//registry.npmjs.org/:_authToken' ${{ secrets.NPM_TOKEN }} 27 | 28 | - name: Install Dependencies 29 | run: yarn install --immutable 30 | 31 | - name: Run Unit Tests + Coverage 32 | run: yarn test:cov 33 | 34 | - name: Build 35 | run: yarn build 36 | 37 | - name: Publish To NPM 38 | env: 39 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 40 | GITHUB_REF: ${{ github.ref }} 41 | run: npm publish $(if [ "$GITHUB_REF" != 'refs/heads/main' ]; then echo '--tag next';fi;) 42 | 43 | - name: Get package version 44 | id: package-info 45 | env: 46 | SHA: ${{ github.sha }} 47 | run: | 48 | echo "::set-output name=version::$(node -p \"require('./package.json').version\")" 49 | echo "::set-output name=body::$(git --no-pager log --format=%B -n 1 $SHA)" 50 | 51 | - name: Create Release 52 | id: create_release 53 | uses: actions/create-release@v1 54 | env: 55 | GITHUB_TOKEN: ${{ github.token }} 56 | with: 57 | tag_name: v${{ steps.package-info.outputs.version }} 58 | release_name: v${{ steps.package-info.outputs.version }} 59 | draft: false 60 | body: ${{ steps.package-info.outputs.body }} 61 | prerelease: ${{ github.ref }} == 'refs/heads/next' 62 | 63 | - name: Upload Coverage 64 | uses: codecov/codecov-action@v4 65 | with: 66 | token: ${{ secrets.CODE_COV }} 67 | -------------------------------------------------------------------------------- /.github/workflows/verify.yml: -------------------------------------------------------------------------------- 1 | name: Verify 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | build: 7 | name: Build 8 | runs-on: ubuntu-latest 9 | strategy: 10 | matrix: 11 | node-version: [18.x, 20.x] 12 | steps: 13 | - name: Checkout Code 14 | uses: actions/checkout@v4 15 | 16 | - name: Use Node.js ${{ matrix.node-version }} 17 | uses: actions/setup-node@v4 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | cache: 'yarn' 21 | 22 | - name: Install Dependencies 23 | run: yarn install --immutable 24 | 25 | - name: Run Unit Tests + Coverage 26 | run: yarn test:cov 27 | 28 | - name: Build 29 | run: yarn build 30 | 31 | - name: Upload Coverage 32 | uses: codecov/codecov-action@v4 33 | with: 34 | token: ${{ secrets.CODE_COV }} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | .pnp.* 4 | .yarn/* 5 | !.yarn/patches 6 | !.yarn/plugins 7 | !.yarn/releases 8 | !.yarn/sdks 9 | !.yarn/versions 10 | 11 | **/.DS_Store 12 | coverage 13 | examples/basic/*js 14 | docs 15 | dist 16 | lib 17 | es 18 | *.log 19 | .nyc_output -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | yarn lint-staged 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | DS_Store 3 | **/.DS_Store 4 | examples 5 | tests 6 | coverage 7 | .istanbul.yml 8 | .babelrc 9 | .babelrc.js 10 | SUMMARY.md 11 | webpack.config.js 12 | .eslintignore 13 | .eslintrc 14 | .github 15 | .travis.yml 16 | CODE_OF_CONDUCT.md 17 | CHANGELOG.md 18 | .codeclimate.yml 19 | .nyc_output -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | nodeLinker: node-modules 2 | 3 | yarnPath: .yarn/releases/yarn-4.2.1.cjs 4 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | Every release, along with the migration instructions, is documented on the Github [Releases](https://github.com/prescottprue/react-google-button/releases) page. 5 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018-present Prescott Prue 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-google-button 2 | 3 | [![NPM version][npm-image]][npm-url] 4 | [![Build Status][build-status-image]][build-status-url] 5 | [![Coverage][coverage-image]][coverage-url] 6 | [![License][license-image]][license-url] 7 | [![Code Style][code-style-image]][code-style-url] 8 | 9 | > Simple Google sign in button for React that follows Google's style guidelines (https://developers.google.com/identity/sign-in/web/build-button) 10 | 11 | ## [Codepen Demo](https://codepen.io/prescottprue/pen/NjmeKM) 12 | 13 | ## Rendered Preview 14 | 15 | ![Preview Image](https://storage.googleapis.com/pruvit-968.appspot.com/react-google-button/preview.png) 16 | 17 | ## Getting Started 18 | 19 | `react-google-button` is universal, so it can be used client-side or server-side. 20 | 21 | 1. Install through: `npm install --save react-google-button` 22 | 23 | 2. Import `GoogleButton` from `react-google-button`: 24 | 25 | ```javascript 26 | import GoogleButton from 'react-google-button' 27 | ``` 28 | 29 | 3. Use `GoogleButton` component: 30 | 31 | ```javascript 32 | { console.log('Google button clicked') }} 34 | /> 35 | ``` 36 | 37 | ## Props 38 | 39 | ### type 40 | ##### PropType 41 | ```js 42 | oneOf([ 'light', 'dark' ]) 43 | ``` 44 | 45 | ##### Default 46 | ```js 47 | 'dark' 48 | ``` 49 | 50 | ##### Example 51 | 52 | ```js 53 | { console.log('Google button clicked') }} 56 | /> 57 | ``` 58 | 59 | ##### Description 60 | `'light'` or `'dark'` for the different google styles (defaults to `dark`) 61 | 62 | 63 | ### disabled 64 | `disabled` - whether or not button is disabled 65 | 66 | ##### PropType 67 | ```js 68 | Boolean 69 | ``` 70 | 71 | ##### Default 72 | ```js 73 | false 74 | ``` 75 | 76 | ##### Example 77 | 78 | ```javascript 79 | { console.log('this will not run on click since it is disabled') }} 82 | /> 83 | ``` 84 | 85 | ### label 86 | ##### PropType 87 | ```js 88 | String 89 | ``` 90 | ##### Default 91 | ```js 92 | 'Sign in with Google' 93 | ``` 94 | 95 | ##### Example 96 | 97 | ```javascript 98 | { console.log('Google button clicked') }} 101 | /> 102 | ``` 103 | 104 | ##### Description 105 | Override the 'Sign in with Google' words with another string. 106 | 107 | **Note**: [Google's branding guidelines](https://developers.google.com/identity/branding-guidelines) states you should not to do this 108 | 109 | 110 | ## Builds 111 | 112 | Most commonly people consume `react-google-button` as a [CommonJS module](http://webpack.github.io/docs/commonjs.html). This module is what you get when you import redux in a Webpack, Browserify, or a Node environment. 113 | 114 | If you don't use a module bundler, it's also fine. The `react-google-button` npm package includes precompiled production and development [UMD builds](https://github.com/umdjs/umd) in the [dist folder](https://unpkg.com/react-google-button@latest/dist/). They can be used directly without a bundler and are thus compatible with many popular JavaScript module loaders and environments. For example, you can drop a UMD build as a ` 120 | 121 | 122 | ``` 123 | 124 | Note: In an effort to keep things simple, the wording from this explanation was modeled after [the installation section of the Redux Docs](https://redux.js.org/#installation). 125 | 126 | [npm-image]: https://img.shields.io/npm/v/react-google-button.svg?style=flat-square 127 | [npm-url]: https://npmjs.org/package/react-google-button 128 | [build-status-image]: https://img.shields.io/github/workflow/status/prescottprue/react-google-button/NPM%20Package%20Publish?style=flat-square&logo=github 129 | [build-status-url]: https://github.com/prescottprue/react-google-button/actions 130 | [coverage-image]: https://img.shields.io/codeclimate/coverage/github/prescottprue/react-google-button.svg?style=flat-square&logo=codecov 131 | [coverage-url]: https://codeclimate.com/github/prescottprue/react-google-button 132 | [license-image]: https://img.shields.io/npm/l/react-google-button.svg?style=flat-square 133 | [license-url]: https://github.com/prescottprue/react-google-button/blob/master/LICENSE 134 | [code-style-image]: https://img.shields.io/badge/code%20style-standard-brightgreen.svg?style=flat-square 135 | [code-style-url]: http://standardjs.com/ 136 | -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "cdn": { 3 | "bucket": "", 4 | "prefix": "react-google-button" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /examples/basic/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | React-Google-Button 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /examples/basic/react-google-button.js: -------------------------------------------------------------------------------- 1 | /*! react-google-button.js v0.3.0 | (c) prescottprue */ 2 | (function webpackUniversalModuleDefinition(root, factory) { 3 | if(typeof exports === 'object' && typeof module === 'object') 4 | module.exports = factory(require("react")); 5 | else if(typeof define === 'function' && define.amd) 6 | define(["react"], factory); 7 | else if(typeof exports === 'object') 8 | exports["ReactGoogleButton"] = factory(require("react")); 9 | else 10 | root["ReactGoogleButton"] = factory(root["React"]); 11 | })(this, function(__WEBPACK_EXTERNAL_MODULE_4__) { 12 | return /******/ (function(modules) { // webpackBootstrap 13 | /******/ // The module cache 14 | /******/ var installedModules = {}; 15 | /******/ 16 | /******/ // The require function 17 | /******/ function __webpack_require__(moduleId) { 18 | /******/ 19 | /******/ // Check if module is in cache 20 | /******/ if(installedModules[moduleId]) { 21 | /******/ return installedModules[moduleId].exports; 22 | /******/ } 23 | /******/ // Create a new module (and put it into the cache) 24 | /******/ var module = installedModules[moduleId] = { 25 | /******/ i: moduleId, 26 | /******/ l: false, 27 | /******/ exports: {} 28 | /******/ }; 29 | /******/ 30 | /******/ // Execute the module function 31 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); 32 | /******/ 33 | /******/ // Flag the module as loaded 34 | /******/ module.l = true; 35 | /******/ 36 | /******/ // Return the exports of the module 37 | /******/ return module.exports; 38 | /******/ } 39 | /******/ 40 | /******/ 41 | /******/ // expose the modules object (__webpack_modules__) 42 | /******/ __webpack_require__.m = modules; 43 | /******/ 44 | /******/ // expose the module cache 45 | /******/ __webpack_require__.c = installedModules; 46 | /******/ 47 | /******/ // define getter function for harmony exports 48 | /******/ __webpack_require__.d = function(exports, name, getter) { 49 | /******/ if(!__webpack_require__.o(exports, name)) { 50 | /******/ Object.defineProperty(exports, name, { 51 | /******/ configurable: false, 52 | /******/ enumerable: true, 53 | /******/ get: getter 54 | /******/ }); 55 | /******/ } 56 | /******/ }; 57 | /******/ 58 | /******/ // getDefaultExport function for compatibility with non-harmony modules 59 | /******/ __webpack_require__.n = function(module) { 60 | /******/ var getter = module && module.__esModule ? 61 | /******/ function getDefault() { return module['default']; } : 62 | /******/ function getModuleExports() { return module; }; 63 | /******/ __webpack_require__.d(getter, 'a', getter); 64 | /******/ return getter; 65 | /******/ }; 66 | /******/ 67 | /******/ // Object.prototype.hasOwnProperty.call 68 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; 69 | /******/ 70 | /******/ // __webpack_public_path__ 71 | /******/ __webpack_require__.p = "/dist/"; 72 | /******/ 73 | /******/ // Load entry module and return exports 74 | /******/ return __webpack_require__(__webpack_require__.s = 8); 75 | /******/ }) 76 | /************************************************************************/ 77 | /******/ ([ 78 | /* 0 */ 79 | /***/ (function(module, exports) { 80 | 81 | // shim for using process in browser 82 | var process = module.exports = {}; 83 | 84 | // cached from whatever global is present so that test runners that stub it 85 | // don't break things. But we need to wrap it in a try catch in case it is 86 | // wrapped in strict mode code which doesn't define any globals. It's inside a 87 | // function because try/catches deoptimize in certain engines. 88 | 89 | var cachedSetTimeout; 90 | var cachedClearTimeout; 91 | 92 | function defaultSetTimout() { 93 | throw new Error('setTimeout has not been defined'); 94 | } 95 | function defaultClearTimeout () { 96 | throw new Error('clearTimeout has not been defined'); 97 | } 98 | (function () { 99 | try { 100 | if (typeof setTimeout === 'function') { 101 | cachedSetTimeout = setTimeout; 102 | } else { 103 | cachedSetTimeout = defaultSetTimout; 104 | } 105 | } catch (e) { 106 | cachedSetTimeout = defaultSetTimout; 107 | } 108 | try { 109 | if (typeof clearTimeout === 'function') { 110 | cachedClearTimeout = clearTimeout; 111 | } else { 112 | cachedClearTimeout = defaultClearTimeout; 113 | } 114 | } catch (e) { 115 | cachedClearTimeout = defaultClearTimeout; 116 | } 117 | } ()) 118 | function runTimeout(fun) { 119 | if (cachedSetTimeout === setTimeout) { 120 | //normal enviroments in sane situations 121 | return setTimeout(fun, 0); 122 | } 123 | // if setTimeout wasn't available but was latter defined 124 | if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { 125 | cachedSetTimeout = setTimeout; 126 | return setTimeout(fun, 0); 127 | } 128 | try { 129 | // when when somebody has screwed with setTimeout but no I.E. maddness 130 | return cachedSetTimeout(fun, 0); 131 | } catch(e){ 132 | try { 133 | // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 134 | return cachedSetTimeout.call(null, fun, 0); 135 | } catch(e){ 136 | // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error 137 | return cachedSetTimeout.call(this, fun, 0); 138 | } 139 | } 140 | 141 | 142 | } 143 | function runClearTimeout(marker) { 144 | if (cachedClearTimeout === clearTimeout) { 145 | //normal enviroments in sane situations 146 | return clearTimeout(marker); 147 | } 148 | // if clearTimeout wasn't available but was latter defined 149 | if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { 150 | cachedClearTimeout = clearTimeout; 151 | return clearTimeout(marker); 152 | } 153 | try { 154 | // when when somebody has screwed with setTimeout but no I.E. maddness 155 | return cachedClearTimeout(marker); 156 | } catch (e){ 157 | try { 158 | // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally 159 | return cachedClearTimeout.call(null, marker); 160 | } catch (e){ 161 | // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. 162 | // Some versions of I.E. have different rules for clearTimeout vs setTimeout 163 | return cachedClearTimeout.call(this, marker); 164 | } 165 | } 166 | 167 | 168 | 169 | } 170 | var queue = []; 171 | var draining = false; 172 | var currentQueue; 173 | var queueIndex = -1; 174 | 175 | function cleanUpNextTick() { 176 | if (!draining || !currentQueue) { 177 | return; 178 | } 179 | draining = false; 180 | if (currentQueue.length) { 181 | queue = currentQueue.concat(queue); 182 | } else { 183 | queueIndex = -1; 184 | } 185 | if (queue.length) { 186 | drainQueue(); 187 | } 188 | } 189 | 190 | function drainQueue() { 191 | if (draining) { 192 | return; 193 | } 194 | var timeout = runTimeout(cleanUpNextTick); 195 | draining = true; 196 | 197 | var len = queue.length; 198 | while(len) { 199 | currentQueue = queue; 200 | queue = []; 201 | while (++queueIndex < len) { 202 | if (currentQueue) { 203 | currentQueue[queueIndex].run(); 204 | } 205 | } 206 | queueIndex = -1; 207 | len = queue.length; 208 | } 209 | currentQueue = null; 210 | draining = false; 211 | runClearTimeout(timeout); 212 | } 213 | 214 | process.nextTick = function (fun) { 215 | var args = new Array(arguments.length - 1); 216 | if (arguments.length > 1) { 217 | for (var i = 1; i < arguments.length; i++) { 218 | args[i - 1] = arguments[i]; 219 | } 220 | } 221 | queue.push(new Item(fun, args)); 222 | if (queue.length === 1 && !draining) { 223 | runTimeout(drainQueue); 224 | } 225 | }; 226 | 227 | // v8 likes predictible objects 228 | function Item(fun, array) { 229 | this.fun = fun; 230 | this.array = array; 231 | } 232 | Item.prototype.run = function () { 233 | this.fun.apply(null, this.array); 234 | }; 235 | process.title = 'browser'; 236 | process.browser = true; 237 | process.env = {}; 238 | process.argv = []; 239 | process.version = ''; // empty string to avoid regexp issues 240 | process.versions = {}; 241 | 242 | function noop() {} 243 | 244 | process.on = noop; 245 | process.addListener = noop; 246 | process.once = noop; 247 | process.off = noop; 248 | process.removeListener = noop; 249 | process.removeAllListeners = noop; 250 | process.emit = noop; 251 | process.prependListener = noop; 252 | process.prependOnceListener = noop; 253 | 254 | process.listeners = function (name) { return [] } 255 | 256 | process.binding = function (name) { 257 | throw new Error('process.binding is not supported'); 258 | }; 259 | 260 | process.cwd = function () { return '/' }; 261 | process.chdir = function (dir) { 262 | throw new Error('process.chdir is not supported'); 263 | }; 264 | process.umask = function() { return 0; }; 265 | 266 | 267 | /***/ }), 268 | /* 1 */ 269 | /***/ (function(module, exports, __webpack_require__) { 270 | 271 | "use strict"; 272 | 273 | 274 | /** 275 | * Copyright (c) 2013-present, Facebook, Inc. 276 | * All rights reserved. 277 | * 278 | * This source code is licensed under the BSD-style license found in the 279 | * LICENSE file in the root directory of this source tree. An additional grant 280 | * of patent rights can be found in the PATENTS file in the same directory. 281 | * 282 | * 283 | */ 284 | 285 | function makeEmptyFunction(arg) { 286 | return function () { 287 | return arg; 288 | }; 289 | } 290 | 291 | /** 292 | * This function accepts and discards inputs; it has no side effects. This is 293 | * primarily useful idiomatically for overridable function endpoints which 294 | * always need to be callable, since JS lacks a null-call idiom ala Cocoa. 295 | */ 296 | var emptyFunction = function emptyFunction() {}; 297 | 298 | emptyFunction.thatReturns = makeEmptyFunction; 299 | emptyFunction.thatReturnsFalse = makeEmptyFunction(false); 300 | emptyFunction.thatReturnsTrue = makeEmptyFunction(true); 301 | emptyFunction.thatReturnsNull = makeEmptyFunction(null); 302 | emptyFunction.thatReturnsThis = function () { 303 | return this; 304 | }; 305 | emptyFunction.thatReturnsArgument = function (arg) { 306 | return arg; 307 | }; 308 | 309 | module.exports = emptyFunction; 310 | 311 | /***/ }), 312 | /* 2 */ 313 | /***/ (function(module, exports, __webpack_require__) { 314 | 315 | "use strict"; 316 | /* WEBPACK VAR INJECTION */(function(process) {/** 317 | * Copyright (c) 2013-present, Facebook, Inc. 318 | * All rights reserved. 319 | * 320 | * This source code is licensed under the BSD-style license found in the 321 | * LICENSE file in the root directory of this source tree. An additional grant 322 | * of patent rights can be found in the PATENTS file in the same directory. 323 | * 324 | */ 325 | 326 | 327 | 328 | /** 329 | * Use invariant() to assert state which your program assumes to be true. 330 | * 331 | * Provide sprintf-style format (only %s is supported) and arguments 332 | * to provide information about what broke and what you were 333 | * expecting. 334 | * 335 | * The invariant message will be stripped in production, but the invariant 336 | * will remain to ensure logic does not differ in production. 337 | */ 338 | 339 | var validateFormat = function validateFormat(format) {}; 340 | 341 | if (process.env.NODE_ENV !== 'production') { 342 | validateFormat = function validateFormat(format) { 343 | if (format === undefined) { 344 | throw new Error('invariant requires an error message argument'); 345 | } 346 | }; 347 | } 348 | 349 | function invariant(condition, format, a, b, c, d, e, f) { 350 | validateFormat(format); 351 | 352 | if (!condition) { 353 | var error; 354 | if (format === undefined) { 355 | error = new Error('Minified exception occurred; use the non-minified dev environment ' + 'for the full error message and additional helpful warnings.'); 356 | } else { 357 | var args = [a, b, c, d, e, f]; 358 | var argIndex = 0; 359 | error = new Error(format.replace(/%s/g, function () { 360 | return args[argIndex++]; 361 | })); 362 | error.name = 'Invariant Violation'; 363 | } 364 | 365 | error.framesToPop = 1; // we don't care about invariant's own frame 366 | throw error; 367 | } 368 | } 369 | 370 | module.exports = invariant; 371 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) 372 | 373 | /***/ }), 374 | /* 3 */ 375 | /***/ (function(module, exports, __webpack_require__) { 376 | 377 | "use strict"; 378 | /** 379 | * Copyright 2013-present, Facebook, Inc. 380 | * All rights reserved. 381 | * 382 | * This source code is licensed under the BSD-style license found in the 383 | * LICENSE file in the root directory of this source tree. An additional grant 384 | * of patent rights can be found in the PATENTS file in the same directory. 385 | */ 386 | 387 | 388 | 389 | var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; 390 | 391 | module.exports = ReactPropTypesSecret; 392 | 393 | 394 | /***/ }), 395 | /* 4 */ 396 | /***/ (function(module, exports) { 397 | 398 | module.exports = __WEBPACK_EXTERNAL_MODULE_4__; 399 | 400 | /***/ }), 401 | /* 5 */ 402 | /***/ (function(module, exports, __webpack_require__) { 403 | 404 | /* WEBPACK VAR INJECTION */(function(process) {/** 405 | * Copyright 2013-present, Facebook, Inc. 406 | * All rights reserved. 407 | * 408 | * This source code is licensed under the BSD-style license found in the 409 | * LICENSE file in the root directory of this source tree. An additional grant 410 | * of patent rights can be found in the PATENTS file in the same directory. 411 | */ 412 | 413 | if (process.env.NODE_ENV !== 'production') { 414 | var REACT_ELEMENT_TYPE = (typeof Symbol === 'function' && 415 | Symbol.for && 416 | Symbol.for('react.element')) || 417 | 0xeac7; 418 | 419 | var isValidElement = function(object) { 420 | return typeof object === 'object' && 421 | object !== null && 422 | object.$$typeof === REACT_ELEMENT_TYPE; 423 | }; 424 | 425 | // By explicitly using `prop-types` you are opting into new development behavior. 426 | // http://fb.me/prop-types-in-prod 427 | var throwOnDirectAccess = true; 428 | module.exports = __webpack_require__(10)(isValidElement, throwOnDirectAccess); 429 | } else { 430 | // By explicitly using `prop-types` you are opting into new production behavior. 431 | // http://fb.me/prop-types-in-prod 432 | module.exports = __webpack_require__(12)(); 433 | } 434 | 435 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) 436 | 437 | /***/ }), 438 | /* 6 */ 439 | /***/ (function(module, exports, __webpack_require__) { 440 | 441 | "use strict"; 442 | /* WEBPACK VAR INJECTION */(function(process) {/** 443 | * Copyright 2014-2015, Facebook, Inc. 444 | * All rights reserved. 445 | * 446 | * This source code is licensed under the BSD-style license found in the 447 | * LICENSE file in the root directory of this source tree. An additional grant 448 | * of patent rights can be found in the PATENTS file in the same directory. 449 | * 450 | */ 451 | 452 | 453 | 454 | var emptyFunction = __webpack_require__(1); 455 | 456 | /** 457 | * Similar to invariant but only logs a warning if the condition is not met. 458 | * This can be used to log issues in development environments in critical 459 | * paths. Removing the logging code for production environments will keep the 460 | * same logic and follow the same code paths. 461 | */ 462 | 463 | var warning = emptyFunction; 464 | 465 | if (process.env.NODE_ENV !== 'production') { 466 | (function () { 467 | var printWarning = function printWarning(format) { 468 | for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { 469 | args[_key - 1] = arguments[_key]; 470 | } 471 | 472 | var argIndex = 0; 473 | var message = 'Warning: ' + format.replace(/%s/g, function () { 474 | return args[argIndex++]; 475 | }); 476 | if (typeof console !== 'undefined') { 477 | console.error(message); 478 | } 479 | try { 480 | // --- Welcome to debugging React --- 481 | // This error was thrown as a convenience so that you can use this stack 482 | // to find the callsite that caused this warning to fire. 483 | throw new Error(message); 484 | } catch (x) {} 485 | }; 486 | 487 | warning = function warning(condition, format) { 488 | if (format === undefined) { 489 | throw new Error('`warning(condition, format, ...args)` requires a warning ' + 'message argument'); 490 | } 491 | 492 | if (format.indexOf('Failed Composite propType: ') === 0) { 493 | return; // Ignore CompositeComponent proptype check. 494 | } 495 | 496 | if (!condition) { 497 | for (var _len2 = arguments.length, args = Array(_len2 > 2 ? _len2 - 2 : 0), _key2 = 2; _key2 < _len2; _key2++) { 498 | args[_key2 - 2] = arguments[_key2]; 499 | } 500 | 501 | printWarning.apply(undefined, [format].concat(args)); 502 | } 503 | }; 504 | })(); 505 | } 506 | 507 | module.exports = warning; 508 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) 509 | 510 | /***/ }), 511 | /* 7 */ 512 | /***/ (function(module, exports, __webpack_require__) { 513 | 514 | "use strict"; 515 | 516 | 517 | Object.defineProperty(exports, "__esModule", { 518 | value: true 519 | }); 520 | 521 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 522 | 523 | var baseStyle = { 524 | height: '50px', 525 | width: '240px', 526 | border: 'none', 527 | textAlign: 'center', 528 | verticalAlign: 'center', 529 | boxShadow: '0 2px 4px 0 rgba(0,0,0,.25)', 530 | fontSize: '16px', 531 | lineHeight: '48px', 532 | display: 'block', 533 | borderRadius: '1px', 534 | transition: 'background-color .218s, border-color .218s, box-shadow .218s', 535 | fontFamily: 'Roboto,arial,sans-serif', 536 | cursor: 'pointer' 537 | }; 538 | 539 | var darkStyle = exports.darkStyle = _extends({ 540 | backgroundColor: '#4285f4', 541 | color: '#fff' 542 | }, baseStyle); 543 | 544 | var lightStyle = exports.lightStyle = _extends({ 545 | backgroundColor: '#fff', 546 | color: 'rgba(0,0,0,.54)' 547 | }, baseStyle); 548 | 549 | var iconStyle = exports.iconStyle = { 550 | width: '48px', 551 | height: '48px', 552 | textAlign: 'center', 553 | verticalAlign: 'center', 554 | display: 'block', 555 | marginTop: '1px', 556 | marginLeft: '1px', 557 | float: 'left', 558 | backgroundColor: '#fff', 559 | borderRadius: '1px', 560 | whiteSpace: 'nowrap' 561 | }; 562 | 563 | var svgStyle = exports.svgStyle = { 564 | width: '48px', 565 | height: '48px', 566 | display: 'block' 567 | }; 568 | 569 | var hoverStyle = exports.hoverStyle = { 570 | boxShadow: '0 0 3px 3px rgba(66,133,244,.3)', 571 | transition: 'background-color .218s, border-color .218s, box-shadow .218s' 572 | }; 573 | 574 | // export const pressedStyle = { 575 | // backgroundColor: '#3367D6' 576 | // } 577 | 578 | var disabledStyle = exports.disabledStyle = { 579 | backgroundColor: 'rgba(37, 5, 5, .08)', 580 | color: 'rgba(0, 0, 0, .40)', 581 | cursor: 'not-allowed' 582 | }; 583 | 584 | var disabledIconStyle = exports.disabledIconStyle = { 585 | backgroundColor: 'transparent' 586 | }; 587 | 588 | /***/ }), 589 | /* 8 */ 590 | /***/ (function(module, exports, __webpack_require__) { 591 | 592 | "use strict"; 593 | 594 | 595 | Object.defineProperty(exports, "__esModule", { 596 | value: true 597 | }); 598 | exports.default = exports.GoogleButton = undefined; 599 | 600 | var _GoogleButton = __webpack_require__(9); 601 | 602 | Object.defineProperty(exports, 'GoogleButton', { 603 | enumerable: true, 604 | get: function get() { 605 | return _GoogleButton.GoogleButton; 606 | } 607 | }); 608 | 609 | var _GoogleButton2 = _interopRequireDefault(_GoogleButton); 610 | 611 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 612 | 613 | exports.default = _GoogleButton2.default; 614 | 615 | /***/ }), 616 | /* 9 */ 617 | /***/ (function(module, exports, __webpack_require__) { 618 | 619 | "use strict"; 620 | 621 | 622 | Object.defineProperty(exports, "__esModule", { 623 | value: true 624 | }); 625 | 626 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 627 | 628 | var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); 629 | 630 | var _react = __webpack_require__(4); 631 | 632 | var _react2 = _interopRequireDefault(_react); 633 | 634 | var _propTypes = __webpack_require__(5); 635 | 636 | var _propTypes2 = _interopRequireDefault(_propTypes); 637 | 638 | var _icons = __webpack_require__(13); 639 | 640 | var _styles = __webpack_require__(7); 641 | 642 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 643 | 644 | function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } 645 | 646 | function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } 647 | 648 | function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } 649 | 650 | var GoogleButton = function (_Component) { 651 | _inherits(GoogleButton, _Component); 652 | 653 | function GoogleButton() { 654 | var _ref; 655 | 656 | var _temp, _this, _ret; 657 | 658 | _classCallCheck(this, GoogleButton); 659 | 660 | for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { 661 | args[_key] = arguments[_key]; 662 | } 663 | 664 | return _ret = (_temp = (_this = _possibleConstructorReturn(this, (_ref = GoogleButton.__proto__ || Object.getPrototypeOf(GoogleButton)).call.apply(_ref, [this].concat(args))), _this), _this.state = { 665 | hovered: false 666 | }, _this.getStyle = function () { 667 | var baseStyle = _this.props.type === 'dark' ? _styles.darkStyle : _styles.lightStyle; 668 | if (_this.state.hovered) { 669 | return _extends({}, baseStyle, _styles.hoverStyle); 670 | } 671 | if (_this.props.disabled) { 672 | return _extends({}, baseStyle, _styles.disabledStyle); 673 | } 674 | return baseStyle; 675 | }, _this.mouseOver = function () { 676 | if (!_this.props.disabled) { 677 | _this.setState({ hovered: true }); 678 | } 679 | }, _this.mouseOut = function () { 680 | if (!_this.props.disabled) { 681 | _this.setState({ hovered: false }); 682 | } 683 | }, _this.click = function (e) { 684 | if (!_this.props.disabled) { 685 | _this.props.onClick(e); 686 | } 687 | }, _temp), _possibleConstructorReturn(_this, _ret); 688 | } 689 | 690 | _createClass(GoogleButton, [{ 691 | key: 'render', 692 | value: function render() { 693 | var label = this.props.label; 694 | 695 | 696 | return _react2.default.createElement( 697 | 'div', 698 | _extends({}, this.props, { 699 | onClick: this.click, 700 | style: this.getStyle(), 701 | onMouseOver: this.mouseOver, 702 | onMouseOut: this.mouseOut 703 | }), 704 | _react2.default.createElement(_icons.GoogleIcon, this.props), 705 | _react2.default.createElement( 706 | 'span', 707 | null, 708 | label 709 | ) 710 | ); 711 | } 712 | }]); 713 | 714 | return GoogleButton; 715 | }(_react.Component); 716 | 717 | GoogleButton.propTypes = { 718 | label: _propTypes2.default.string, 719 | disabled: _propTypes2.default.bool, 720 | onClick: _propTypes2.default.func, 721 | type: _propTypes2.default.oneOf(['light', 'dark']) 722 | }; 723 | GoogleButton.defaultProps = { 724 | label: 'Sign in with Google', 725 | disabled: false, 726 | type: 'dark', 727 | onClick: function onClick() {} 728 | }; 729 | exports.default = GoogleButton; 730 | 731 | /***/ }), 732 | /* 10 */ 733 | /***/ (function(module, exports, __webpack_require__) { 734 | 735 | "use strict"; 736 | /* WEBPACK VAR INJECTION */(function(process) {/** 737 | * Copyright 2013-present, Facebook, Inc. 738 | * All rights reserved. 739 | * 740 | * This source code is licensed under the BSD-style license found in the 741 | * LICENSE file in the root directory of this source tree. An additional grant 742 | * of patent rights can be found in the PATENTS file in the same directory. 743 | */ 744 | 745 | 746 | 747 | var emptyFunction = __webpack_require__(1); 748 | var invariant = __webpack_require__(2); 749 | var warning = __webpack_require__(6); 750 | 751 | var ReactPropTypesSecret = __webpack_require__(3); 752 | var checkPropTypes = __webpack_require__(11); 753 | 754 | module.exports = function(isValidElement, throwOnDirectAccess) { 755 | /* global Symbol */ 756 | var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; 757 | var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. 758 | 759 | /** 760 | * Returns the iterator method function contained on the iterable object. 761 | * 762 | * Be sure to invoke the function with the iterable as context: 763 | * 764 | * var iteratorFn = getIteratorFn(myIterable); 765 | * if (iteratorFn) { 766 | * var iterator = iteratorFn.call(myIterable); 767 | * ... 768 | * } 769 | * 770 | * @param {?object} maybeIterable 771 | * @return {?function} 772 | */ 773 | function getIteratorFn(maybeIterable) { 774 | var iteratorFn = maybeIterable && (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]); 775 | if (typeof iteratorFn === 'function') { 776 | return iteratorFn; 777 | } 778 | } 779 | 780 | /** 781 | * Collection of methods that allow declaration and validation of props that are 782 | * supplied to React components. Example usage: 783 | * 784 | * var Props = require('ReactPropTypes'); 785 | * var MyArticle = React.createClass({ 786 | * propTypes: { 787 | * // An optional string prop named "description". 788 | * description: Props.string, 789 | * 790 | * // A required enum prop named "category". 791 | * category: Props.oneOf(['News','Photos']).isRequired, 792 | * 793 | * // A prop named "dialog" that requires an instance of Dialog. 794 | * dialog: Props.instanceOf(Dialog).isRequired 795 | * }, 796 | * render: function() { ... } 797 | * }); 798 | * 799 | * A more formal specification of how these methods are used: 800 | * 801 | * type := array|bool|func|object|number|string|oneOf([...])|instanceOf(...) 802 | * decl := ReactPropTypes.{type}(.isRequired)? 803 | * 804 | * Each and every declaration produces a function with the same signature. This 805 | * allows the creation of custom validation functions. For example: 806 | * 807 | * var MyLink = React.createClass({ 808 | * propTypes: { 809 | * // An optional string or URI prop named "href". 810 | * href: function(props, propName, componentName) { 811 | * var propValue = props[propName]; 812 | * if (propValue != null && typeof propValue !== 'string' && 813 | * !(propValue instanceof URI)) { 814 | * return new Error( 815 | * 'Expected a string or an URI for ' + propName + ' in ' + 816 | * componentName 817 | * ); 818 | * } 819 | * } 820 | * }, 821 | * render: function() {...} 822 | * }); 823 | * 824 | * @internal 825 | */ 826 | 827 | var ANONYMOUS = '<>'; 828 | 829 | // Important! 830 | // Keep this list in sync with production version in `./factoryWithThrowingShims.js`. 831 | var ReactPropTypes = { 832 | array: createPrimitiveTypeChecker('array'), 833 | bool: createPrimitiveTypeChecker('boolean'), 834 | func: createPrimitiveTypeChecker('function'), 835 | number: createPrimitiveTypeChecker('number'), 836 | object: createPrimitiveTypeChecker('object'), 837 | string: createPrimitiveTypeChecker('string'), 838 | symbol: createPrimitiveTypeChecker('symbol'), 839 | 840 | any: createAnyTypeChecker(), 841 | arrayOf: createArrayOfTypeChecker, 842 | element: createElementTypeChecker(), 843 | instanceOf: createInstanceTypeChecker, 844 | node: createNodeChecker(), 845 | objectOf: createObjectOfTypeChecker, 846 | oneOf: createEnumTypeChecker, 847 | oneOfType: createUnionTypeChecker, 848 | shape: createShapeTypeChecker 849 | }; 850 | 851 | /** 852 | * inlined Object.is polyfill to avoid requiring consumers ship their own 853 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 854 | */ 855 | /*eslint-disable no-self-compare*/ 856 | function is(x, y) { 857 | // SameValue algorithm 858 | if (x === y) { 859 | // Steps 1-5, 7-10 860 | // Steps 6.b-6.e: +0 != -0 861 | return x !== 0 || 1 / x === 1 / y; 862 | } else { 863 | // Step 6.a: NaN == NaN 864 | return x !== x && y !== y; 865 | } 866 | } 867 | /*eslint-enable no-self-compare*/ 868 | 869 | /** 870 | * We use an Error-like object for backward compatibility as people may call 871 | * PropTypes directly and inspect their output. However, we don't use real 872 | * Errors anymore. We don't inspect their stack anyway, and creating them 873 | * is prohibitively expensive if they are created too often, such as what 874 | * happens in oneOfType() for any type before the one that matched. 875 | */ 876 | function PropTypeError(message) { 877 | this.message = message; 878 | this.stack = ''; 879 | } 880 | // Make `instanceof Error` still work for returned errors. 881 | PropTypeError.prototype = Error.prototype; 882 | 883 | function createChainableTypeChecker(validate) { 884 | if (process.env.NODE_ENV !== 'production') { 885 | var manualPropTypeCallCache = {}; 886 | var manualPropTypeWarningCount = 0; 887 | } 888 | function checkType(isRequired, props, propName, componentName, location, propFullName, secret) { 889 | componentName = componentName || ANONYMOUS; 890 | propFullName = propFullName || propName; 891 | 892 | if (secret !== ReactPropTypesSecret) { 893 | if (throwOnDirectAccess) { 894 | // New behavior only for users of `prop-types` package 895 | invariant( 896 | false, 897 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + 898 | 'Use `PropTypes.checkPropTypes()` to call them. ' + 899 | 'Read more at http://fb.me/use-check-prop-types' 900 | ); 901 | } else if (process.env.NODE_ENV !== 'production' && typeof console !== 'undefined') { 902 | // Old behavior for people using React.PropTypes 903 | var cacheKey = componentName + ':' + propName; 904 | if ( 905 | !manualPropTypeCallCache[cacheKey] && 906 | // Avoid spamming the console because they are often not actionable except for lib authors 907 | manualPropTypeWarningCount < 3 908 | ) { 909 | warning( 910 | false, 911 | 'You are manually calling a React.PropTypes validation ' + 912 | 'function for the `%s` prop on `%s`. This is deprecated ' + 913 | 'and will throw in the standalone `prop-types` package. ' + 914 | 'You may be seeing this warning due to a third-party PropTypes ' + 915 | 'library. See https://fb.me/react-warning-dont-call-proptypes ' + 'for details.', 916 | propFullName, 917 | componentName 918 | ); 919 | manualPropTypeCallCache[cacheKey] = true; 920 | manualPropTypeWarningCount++; 921 | } 922 | } 923 | } 924 | if (props[propName] == null) { 925 | if (isRequired) { 926 | if (props[propName] === null) { 927 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required ' + ('in `' + componentName + '`, but its value is `null`.')); 928 | } 929 | return new PropTypeError('The ' + location + ' `' + propFullName + '` is marked as required in ' + ('`' + componentName + '`, but its value is `undefined`.')); 930 | } 931 | return null; 932 | } else { 933 | return validate(props, propName, componentName, location, propFullName); 934 | } 935 | } 936 | 937 | var chainedCheckType = checkType.bind(null, false); 938 | chainedCheckType.isRequired = checkType.bind(null, true); 939 | 940 | return chainedCheckType; 941 | } 942 | 943 | function createPrimitiveTypeChecker(expectedType) { 944 | function validate(props, propName, componentName, location, propFullName, secret) { 945 | var propValue = props[propName]; 946 | var propType = getPropType(propValue); 947 | if (propType !== expectedType) { 948 | // `propValue` being instance of, say, date/regexp, pass the 'object' 949 | // check, but we can offer a more precise error message here rather than 950 | // 'of type `object`'. 951 | var preciseType = getPreciseType(propValue); 952 | 953 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + preciseType + '` supplied to `' + componentName + '`, expected ') + ('`' + expectedType + '`.')); 954 | } 955 | return null; 956 | } 957 | return createChainableTypeChecker(validate); 958 | } 959 | 960 | function createAnyTypeChecker() { 961 | return createChainableTypeChecker(emptyFunction.thatReturnsNull); 962 | } 963 | 964 | function createArrayOfTypeChecker(typeChecker) { 965 | function validate(props, propName, componentName, location, propFullName) { 966 | if (typeof typeChecker !== 'function') { 967 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside arrayOf.'); 968 | } 969 | var propValue = props[propName]; 970 | if (!Array.isArray(propValue)) { 971 | var propType = getPropType(propValue); 972 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an array.')); 973 | } 974 | for (var i = 0; i < propValue.length; i++) { 975 | var error = typeChecker(propValue, i, componentName, location, propFullName + '[' + i + ']', ReactPropTypesSecret); 976 | if (error instanceof Error) { 977 | return error; 978 | } 979 | } 980 | return null; 981 | } 982 | return createChainableTypeChecker(validate); 983 | } 984 | 985 | function createElementTypeChecker() { 986 | function validate(props, propName, componentName, location, propFullName) { 987 | var propValue = props[propName]; 988 | if (!isValidElement(propValue)) { 989 | var propType = getPropType(propValue); 990 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected a single ReactElement.')); 991 | } 992 | return null; 993 | } 994 | return createChainableTypeChecker(validate); 995 | } 996 | 997 | function createInstanceTypeChecker(expectedClass) { 998 | function validate(props, propName, componentName, location, propFullName) { 999 | if (!(props[propName] instanceof expectedClass)) { 1000 | var expectedClassName = expectedClass.name || ANONYMOUS; 1001 | var actualClassName = getClassName(props[propName]); 1002 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + actualClassName + '` supplied to `' + componentName + '`, expected ') + ('instance of `' + expectedClassName + '`.')); 1003 | } 1004 | return null; 1005 | } 1006 | return createChainableTypeChecker(validate); 1007 | } 1008 | 1009 | function createEnumTypeChecker(expectedValues) { 1010 | if (!Array.isArray(expectedValues)) { 1011 | process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOf, expected an instance of array.') : void 0; 1012 | return emptyFunction.thatReturnsNull; 1013 | } 1014 | 1015 | function validate(props, propName, componentName, location, propFullName) { 1016 | var propValue = props[propName]; 1017 | for (var i = 0; i < expectedValues.length; i++) { 1018 | if (is(propValue, expectedValues[i])) { 1019 | return null; 1020 | } 1021 | } 1022 | 1023 | var valuesString = JSON.stringify(expectedValues); 1024 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of value `' + propValue + '` ' + ('supplied to `' + componentName + '`, expected one of ' + valuesString + '.')); 1025 | } 1026 | return createChainableTypeChecker(validate); 1027 | } 1028 | 1029 | function createObjectOfTypeChecker(typeChecker) { 1030 | function validate(props, propName, componentName, location, propFullName) { 1031 | if (typeof typeChecker !== 'function') { 1032 | return new PropTypeError('Property `' + propFullName + '` of component `' + componentName + '` has invalid PropType notation inside objectOf.'); 1033 | } 1034 | var propValue = props[propName]; 1035 | var propType = getPropType(propValue); 1036 | if (propType !== 'object') { 1037 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type ' + ('`' + propType + '` supplied to `' + componentName + '`, expected an object.')); 1038 | } 1039 | for (var key in propValue) { 1040 | if (propValue.hasOwnProperty(key)) { 1041 | var error = typeChecker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); 1042 | if (error instanceof Error) { 1043 | return error; 1044 | } 1045 | } 1046 | } 1047 | return null; 1048 | } 1049 | return createChainableTypeChecker(validate); 1050 | } 1051 | 1052 | function createUnionTypeChecker(arrayOfTypeCheckers) { 1053 | if (!Array.isArray(arrayOfTypeCheckers)) { 1054 | process.env.NODE_ENV !== 'production' ? warning(false, 'Invalid argument supplied to oneOfType, expected an instance of array.') : void 0; 1055 | return emptyFunction.thatReturnsNull; 1056 | } 1057 | 1058 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) { 1059 | var checker = arrayOfTypeCheckers[i]; 1060 | if (typeof checker !== 'function') { 1061 | warning( 1062 | false, 1063 | 'Invalid argument supplid to oneOfType. Expected an array of check functions, but ' + 1064 | 'received %s at index %s.', 1065 | getPostfixForTypeWarning(checker), 1066 | i 1067 | ); 1068 | return emptyFunction.thatReturnsNull; 1069 | } 1070 | } 1071 | 1072 | function validate(props, propName, componentName, location, propFullName) { 1073 | for (var i = 0; i < arrayOfTypeCheckers.length; i++) { 1074 | var checker = arrayOfTypeCheckers[i]; 1075 | if (checker(props, propName, componentName, location, propFullName, ReactPropTypesSecret) == null) { 1076 | return null; 1077 | } 1078 | } 1079 | 1080 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`.')); 1081 | } 1082 | return createChainableTypeChecker(validate); 1083 | } 1084 | 1085 | function createNodeChecker() { 1086 | function validate(props, propName, componentName, location, propFullName) { 1087 | if (!isNode(props[propName])) { 1088 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` supplied to ' + ('`' + componentName + '`, expected a ReactNode.')); 1089 | } 1090 | return null; 1091 | } 1092 | return createChainableTypeChecker(validate); 1093 | } 1094 | 1095 | function createShapeTypeChecker(shapeTypes) { 1096 | function validate(props, propName, componentName, location, propFullName) { 1097 | var propValue = props[propName]; 1098 | var propType = getPropType(propValue); 1099 | if (propType !== 'object') { 1100 | return new PropTypeError('Invalid ' + location + ' `' + propFullName + '` of type `' + propType + '` ' + ('supplied to `' + componentName + '`, expected `object`.')); 1101 | } 1102 | for (var key in shapeTypes) { 1103 | var checker = shapeTypes[key]; 1104 | if (!checker) { 1105 | continue; 1106 | } 1107 | var error = checker(propValue, key, componentName, location, propFullName + '.' + key, ReactPropTypesSecret); 1108 | if (error) { 1109 | return error; 1110 | } 1111 | } 1112 | return null; 1113 | } 1114 | return createChainableTypeChecker(validate); 1115 | } 1116 | 1117 | function isNode(propValue) { 1118 | switch (typeof propValue) { 1119 | case 'number': 1120 | case 'string': 1121 | case 'undefined': 1122 | return true; 1123 | case 'boolean': 1124 | return !propValue; 1125 | case 'object': 1126 | if (Array.isArray(propValue)) { 1127 | return propValue.every(isNode); 1128 | } 1129 | if (propValue === null || isValidElement(propValue)) { 1130 | return true; 1131 | } 1132 | 1133 | var iteratorFn = getIteratorFn(propValue); 1134 | if (iteratorFn) { 1135 | var iterator = iteratorFn.call(propValue); 1136 | var step; 1137 | if (iteratorFn !== propValue.entries) { 1138 | while (!(step = iterator.next()).done) { 1139 | if (!isNode(step.value)) { 1140 | return false; 1141 | } 1142 | } 1143 | } else { 1144 | // Iterator will provide entry [k,v] tuples rather than values. 1145 | while (!(step = iterator.next()).done) { 1146 | var entry = step.value; 1147 | if (entry) { 1148 | if (!isNode(entry[1])) { 1149 | return false; 1150 | } 1151 | } 1152 | } 1153 | } 1154 | } else { 1155 | return false; 1156 | } 1157 | 1158 | return true; 1159 | default: 1160 | return false; 1161 | } 1162 | } 1163 | 1164 | function isSymbol(propType, propValue) { 1165 | // Native Symbol. 1166 | if (propType === 'symbol') { 1167 | return true; 1168 | } 1169 | 1170 | // 19.4.3.5 Symbol.prototype[@@toStringTag] === 'Symbol' 1171 | if (propValue['@@toStringTag'] === 'Symbol') { 1172 | return true; 1173 | } 1174 | 1175 | // Fallback for non-spec compliant Symbols which are polyfilled. 1176 | if (typeof Symbol === 'function' && propValue instanceof Symbol) { 1177 | return true; 1178 | } 1179 | 1180 | return false; 1181 | } 1182 | 1183 | // Equivalent of `typeof` but with special handling for array and regexp. 1184 | function getPropType(propValue) { 1185 | var propType = typeof propValue; 1186 | if (Array.isArray(propValue)) { 1187 | return 'array'; 1188 | } 1189 | if (propValue instanceof RegExp) { 1190 | // Old webkits (at least until Android 4.0) return 'function' rather than 1191 | // 'object' for typeof a RegExp. We'll normalize this here so that /bla/ 1192 | // passes PropTypes.object. 1193 | return 'object'; 1194 | } 1195 | if (isSymbol(propType, propValue)) { 1196 | return 'symbol'; 1197 | } 1198 | return propType; 1199 | } 1200 | 1201 | // This handles more types than `getPropType`. Only used for error messages. 1202 | // See `createPrimitiveTypeChecker`. 1203 | function getPreciseType(propValue) { 1204 | if (typeof propValue === 'undefined' || propValue === null) { 1205 | return '' + propValue; 1206 | } 1207 | var propType = getPropType(propValue); 1208 | if (propType === 'object') { 1209 | if (propValue instanceof Date) { 1210 | return 'date'; 1211 | } else if (propValue instanceof RegExp) { 1212 | return 'regexp'; 1213 | } 1214 | } 1215 | return propType; 1216 | } 1217 | 1218 | // Returns a string that is postfixed to a warning about an invalid type. 1219 | // For example, "undefined" or "of type array" 1220 | function getPostfixForTypeWarning(value) { 1221 | var type = getPreciseType(value); 1222 | switch (type) { 1223 | case 'array': 1224 | case 'object': 1225 | return 'an ' + type; 1226 | case 'boolean': 1227 | case 'date': 1228 | case 'regexp': 1229 | return 'a ' + type; 1230 | default: 1231 | return type; 1232 | } 1233 | } 1234 | 1235 | // Returns class name of the object, if any. 1236 | function getClassName(propValue) { 1237 | if (!propValue.constructor || !propValue.constructor.name) { 1238 | return ANONYMOUS; 1239 | } 1240 | return propValue.constructor.name; 1241 | } 1242 | 1243 | ReactPropTypes.checkPropTypes = checkPropTypes; 1244 | ReactPropTypes.PropTypes = ReactPropTypes; 1245 | 1246 | return ReactPropTypes; 1247 | }; 1248 | 1249 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) 1250 | 1251 | /***/ }), 1252 | /* 11 */ 1253 | /***/ (function(module, exports, __webpack_require__) { 1254 | 1255 | "use strict"; 1256 | /* WEBPACK VAR INJECTION */(function(process) {/** 1257 | * Copyright 2013-present, Facebook, Inc. 1258 | * All rights reserved. 1259 | * 1260 | * This source code is licensed under the BSD-style license found in the 1261 | * LICENSE file in the root directory of this source tree. An additional grant 1262 | * of patent rights can be found in the PATENTS file in the same directory. 1263 | */ 1264 | 1265 | 1266 | 1267 | if (process.env.NODE_ENV !== 'production') { 1268 | var invariant = __webpack_require__(2); 1269 | var warning = __webpack_require__(6); 1270 | var ReactPropTypesSecret = __webpack_require__(3); 1271 | var loggedTypeFailures = {}; 1272 | } 1273 | 1274 | /** 1275 | * Assert that the values match with the type specs. 1276 | * Error messages are memorized and will only be shown once. 1277 | * 1278 | * @param {object} typeSpecs Map of name to a ReactPropType 1279 | * @param {object} values Runtime values that need to be type-checked 1280 | * @param {string} location e.g. "prop", "context", "child context" 1281 | * @param {string} componentName Name of the component for error messages. 1282 | * @param {?Function} getStack Returns the component stack. 1283 | * @private 1284 | */ 1285 | function checkPropTypes(typeSpecs, values, location, componentName, getStack) { 1286 | if (process.env.NODE_ENV !== 'production') { 1287 | for (var typeSpecName in typeSpecs) { 1288 | if (typeSpecs.hasOwnProperty(typeSpecName)) { 1289 | var error; 1290 | // Prop type validation may throw. In case they do, we don't want to 1291 | // fail the render phase where it didn't fail before. So we log it. 1292 | // After these have been cleaned up, we'll let them throw. 1293 | try { 1294 | // This is intentionally an invariant that gets caught. It's the same 1295 | // behavior as without this statement except with a better message. 1296 | invariant(typeof typeSpecs[typeSpecName] === 'function', '%s: %s type `%s` is invalid; it must be a function, usually from ' + 'React.PropTypes.', componentName || 'React class', location, typeSpecName); 1297 | error = typeSpecs[typeSpecName](values, typeSpecName, componentName, location, null, ReactPropTypesSecret); 1298 | } catch (ex) { 1299 | error = ex; 1300 | } 1301 | warning(!error || error instanceof Error, '%s: type specification of %s `%s` is invalid; the type checker ' + 'function must return `null` or an `Error` but returned a %s. ' + 'You may have forgotten to pass an argument to the type checker ' + 'creator (arrayOf, instanceOf, objectOf, oneOf, oneOfType, and ' + 'shape all require an argument).', componentName || 'React class', location, typeSpecName, typeof error); 1302 | if (error instanceof Error && !(error.message in loggedTypeFailures)) { 1303 | // Only monitor this failure once because there tends to be a lot of the 1304 | // same error. 1305 | loggedTypeFailures[error.message] = true; 1306 | 1307 | var stack = getStack ? getStack() : ''; 1308 | 1309 | warning(false, 'Failed %s type: %s%s', location, error.message, stack != null ? stack : ''); 1310 | } 1311 | } 1312 | } 1313 | } 1314 | } 1315 | 1316 | module.exports = checkPropTypes; 1317 | 1318 | /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(0))) 1319 | 1320 | /***/ }), 1321 | /* 12 */ 1322 | /***/ (function(module, exports, __webpack_require__) { 1323 | 1324 | "use strict"; 1325 | /** 1326 | * Copyright 2013-present, Facebook, Inc. 1327 | * All rights reserved. 1328 | * 1329 | * This source code is licensed under the BSD-style license found in the 1330 | * LICENSE file in the root directory of this source tree. An additional grant 1331 | * of patent rights can be found in the PATENTS file in the same directory. 1332 | */ 1333 | 1334 | 1335 | 1336 | var emptyFunction = __webpack_require__(1); 1337 | var invariant = __webpack_require__(2); 1338 | var ReactPropTypesSecret = __webpack_require__(3); 1339 | 1340 | module.exports = function() { 1341 | function shim(props, propName, componentName, location, propFullName, secret) { 1342 | if (secret === ReactPropTypesSecret) { 1343 | // It is still safe when called from React. 1344 | return; 1345 | } 1346 | invariant( 1347 | false, 1348 | 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' + 1349 | 'Use PropTypes.checkPropTypes() to call them. ' + 1350 | 'Read more at http://fb.me/use-check-prop-types' 1351 | ); 1352 | }; 1353 | shim.isRequired = shim; 1354 | function getShim() { 1355 | return shim; 1356 | }; 1357 | // Important! 1358 | // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`. 1359 | var ReactPropTypes = { 1360 | array: shim, 1361 | bool: shim, 1362 | func: shim, 1363 | number: shim, 1364 | object: shim, 1365 | string: shim, 1366 | symbol: shim, 1367 | 1368 | any: shim, 1369 | arrayOf: getShim, 1370 | element: shim, 1371 | instanceOf: getShim, 1372 | node: shim, 1373 | objectOf: getShim, 1374 | oneOf: getShim, 1375 | oneOfType: getShim, 1376 | shape: getShim 1377 | }; 1378 | 1379 | ReactPropTypes.checkPropTypes = emptyFunction; 1380 | ReactPropTypes.PropTypes = ReactPropTypes; 1381 | 1382 | return ReactPropTypes; 1383 | }; 1384 | 1385 | 1386 | /***/ }), 1387 | /* 13 */ 1388 | /***/ (function(module, exports, __webpack_require__) { 1389 | 1390 | "use strict"; 1391 | 1392 | 1393 | Object.defineProperty(exports, "__esModule", { 1394 | value: true 1395 | }); 1396 | exports.GoogleIcon = undefined; 1397 | 1398 | var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; 1399 | 1400 | var _react = __webpack_require__(4); 1401 | 1402 | var _react2 = _interopRequireDefault(_react); 1403 | 1404 | var _propTypes = __webpack_require__(5); 1405 | 1406 | var _propTypes2 = _interopRequireDefault(_propTypes); 1407 | 1408 | var _styles = __webpack_require__(7); 1409 | 1410 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 1411 | 1412 | var darkSvg = _react2.default.createElement( 1413 | 'svg', 1414 | { version: '1.1', xmlns: 'http://www.w3.org/2000/svg', width: '46px', height: '46px', viewBox: '0 0 46 46', style: _styles.svgStyle }, 1415 | _react2.default.createElement( 1416 | 'defs', 1417 | null, 1418 | _react2.default.createElement( 1419 | 'filter', 1420 | { x: '-50%', y: '-50%', width: '200%', height: '200%', filterUnits: 'objectBoundingBox', id: 'filter-1' }, 1421 | _react2.default.createElement('feOffset', { dx: '0', dy: '1', 'in': 'SourceAlpha', result: 'shadowOffsetOuter1' }), 1422 | _react2.default.createElement('feGaussianBlur', { stdDeviation: '0.5', 'in': 'shadowOffsetOuter1', result: 'shadowBlurOuter1' }), 1423 | _react2.default.createElement('feColorMatrix', { values: '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.168 0', 'in': 'shadowBlurOuter1', type: 'matrix', result: 'shadowMatrixOuter1' }), 1424 | _react2.default.createElement('feOffset', { dx: '0', dy: '0', 'in': 'SourceAlpha', result: 'shadowOffsetOuter2' }), 1425 | _react2.default.createElement('feGaussianBlur', { stdDeviation: '0.5', 'in': 'shadowOffsetOuter2', result: 'shadowBlurOuter2' }), 1426 | _react2.default.createElement('feColorMatrix', { values: '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.084 0', 'in': 'shadowBlurOuter2', type: 'matrix', result: 'shadowMatrixOuter2' }), 1427 | _react2.default.createElement( 1428 | 'feMerge', 1429 | null, 1430 | _react2.default.createElement('feMergeNode', { 'in': 'shadowMatrixOuter1' }), 1431 | _react2.default.createElement('feMergeNode', { 'in': 'shadowMatrixOuter2' }), 1432 | _react2.default.createElement('feMergeNode', { 'in': 'SourceGraphic' }) 1433 | ) 1434 | ), 1435 | _react2.default.createElement('rect', { id: 'path-2', x: '0', y: '0', width: '40', height: '40', rx: '2' }), 1436 | _react2.default.createElement('rect', { id: 'path-3', x: '5', y: '5', width: '38', height: '38', rx: '1' }) 1437 | ), 1438 | _react2.default.createElement( 1439 | 'g', 1440 | { id: 'Google-Button', stroke: 'none', strokeWidth: '1', fill: 'none', fillRule: 'evenodd' }, 1441 | _react2.default.createElement('g', { id: '9-PATCH', transform: 'translate(-608.000000, -219.000000)' }), 1442 | _react2.default.createElement( 1443 | 'g', 1444 | { id: 'btn_google_dark_normal', transform: 'translate(-1.000000, -1.000000)' }, 1445 | _react2.default.createElement( 1446 | 'g', 1447 | { id: 'button', transform: 'translate(4.000000, 4.000000)', filter: 'url(#filter-1)' }, 1448 | _react2.default.createElement( 1449 | 'g', 1450 | { id: 'button-bg' }, 1451 | _react2.default.createElement('use', { fill: '#4285F4', fillRule: 'evenodd' }), 1452 | _react2.default.createElement('use', { fill: 'none' }), 1453 | _react2.default.createElement('use', { fill: 'none' }), 1454 | _react2.default.createElement('use', { fill: 'none' }) 1455 | ) 1456 | ), 1457 | _react2.default.createElement( 1458 | 'g', 1459 | { id: 'button-bg-copy' }, 1460 | _react2.default.createElement('use', { fill: '#FFFFFF', fillRule: 'evenodd' }), 1461 | _react2.default.createElement('use', { fill: 'none' }), 1462 | _react2.default.createElement('use', { fill: 'none' }), 1463 | _react2.default.createElement('use', { fill: 'none' }) 1464 | ), 1465 | _react2.default.createElement( 1466 | 'g', 1467 | { id: 'logo_googleg_48dp', transform: 'translate(15.000000, 15.000000)' }, 1468 | _react2.default.createElement('path', { d: 'M17.64,9.20454545 C17.64,8.56636364 17.5827273,7.95272727 17.4763636,7.36363636 L9,7.36363636 L9,10.845 L13.8436364,10.845 C13.635,11.97 13.0009091,12.9231818 12.0477273,13.5613636 L12.0477273,15.8195455 L14.9563636,15.8195455 C16.6581818,14.2527273 17.64,11.9454545 17.64,9.20454545 L17.64,9.20454545 Z', id: 'Shape', fill: '#4285F4' }), 1469 | _react2.default.createElement('path', { d: 'M9,18 C11.43,18 13.4672727,17.1940909 14.9563636,15.8195455 L12.0477273,13.5613636 C11.2418182,14.1013636 10.2109091,14.4204545 9,14.4204545 C6.65590909,14.4204545 4.67181818,12.8372727 3.96409091,10.71 L0.957272727,10.71 L0.957272727,13.0418182 C2.43818182,15.9831818 5.48181818,18 9,18 L9,18 Z', id: 'Shape', fill: '#34A853' }), 1470 | _react2.default.createElement('path', { d: 'M3.96409091,10.71 C3.78409091,10.17 3.68181818,9.59318182 3.68181818,9 C3.68181818,8.40681818 3.78409091,7.83 3.96409091,7.29 L3.96409091,4.95818182 L0.957272727,4.95818182 C0.347727273,6.17318182 0,7.54772727 0,9 C0,10.4522727 0.347727273,11.8268182 0.957272727,13.0418182 L3.96409091,10.71 L3.96409091,10.71 Z', id: 'Shape', fill: '#FBBC05' }), 1471 | _react2.default.createElement('path', { d: 'M9,3.57954545 C10.3213636,3.57954545 11.5077273,4.03363636 12.4404545,4.92545455 L15.0218182,2.34409091 C13.4631818,0.891818182 11.4259091,0 9,0 C5.48181818,0 2.43818182,2.01681818 0.957272727,4.95818182 L3.96409091,7.29 C4.67181818,5.16272727 6.65590909,3.57954545 9,3.57954545 L9,3.57954545 Z', id: 'Shape', fill: '#EA4335' }), 1472 | _react2.default.createElement('path', { d: 'M0,0 L18,0 L18,18 L0,18 L0,0 Z', id: 'Shape' }) 1473 | ), 1474 | _react2.default.createElement('g', { id: 'handles_square' }) 1475 | ) 1476 | ) 1477 | ); 1478 | 1479 | var lightSvg = _react2.default.createElement( 1480 | 'svg', 1481 | { version: '1.1', xmlns: 'http://www.w3.org/2000/svg', width: '46px', height: '46px', viewBox: '0 0 46 46', style: _styles.svgStyle }, 1482 | _react2.default.createElement( 1483 | 'defs', 1484 | null, 1485 | _react2.default.createElement( 1486 | 'filter', 1487 | { x: '-50%', y: '-50%', width: '200%', height: '200%', filterUnits: 'objectBoundingBox', id: 'filter-1' }, 1488 | _react2.default.createElement('feOffset', { dx: '0', dy: '1', 'in': 'SourceAlpha', result: 'shadowOffsetOuter1' }), 1489 | _react2.default.createElement('feGaussianBlur', { stdDeviation: '0.5', 'in': 'shadowOffsetOuter1', result: 'shadowBlurOuter1' }), 1490 | _react2.default.createElement('feColorMatrix', { values: '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.168 0', 'in': 'shadowBlurOuter1', type: 'matrix', result: 'shadowMatrixOuter1' }), 1491 | _react2.default.createElement('feOffset', { dx: '0', dy: '0', 'in': 'SourceAlpha', result: 'shadowOffsetOuter2' }), 1492 | _react2.default.createElement('feGaussianBlur', { stdDeviation: '0.5', 'in': 'shadowOffsetOuter2', result: 'shadowBlurOuter2' }), 1493 | _react2.default.createElement('feColorMatrix', { values: '0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.084 0', 'in': 'shadowBlurOuter2', type: 'matrix', result: 'shadowMatrixOuter2' }), 1494 | _react2.default.createElement( 1495 | 'feMerge', 1496 | null, 1497 | _react2.default.createElement('feMergeNode', { 'in': 'shadowMatrixOuter1' }), 1498 | _react2.default.createElement('feMergeNode', { 'in': 'shadowMatrixOuter2' }), 1499 | _react2.default.createElement('feMergeNode', { 'in': 'SourceGraphic' }) 1500 | ) 1501 | ), 1502 | _react2.default.createElement('rect', { id: 'path-2', x: '0', y: '0', width: '40', height: '40', rx: '2' }) 1503 | ), 1504 | _react2.default.createElement( 1505 | 'g', 1506 | { id: 'Google-Button', stroke: 'none', strokeWidth: '1', fill: 'none', fillRule: 'evenodd' }, 1507 | _react2.default.createElement('g', { id: '9-PATCH', transform: 'translate(-608.000000, -160.000000)' }), 1508 | _react2.default.createElement( 1509 | 'g', 1510 | { id: 'btn_google_light_normal', transform: 'translate(-1.000000, -1.000000)' }, 1511 | _react2.default.createElement( 1512 | 'g', 1513 | { id: 'button', transform: 'translate(4.000000, 4.000000)', filter: 'url(#filter-1)' }, 1514 | _react2.default.createElement( 1515 | 'g', 1516 | { id: 'button-bg' }, 1517 | _react2.default.createElement('use', { fill: '#FFFFFF', fillRule: 'evenodd' }), 1518 | _react2.default.createElement('use', { fill: 'none' }), 1519 | _react2.default.createElement('use', { fill: 'none' }), 1520 | _react2.default.createElement('use', { fill: 'none' }) 1521 | ) 1522 | ), 1523 | _react2.default.createElement( 1524 | 'g', 1525 | { id: 'logo_googleg_48dp', transform: 'translate(15.000000, 15.000000)' }, 1526 | _react2.default.createElement('path', { d: 'M17.64,9.20454545 C17.64,8.56636364 17.5827273,7.95272727 17.4763636,7.36363636 L9,7.36363636 L9,10.845 L13.8436364,10.845 C13.635,11.97 13.0009091,12.9231818 12.0477273,13.5613636 L12.0477273,15.8195455 L14.9563636,15.8195455 C16.6581818,14.2527273 17.64,11.9454545 17.64,9.20454545 L17.64,9.20454545 Z', id: 'Shape', fill: '#4285F4' }), 1527 | _react2.default.createElement('path', { d: 'M9,18 C11.43,18 13.4672727,17.1940909 14.9563636,15.8195455 L12.0477273,13.5613636 C11.2418182,14.1013636 10.2109091,14.4204545 9,14.4204545 C6.65590909,14.4204545 4.67181818,12.8372727 3.96409091,10.71 L0.957272727,10.71 L0.957272727,13.0418182 C2.43818182,15.9831818 5.48181818,18 9,18 L9,18 Z', id: 'Shape', fill: '#34A853' }), 1528 | _react2.default.createElement('path', { d: 'M3.96409091,10.71 C3.78409091,10.17 3.68181818,9.59318182 3.68181818,9 C3.68181818,8.40681818 3.78409091,7.83 3.96409091,7.29 L3.96409091,4.95818182 L0.957272727,4.95818182 C0.347727273,6.17318182 0,7.54772727 0,9 C0,10.4522727 0.347727273,11.8268182 0.957272727,13.0418182 L3.96409091,10.71 L3.96409091,10.71 Z', id: 'Shape', fill: '#FBBC05' }), 1529 | _react2.default.createElement('path', { d: 'M9,3.57954545 C10.3213636,3.57954545 11.5077273,4.03363636 12.4404545,4.92545455 L15.0218182,2.34409091 C13.4631818,0.891818182 11.4259091,0 9,0 C5.48181818,0 2.43818182,2.01681818 0.957272727,4.95818182 L3.96409091,7.29 C4.67181818,5.16272727 6.65590909,3.57954545 9,3.57954545 L9,3.57954545 Z', id: 'Shape', fill: '#EA4335' }), 1530 | _react2.default.createElement('path', { d: 'M0,0 L18,0 L18,18 L0,18 L0,0 Z', id: 'Shape' }) 1531 | ), 1532 | _react2.default.createElement('g', { id: 'handles_square' }) 1533 | ) 1534 | ) 1535 | ); 1536 | 1537 | var disabledSvg = _react2.default.createElement( 1538 | 'svg', 1539 | { width: '46px', height: '46px', viewBox: '0 0 46 46', version: '1.1', xmlns: 'http://www.w3.org/2000/svg', style: _styles.svgStyle }, 1540 | _react2.default.createElement( 1541 | 'defs', 1542 | null, 1543 | _react2.default.createElement('rect', { id: 'path-1', x: '0', y: '0', width: '40', height: '40', rx: '2' }) 1544 | ), 1545 | _react2.default.createElement( 1546 | 'g', 1547 | { id: 'Google-Button', stroke: 'none', strokeWidth: '1', fill: 'none', fillRule: 'evenodd' }, 1548 | _react2.default.createElement('g', { id: '9-PATCH', transform: 'translate(-788.000000, -219.000000)' }), 1549 | _react2.default.createElement( 1550 | 'g', 1551 | { id: 'btn_google_dark_disabled', transform: 'translate(-1.000000, -1.000000)' }, 1552 | _react2.default.createElement( 1553 | 'g', 1554 | { id: 'button', transform: 'translate(4.000000, 4.000000)' }, 1555 | _react2.default.createElement( 1556 | 'g', 1557 | { id: 'button-bg' }, 1558 | _react2.default.createElement('use', { fillOpacity: '0.08', fill: '#000000', fillRule: 'evenodd' }), 1559 | _react2.default.createElement('use', { fill: 'none' }), 1560 | _react2.default.createElement('use', { fill: 'none' }), 1561 | _react2.default.createElement('use', { fill: 'none' }) 1562 | ) 1563 | ), 1564 | _react2.default.createElement('path', { d: 'M24.001,25.71 L24.001,22.362 L32.425,22.362 C32.551,22.929 32.65,23.46 32.65,24.207 C32.65,29.346 29.203,33 24.01,33 C19.042,33 15.01,28.968 15.01,24 C15.01,19.032 19.042,15 24.01,15 C26.44,15 28.474,15.891 30.031,17.349 L27.475,19.833 C26.827,19.221 25.693,18.501 24.01,18.501 C21.031,18.501 18.601,20.976 18.601,24.009 C18.601,27.042 21.031,29.517 24.01,29.517 C27.457,29.517 28.726,27.132 28.96,25.719 L24.001,25.719 L24.001,25.71 Z', id: 'Shape-Copy', fillOpacity: '0.4', fill: '#000000' }), 1565 | _react2.default.createElement('g', { id: 'handles_square' }) 1566 | ) 1567 | ) 1568 | ); 1569 | 1570 | var GoogleIcon = exports.GoogleIcon = function GoogleIcon(_ref) { 1571 | var disabled = _ref.disabled, 1572 | type = _ref.type; 1573 | return _react2.default.createElement( 1574 | 'div', 1575 | { style: !disabled ? _styles.iconStyle : _extends({}, _styles.iconStyle, _styles.disabledIconStyle) }, 1576 | !disabled ? type === 'dark' ? darkSvg : lightSvg : disabledSvg 1577 | ); 1578 | }; 1579 | 1580 | GoogleIcon.propTypes = { 1581 | disabled: _propTypes2.default.bool, 1582 | type: _propTypes2.default.oneOf(['light', 'dark']) 1583 | }; 1584 | 1585 | GoogleIcon.defaultProps = { 1586 | type: 'dark' 1587 | }; 1588 | 1589 | /***/ }) 1590 | /******/ ]); 1591 | }); -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | interface GoogleButtonProps extends React.HTMLAttributes { 4 | label?: string; 5 | type?: "dark" | "light"; 6 | disabled?: boolean; 7 | } 8 | 9 | /** 10 | * A React Component that renders a button that follows Google's Styleguide 11 | */ 12 | declare class GoogleButton extends React.Component { 13 | 14 | } 15 | 16 | export default GoogleButton; 17 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-google-button", 3 | "version": "0.8.0", 4 | "main": "lib/index.js", 5 | "module": "es/index.js", 6 | "jsnext:main": "es/index.js", 7 | "unpkg": "dist/react-google-button.min.js", 8 | "typings": "./index.d.ts", 9 | "scripts": { 10 | "prepare": "husky", 11 | "clean": "rimraf lib coverage", 12 | "lint": "eslint -c .eslintrc.js ./src", 13 | "lint:fix": "npm run lint -- --fix", 14 | "format": "prettier --single-quote --no-semi --trailing-comma none --write \"src/**/*.js\" \"test/**/*.js\" webpack.config.js", 15 | "test": "mocha -R spec ./test/unit/**", 16 | "test:cov": "nyc --reporter=lcov --reporter=html npm run test", 17 | "build:commonjs": "cross-env BABEL_ENV=commonjs babel src --out-dir lib", 18 | "build:example": "cp dist/react-google-button.min.js examples/basic", 19 | "build:es": "cross-env BABEL_ENV=es babel src --out-dir es", 20 | "build:umd": "cross-env BABEL_ENV=commonjs NODE_ENV=development webpack --mode=development", 21 | "build:umd:min": "cross-env BABEL_ENV=commonjs NODE_ENV=production webpack --mode=production", 22 | "build": "npm run build:commonjs && npm run build:es && npm run build:umd && npm run build:umd:min", 23 | "serve": "npm run build && http-server examples/basic", 24 | "watch:umd": "npm run build:umd -- --progress --colors --watch", 25 | "watch:lib": "npm run build:lib -- --watch", 26 | "watch:es": "npm run build:es -- --watch", 27 | "watch": "npm run watch:es" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "git+https://github.com/prescottprue/react-google-button.git" 32 | }, 33 | "keywords": [ 34 | "react", 35 | "google", 36 | "button", 37 | "authentication" 38 | ], 39 | "author": "prescottprue", 40 | "contributors": [ 41 | { 42 | "name": "prescottprue", 43 | "email": "sprue.dev@gmail.com" 44 | } 45 | ], 46 | "license": "MIT", 47 | "bugs": { 48 | "url": "https://github.com/prescottprue/react-google-button/issues" 49 | }, 50 | "homepage": "https://github.com/prescottprue/react-google-button", 51 | "dependencies": { 52 | "prop-types": "^15.8.1" 53 | }, 54 | "peerDependencies": { 55 | "react": ">= 16.8.0" 56 | }, 57 | "devDependencies": { 58 | "@babel/cli": "^7.24.5", 59 | "@babel/core": "^7.24.5", 60 | "@babel/plugin-proposal-class-properties": "^7.18.6", 61 | "@babel/plugin-proposal-export-default-from": "^7.24.1", 62 | "@babel/plugin-transform-modules-commonjs": "^7.24.1", 63 | "@babel/preset-env": "^7.24.5", 64 | "@babel/preset-react": "^7.24.1", 65 | "@babel/register": "^7.23.7", 66 | "babel-eslint": "^10.1.0", 67 | "babel-loader": "^8.0.6", 68 | "chai": "^4.2.0", 69 | "chai-enzyme": "1.0.0-beta.1", 70 | "cheerio": "^1.0.0-rc.3", 71 | "cross-env": "^7.0.2", 72 | "enzyme": "^3.11.0", 73 | "enzyme-adapter-react-16": "^1.15.1", 74 | "eslint": "^6.8.0", 75 | "eslint-config-prettier": "^6.10.0", 76 | "eslint-config-standard": "^14.1.0", 77 | "eslint-config-standard-react": "^9.2.0", 78 | "eslint-plugin-babel": "^5.3.0", 79 | "eslint-plugin-import": "^2.20.1", 80 | "eslint-plugin-jsdoc": "^22.1.0", 81 | "eslint-plugin-jsx-a11y": "^6.2.3", 82 | "eslint-plugin-node": "^10.0.0", 83 | "eslint-plugin-prettier": "^3.1.0", 84 | "eslint-plugin-promise": "^4.2.1", 85 | "eslint-plugin-react": "^7.16.0", 86 | "eslint-plugin-standard": "^4.0.0", 87 | "http-server": "^0.12.0", 88 | "husky": "^9.0.11", 89 | "lint-staged": "^15.2.2", 90 | "mocha": "^7.1.1", 91 | "nyc": "^15.0.0", 92 | "prettier": "^2.0.2", 93 | "react": "16.13.0", 94 | "react-dom": "16.13.0", 95 | "rimraf": "^3.0.0", 96 | "sinon": "^9.0.1", 97 | "sinon-chai": "^3.3.0", 98 | "terser-webpack-plugin": "^2.3.5", 99 | "webpack": "^5.91.0", 100 | "webpack-cli": "^5.1.4" 101 | }, 102 | "lint-staged": { 103 | "*.{json,md}": [ 104 | "prettier --write" 105 | ], 106 | "*.{js,ts}": [ 107 | "eslint --fix" 108 | ] 109 | }, 110 | "packageManager": "yarn@4.2.1" 111 | } 112 | -------------------------------------------------------------------------------- /src/GoogleButton.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react' 2 | import PropTypes from 'prop-types' 3 | import { GoogleIcon } from './icons' 4 | import { darkStyle, lightStyle, disabledStyle, hoverStyle } from './styles' 5 | 6 | export default function GoogleButton({ 7 | label = 'Sign in with Google', 8 | disabled = false, 9 | tabIndex = 0, 10 | onClick = () => {}, 11 | type = 'dark', 12 | style 13 | }) { 14 | const [hovered, setHovered] = useState(false) 15 | const mouseOver = () => { 16 | if (!disabled) { 17 | setHovered(true) 18 | } 19 | } 20 | 21 | const mouseOut = () => { 22 | if (!disabled) { 23 | setHovered(false) 24 | } 25 | } 26 | 27 | const getStyle = () => { 28 | const baseStyle = type === 'dark' ? darkStyle : lightStyle 29 | if (hovered) { 30 | return { ...baseStyle, ...hoverStyle, ...style } 31 | } 32 | if (disabled) { 33 | return { ...baseStyle, ...disabledStyle, ...style } 34 | } 35 | return { ...baseStyle, ...style } 36 | } 37 | 38 | const handleClick = (e) => { 39 | if (!disabled) { 40 | onClick(e) 41 | } 42 | } 43 | 44 | return ( 45 |
54 | 55 | {label} 56 |
57 | ) 58 | } 59 | 60 | GoogleButton.propTypes = { 61 | label: PropTypes.string, 62 | disabled: PropTypes.bool, 63 | tabIndex: PropTypes.number, 64 | onClick: PropTypes.func, 65 | type: PropTypes.oneOf(['light', 'dark']), 66 | style: PropTypes.object 67 | } 68 | -------------------------------------------------------------------------------- /src/icons.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PropTypes from 'prop-types' 3 | import { iconStyle, disabledIconStyle, svgStyle } from './styles' 4 | 5 | const darkSvg = ( 6 | 14 | 15 | 23 | 24 | 29 | 35 | 36 | 41 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 63 | 64 | 68 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 92 | 97 | 102 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | ) 114 | 115 | const lightSvg = ( 116 | 124 | 125 | 133 | 134 | 139 | 145 | 146 | 151 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 172 | 173 | 177 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 195 | 200 | 205 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | ) 217 | 218 | const disabledSvg = ( 219 | 227 | 228 | 229 | 230 | 237 | 238 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 256 | 257 | 258 | 259 | 260 | ) 261 | 262 | export const GoogleIcon = ({ disabled, type = 'dark' }) => ( 263 |
264 | {!disabled ? (type === 'dark' ? darkSvg : lightSvg) : disabledSvg} 265 |
266 | ) 267 | 268 | GoogleIcon.propTypes = { 269 | disabled: PropTypes.bool, 270 | type: PropTypes.oneOf(['light', 'dark']) 271 | } 272 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export GoogleButton from './GoogleButton' 2 | export default from './GoogleButton' 3 | -------------------------------------------------------------------------------- /src/styles.js: -------------------------------------------------------------------------------- 1 | const baseStyle = { 2 | height: '50px', 3 | width: '240px', 4 | border: 'none', 5 | textAlign: 'center', 6 | verticalAlign: 'center', 7 | boxShadow: '0 2px 4px 0 rgba(0,0,0,.25)', 8 | fontSize: '16px', 9 | lineHeight: '48px', 10 | display: 'block', 11 | borderRadius: '1px', 12 | transition: 'background-color .218s, border-color .218s, box-shadow .218s', 13 | fontFamily: 'Roboto,arial,sans-serif', 14 | cursor: 'pointer', 15 | userSelect: 'none' 16 | } 17 | 18 | export const darkStyle = { 19 | backgroundColor: '#4285f4', 20 | color: '#fff', 21 | ...baseStyle 22 | } 23 | 24 | export const lightStyle = { 25 | backgroundColor: '#fff', 26 | color: 'rgba(0,0,0,.54)', 27 | ...baseStyle 28 | } 29 | 30 | export const iconStyle = { 31 | width: '48px', 32 | height: '48px', 33 | textAlign: 'center', 34 | verticalAlign: 'center', 35 | display: 'block', 36 | marginTop: '1px', 37 | marginLeft: '1px', 38 | float: 'left', 39 | backgroundColor: '#fff', 40 | borderRadius: '1px', 41 | whiteSpace: 'nowrap' 42 | } 43 | 44 | export const svgStyle = { 45 | width: '48px', 46 | height: '48px', 47 | display: 'block' 48 | } 49 | 50 | export const hoverStyle = { 51 | boxShadow: '0 0 3px 3px rgba(66,133,244,.3)', 52 | transition: 'background-color .218s, border-color .218s, box-shadow .218s' 53 | } 54 | 55 | // export const pressedStyle = { 56 | // backgroundColor: '#3367D6' 57 | // } 58 | 59 | export const disabledStyle = { 60 | backgroundColor: 'rgba(37, 5, 5, .08)', 61 | color: 'rgba(0, 0, 0, .40)', 62 | cursor: 'not-allowed' 63 | } 64 | 65 | export const disabledIconStyle = { 66 | backgroundColor: 'transparent' 67 | } 68 | -------------------------------------------------------------------------------- /test/.eslintrc: -------------------------------------------------------------------------------- 1 | extends: ../.eslintrc 2 | 3 | globals: 4 | sinon: true 5 | expect: true 6 | assert: true 7 | describe: true 8 | it: true 9 | after: true 10 | afterEach: true 11 | before: true 12 | beforeEach: true 13 | 14 | 15 | rules: 16 | no-unused-expressions: [0] 17 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require @babel/register 2 | --require ./test/setup 3 | --recursive 4 | --colors 5 | --report lcov 6 | -------------------------------------------------------------------------------- /test/setup.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-unused-vars */ 2 | const chai = (global.chai = require('chai')) 3 | const sinon = (global.sinon = require('sinon')) 4 | const expect = (global.expect = chai.expect) 5 | const should = (global.should = chai.should()) 6 | const enzyme = require('enzyme') 7 | const chaiEnzyme = require('chai-enzyme') 8 | const Adapter = require('enzyme-adapter-react-16') 9 | const sinonChai = require('sinon-chai') 10 | 11 | enzyme.configure({ adapter: new Adapter() }) 12 | 13 | chai.use(chaiEnzyme()) 14 | chai.use(sinonChai) 15 | -------------------------------------------------------------------------------- /test/unit/index.spec.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import GoogleButton from '../../src' 3 | import { shallow } from 'enzyme' 4 | 5 | const defaults = { 6 | label: 'Sign in with Google', 7 | backgroundColor: '#4285f4' 8 | } 9 | 10 | const disabledStyle = { 11 | backgroundColor: 'rgba(37, 5, 5, .08)' 12 | } 13 | 14 | describe('react-google-button Library', () => { 15 | describe('exports a component', () => { 16 | expect(GoogleButton).to.exist 17 | }) 18 | 19 | describe('Component', () => { 20 | let _component 21 | 22 | describe('Default Props', () => { 23 | beforeEach(() => { 24 | _component = shallow() 25 | }) 26 | it('Renders div', () => { 27 | const firstDiv = _component.find('div') 28 | expect(firstDiv).to.exist 29 | }) 30 | 31 | it('Sets correct label text', () => { 32 | const firstDiv = _component.find('span') 33 | expect(firstDiv.first().text()).to.equal(defaults.label) 34 | }) 35 | 36 | it('Applies styles', () => { 37 | const firstDiv = _component.find('div') 38 | expect(firstDiv.first()).to.have.style( 39 | 'background-color', 40 | defaults.backgroundColor 41 | ) 42 | }) 43 | }) 44 | 45 | describe('Custom Label', () => { 46 | const customLabel = 'Custom Label' 47 | 48 | beforeEach(() => { 49 | _component = shallow() 50 | }) 51 | 52 | it('Renders div', () => { 53 | const firstDiv = _component.find('div') 54 | expect(firstDiv).to.exist 55 | }) 56 | 57 | it('Sets correct label text', () => { 58 | const firstDiv = _component.find('span') 59 | expect(firstDiv.first().text()).to.equal(customLabel) 60 | }) 61 | }) 62 | 63 | describe('Disabled', () => { 64 | beforeEach(() => { 65 | _component = shallow() 66 | }) 67 | 68 | it('Renders div', () => { 69 | const firstDiv = _component.find('div') 70 | expect(firstDiv).to.exist 71 | }) 72 | 73 | it('Applies background color', () => { 74 | const firstDiv = _component.find('div') 75 | expect(firstDiv.first()).to.have.style( 76 | 'background-color', 77 | disabledStyle.backgroundColor 78 | ) 79 | }) 80 | }) 81 | 82 | describe('onClick', () => { 83 | let clickSpy 84 | beforeEach(() => { 85 | clickSpy = sinon.spy() 86 | _component = shallow() 87 | }) 88 | 89 | it('Calls onClick prop when clicked', () => { 90 | _component.simulate('click') 91 | expect(clickSpy).to.have.been.calledOnce 92 | }) 93 | }) 94 | 95 | describe('Hover', () => { 96 | beforeEach(() => { 97 | _component = shallow() 98 | }) 99 | 100 | it('Sets hover style on hover', () => { 101 | _component.simulate('mouseover') 102 | const firstDiv = _component.find('div') 103 | expect(firstDiv.first()).to.have.style( 104 | 'box-shadow', 105 | '0 0 3px 3px rgba(66,133,244,.3)' 106 | ) 107 | expect(firstDiv.first()).to.have.style( 108 | 'transition', 109 | 'background-color .218s, border-color .218s, box-shadow .218s' 110 | ) 111 | }) 112 | 113 | it('Sets original style when mouse leave', () => { 114 | _component.simulate('mouseout') 115 | const firstDiv = _component.find('div') 116 | expect(firstDiv.first()).to.have.style( 117 | 'background-color', 118 | defaults.backgroundColor 119 | ) 120 | expect(firstDiv.first()).to.have.style( 121 | 'background-color', 122 | defaults.backgroundColor 123 | ) 124 | }) 125 | }) 126 | }) 127 | }) 128 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const webpack = require('webpack') 3 | const TerserPlugin = require('terser-webpack-plugin') 4 | const pkg = require('./package.json') 5 | 6 | const config = { 7 | module: { 8 | rules: [ 9 | { test: /\.js$/, loader: 'babel-loader', exclude: [/node_modules/] } 10 | ] 11 | }, 12 | entry: './src/index.js', 13 | plugins: [ 14 | new webpack.BannerPlugin({ 15 | banner: 'react-google-button.js v' + pkg.version + ' | (c) prescottprue', 16 | raw: false, 17 | entryOnly: true 18 | }) 19 | ], 20 | externals: { 21 | react: { 22 | commonjs: 'react', 23 | commonjs2: 'react', 24 | amd: 'react', 25 | root: 'React' 26 | }, 27 | 'prop-types': { 28 | commonjs: 'prop-types', 29 | commonjs2: 'prop-types', 30 | amd: 'prop-types', 31 | root: 'PropTypes' 32 | } 33 | }, 34 | output: { 35 | filename: `react-google-button${ 36 | process.env.NODE_ENV === 'production' ? '.min' : '' 37 | }.js`, 38 | library: 'ReactGoogleButton', 39 | libraryTarget: 'umd', 40 | publicPath: '/dist/' 41 | }, 42 | resolve: { 43 | extensions: ['.js'] 44 | } 45 | } 46 | 47 | if (process.env.NODE_ENV === 'production') { 48 | config.optimization = { 49 | minimizer: [ 50 | new TerserPlugin({ 51 | cache: true, 52 | parallel: true, 53 | terserOptions: { 54 | compress: false, 55 | ecma: 6, 56 | mangle: true 57 | }, 58 | sourceMap: true 59 | }) 60 | ] 61 | } 62 | } 63 | 64 | module.exports = config 65 | --------------------------------------------------------------------------------