react-google-invisible-recaptcha
Advanced tools
Comparing version 0.2.11 to 1.0.0-rc.0
@@ -1,38 +0,25 @@ | ||
'use strict'; | ||
"use strict"; | ||
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
}); | ||
exports["default"] = void 0; | ||
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; }; | ||
var React = _interopRequireWildcard(require("react")); | ||
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; }; }(); | ||
var _uuid = require("uuid"); | ||
var _react = require('react'); | ||
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } | ||
var _react2 = _interopRequireDefault(_react); | ||
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; } | ||
var _propTypes = require('prop-types'); | ||
var _propTypes2 = _interopRequireDefault(_propTypes); | ||
var _v = require('uuid/v4'); | ||
var _v2 = _interopRequireDefault(_v); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
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; } | ||
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; } | ||
var renderers = []; | ||
var injectScript = function injectScript(locale) { | ||
var injectScript = function injectScript(locale, nonce) { | ||
window.GoogleRecaptchaLoaded = function () { | ||
while (renderers.length) { | ||
var renderer = renderers.shift(); | ||
renderer(); | ||
renderer === null || renderer === void 0 ? void 0 : renderer(); | ||
} | ||
@@ -42,131 +29,137 @@ }; | ||
var script = document.createElement('script'); | ||
script.id = 'recaptcha'; | ||
script.src = 'https://www.google.com/recaptcha/api.js?hl=' + locale + '&onload=GoogleRecaptchaLoaded&render=explicit'; | ||
script.type = 'text/javascript'; | ||
script.async = true; | ||
script.defer = true; | ||
script.id = 'recaptcha'; | ||
script.onerror = function (error) { | ||
throw error; | ||
}; | ||
script.src = "https://www.google.com/recaptcha/api.js?".concat(locale && 'hl=' + locale, "&onload=GoogleRecaptchaLoaded&render=explicit"); | ||
script.type = 'text/javascript'; | ||
nonce && script.setAttribute("nonce", nonce); | ||
document.body.appendChild(script); | ||
}; | ||
var GoogleRecaptcha = function (_React$Component) { | ||
_inherits(GoogleRecaptcha, _React$Component); | ||
var defaultProps = { | ||
badge: 'bottomright', | ||
locale: '', | ||
onExpired: function onExpired() { | ||
return undefined; | ||
}, | ||
onError: function onError() { | ||
return undefined; | ||
}, | ||
onLoaded: function onLoaded() { | ||
return undefined; | ||
}, | ||
onResolved: function onResolved() { | ||
return undefined; | ||
}, | ||
tabindex: 0 | ||
}; | ||
var GoogleRecaptcha = /*#__PURE__*/React.forwardRef(function (props, ref) { | ||
var _props$badge = props.badge, | ||
badge = _props$badge === void 0 ? defaultProps.badge : _props$badge, | ||
_props$locale = props.locale, | ||
locale = _props$locale === void 0 ? defaultProps.locale : _props$locale, | ||
nonce = props.nonce, | ||
_props$onExpired = props.onExpired, | ||
onExpired = _props$onExpired === void 0 ? defaultProps.onExpired : _props$onExpired, | ||
_props$onError = props.onError, | ||
onError = _props$onError === void 0 ? defaultProps.onError : _props$onError, | ||
_props$onLoaded = props.onLoaded, | ||
onLoaded = _props$onLoaded === void 0 ? defaultProps.onLoaded : _props$onLoaded, | ||
_props$onResolved = props.onResolved, | ||
onResolved = _props$onResolved === void 0 ? defaultProps.onResolved : _props$onResolved, | ||
sitekey = props.sitekey, | ||
style = props.style, | ||
_props$tabindex = props.tabindex, | ||
tabindex = _props$tabindex === void 0 ? defaultProps.tabindex : _props$tabindex; | ||
var callbackName = 'GoogleRecaptchaResolved-' + (0, _uuid.v4)(); | ||
React.useEffect(function () { | ||
// @ts-expect-error window attachment. | ||
window[callbackName] = onResolved; | ||
function GoogleRecaptcha() { | ||
_classCallCheck(this, GoogleRecaptcha); | ||
if (typeof ref === 'function' || !(ref !== null && ref !== void 0 && ref.current)) { | ||
return; | ||
} | ||
return _possibleConstructorReturn(this, (GoogleRecaptcha.__proto__ || Object.getPrototypeOf(GoogleRecaptcha)).apply(this, arguments)); | ||
} | ||
var domNode = ref.current; | ||
_createClass(GoogleRecaptcha, [{ | ||
key: 'componentDidMount', | ||
value: function componentDidMount() { | ||
var _this2 = this; | ||
var loaded = function loaded() { | ||
if (ref.current) { | ||
var _window$grecaptcha$re, _window$grecaptcha; | ||
var _props = this.props, | ||
sitekey = _props.sitekey, | ||
locale = _props.locale, | ||
badge = _props.badge, | ||
tabindex = _props.tabindex, | ||
onResolved = _props.onResolved, | ||
onError = _props.onError, | ||
onExpired = _props.onExpired, | ||
onLoaded = _props.onLoaded; | ||
var _wrapper = document.createElement('div'); // This wrapper must be appended to the DOM immediately before rendering | ||
// reCaptcha. Otherwise multiple reCaptchas will act jointly somehow. | ||
this.callbackName = 'GoogleRecaptchaResolved-' + (0, _v2.default)(); | ||
window[this.callbackName] = onResolved; | ||
ref.current.appendChild(_wrapper); | ||
var loaded = function loaded() { | ||
if (_this2.container) { | ||
var wrapper = document.createElement('div'); | ||
// This wrapper must be appended to the DOM immediately before rendering | ||
// reCaptcha. Otherwise multiple reCaptchas will act jointly somehow. | ||
_this2.container.appendChild(wrapper); | ||
var recaptchaId = window.grecaptcha.render(wrapper, { | ||
sitekey: sitekey, | ||
size: 'invisible', | ||
badge: badge, | ||
tabindex: tabindex, | ||
callback: _this2.callbackName, | ||
'error-callback': onError, | ||
'expired-callback': onExpired | ||
}); | ||
_this2.execute = function () { | ||
return window.grecaptcha.execute(recaptchaId); | ||
var _recaptchaId = (_window$grecaptcha$re = (_window$grecaptcha = window.grecaptcha).render) === null || _window$grecaptcha$re === void 0 ? void 0 : _window$grecaptcha$re.call(_window$grecaptcha, _wrapper, { | ||
badge: badge, | ||
callback: callbackName, | ||
'error-callback': onError, | ||
'expired-callback': onExpired, | ||
sitekey: sitekey, | ||
size: 'invisible', | ||
tabindex: tabindex | ||
}); | ||
if (_recaptchaId) { | ||
ref.current.callbacks = { | ||
execute: function execute() { | ||
var _window$grecaptcha$ex, _window$grecaptcha2; | ||
return (_window$grecaptcha$ex = (_window$grecaptcha2 = window.grecaptcha).execute) === null || _window$grecaptcha$ex === void 0 ? void 0 : _window$grecaptcha$ex.call(_window$grecaptcha2, _recaptchaId); | ||
}, | ||
getResponse: function getResponse() { | ||
var _window$grecaptcha$ge, _window$grecaptcha3; | ||
return (_window$grecaptcha$ge = (_window$grecaptcha3 = window.grecaptcha).getResponse) === null || _window$grecaptcha$ge === void 0 ? void 0 : _window$grecaptcha$ge.call(_window$grecaptcha3, _recaptchaId); | ||
}, | ||
reset: function reset() { | ||
var _window$grecaptcha$re2, _window$grecaptcha4; | ||
return (_window$grecaptcha$re2 = (_window$grecaptcha4 = window.grecaptcha).reset) === null || _window$grecaptcha$re2 === void 0 ? void 0 : _window$grecaptcha$re2.call(_window$grecaptcha4, _recaptchaId); | ||
} | ||
}; | ||
_this2.reset = function () { | ||
return window.grecaptcha.reset(recaptchaId); | ||
}; | ||
_this2.getResponse = function () { | ||
return window.grecaptcha.getResponse(recaptchaId); | ||
}; | ||
onLoaded(); | ||
} | ||
}; | ||
} | ||
}; | ||
if (window.grecaptcha && window.grecaptcha.render && window.grecaptcha.execute && window.grecaptcha.reset && window.grecaptcha.getResponse) { | ||
loaded(); | ||
} else { | ||
renderers.push(loaded); | ||
if (!document.querySelector('#recaptcha')) { | ||
injectScript(locale); | ||
} | ||
if (window.grecaptcha && window.grecaptcha.render && window.grecaptcha.execute && window.grecaptcha.reset && window.grecaptcha.getResponse) { | ||
loaded(); | ||
} else { | ||
renderers.push(loaded); | ||
if (!document.querySelector('#recaptcha')) { | ||
injectScript(locale, nonce); | ||
} | ||
} | ||
}, { | ||
key: 'componentWillUnmount', | ||
value: function componentWillUnmount() { | ||
while (this.container.firstChild) { | ||
this.container.removeChild(this.container.firstChild); | ||
} | ||
// There is a chance that the reCAPTCHA API lib is not loaded yet, so check | ||
// before invoking reset. | ||
if (this.reset) { | ||
this.reset(); | ||
} | ||
delete window[this.callbackName]; | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var _this3 = this; | ||
var style = this.props.style; | ||
return function () { | ||
var _ref$current, _ref$current$callback; | ||
return _react2.default.createElement('div', _extends({ | ||
ref: function ref(_ref) { | ||
return _this3.container = _ref; | ||
} | ||
}, style && { style: style })); | ||
} | ||
}]); | ||
while (domNode !== null && domNode !== void 0 && domNode.firstChild) { | ||
domNode.removeChild(domNode.firstChild); | ||
} // There is a chance that the reCAPTCHA API lib is not loaded yet, so check | ||
// before invoking reset. | ||
return GoogleRecaptcha; | ||
}(_react2.default.Component); | ||
GoogleRecaptcha.propTypes = { | ||
sitekey: _propTypes2.default.string.isRequired, | ||
locale: _propTypes2.default.string, | ||
badge: _propTypes2.default.oneOf(['bottomright', 'bottomleft', 'inline']), | ||
tabindex: _propTypes2.default.number, | ||
onResolved: _propTypes2.default.func, | ||
onError: _propTypes2.default.func, | ||
onExpired: _propTypes2.default.func, | ||
onLoaded: _propTypes2.default.func, | ||
style: _propTypes2.default.object | ||
}; | ||
(_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : (_ref$current$callback = _ref$current.callbacks) === null || _ref$current$callback === void 0 ? void 0 : _ref$current$callback.reset(); // @ts-expect-error window attachment. | ||
GoogleRecaptcha.defaultProps = { | ||
locale: 'en', | ||
badge: 'bottomright', | ||
tabindex: 0, | ||
onResolved: function onResolved() {}, | ||
onError: function onError() {}, | ||
onExpired: function onExpired() {}, | ||
onLoaded: function onLoaded() {} | ||
}; | ||
exports.default = GoogleRecaptcha; | ||
delete window[callbackName]; | ||
}; | ||
}, []); | ||
return /*#__PURE__*/React.createElement("div", { | ||
ref: ref, | ||
style: style | ||
}); | ||
}); | ||
GoogleRecaptcha.defaultProps = defaultProps; | ||
GoogleRecaptcha.displayName = 'GoogleRecaptcha'; | ||
var _default = GoogleRecaptcha; | ||
exports["default"] = _default; |
{ | ||
"name": "react-google-invisible-recaptcha", | ||
"author": "szchenghuang <szchenghuang@gmail.com>", | ||
"version": "0.2.11", | ||
"version": "1.0.0-rc.0", | ||
"description": "A React component which is simply interested in Google invisible reCaptcha.", | ||
"main": "index.js", | ||
"main": "dist/index.js", | ||
"keywords": [ | ||
@@ -11,3 +11,4 @@ "react", | ||
"invisible", | ||
"recaptcha" | ||
"recaptcha", | ||
"typescript" | ||
], | ||
@@ -28,36 +29,32 @@ "license": "MIT", | ||
"prebuild": "rm -rf dist && mkdir dist ", | ||
"build": "babel ./src --out-dir ./dist", | ||
"build": "babel ./src --out-dir ./dist --extensions .tsx && npx tsc --emitDeclarationOnly", | ||
"test": "echo \"No test specified\" && exit 0" | ||
}, | ||
"dependencies": { | ||
"prop-types": "^15.6.0", | ||
"uuid": "^3.1.0" | ||
"@types/uuid": "^8.3.0", | ||
"uuid": "^8.3.2" | ||
}, | ||
"peerDependencies": { | ||
"react": "16.*" | ||
"react": "^17.0.0-0" | ||
}, | ||
"devDependencies": { | ||
"babel-cli": "^6.26.0", | ||
"babel-core": "^6.26.0", | ||
"babel-eslint": "^8.0.1", | ||
"babel-loader": "^7.1.2", | ||
"babel-plugin-transform-object-rest-spread": "^6.26.0", | ||
"babel-preset-es2015": "^6.24.1", | ||
"babel-preset-react": "^6.24.1", | ||
"babel-register": "^6.26.0", | ||
"babel-runtime": "^6.26.0", | ||
"eslint": "^4.9.0", | ||
"eslint-config-airbnb": "^16.1.0", | ||
"eslint-config-google": "^0.9.1", | ||
"eslint-config-standard": "^10.2.1", | ||
"eslint-plugin-import": "^2.8.0", | ||
"eslint-plugin-jsx-a11y": "^6.0.2", | ||
"eslint-plugin-node": "^5.2.1", | ||
"eslint-plugin-promise": "^3.6.0", | ||
"eslint-plugin-react": "^7.4.0", | ||
"eslint-plugin-standard": "^3.0.1", | ||
"html-webpack-plugin": "^2.30.1", | ||
"react": "^16.3.1", | ||
"react-dom": "^16.3.1", | ||
"webpack": "^3.8.1" | ||
"@babel/cli": "^7.13.16", | ||
"@babel/core": "^7.14.0", | ||
"@babel/preset-env": "^7.14.1", | ||
"@babel/preset-react": "^7.13.13", | ||
"@babel/preset-typescript": "^7.13.0", | ||
"@types/react": "^17.0.5", | ||
"@types/react-dom": "^17.0.3", | ||
"@typescript-eslint/eslint-plugin": "^4.22.1", | ||
"@typescript-eslint/parser": "^4.22.1", | ||
"babel-loader": "^8.2.2", | ||
"eslint": "^7.26.0", | ||
"eslint-plugin-babel": "^5.3.1", | ||
"eslint-plugin-react": "^7.23.2", | ||
"html-webpack-plugin": "^5.3.1", | ||
"react": "^17.0.0-0", | ||
"react-dom": "^17.0.0-0", | ||
"typescript": "^4.2.4", | ||
"webpack": "^5.36.2", | ||
"webpack-cli": "^4.7.0" | ||
}, | ||
@@ -67,3 +64,4 @@ "directories": { | ||
"example": "example" | ||
} | ||
}, | ||
"types": "dist/index.d.ts" | ||
} |
# react-google-invisible-recaptcha # | ||
A React component which is simply interested in Google invisible reCAPTCHA. | ||
A React component which is interested in only Google invisible reCAPTCHA. | ||
* Support multiple reCAPTCHA widgets on one page. | ||
* Vallina JS. | ||
* Support React hooks. | ||
* Support Typescript. | ||
## Migration from 0.x to 1.0.0 | ||
```js | ||
// Version 0.x | ||
<Recaptcha ref={ref => this.recaptcha = ref} ... /> | ||
// this.recaptcha.execute invokes the reCAPTCHA check. | ||
// Version 1.0.0 | ||
const refCaptcha = React.useRef(null) // or React.createRef(). | ||
<Recaptcha ref={refRecaptcha} ... /> | ||
// refRecaptcha.current.callbacks.execute invokes the reCAPTCHA check. | ||
// ^^^^^^^^^^^^^^^^^^ | ||
``` | ||
## [Demo][demo] ## | ||
@@ -16,41 +31,4 @@ | ||
Below is a component which coordinates the procedure. | ||
See the `example/` folder for an example. | ||
```js | ||
class Example extends React.Component { | ||
constructor( props ) { | ||
super( props ); | ||
this.state = { value: '' }; | ||
this.onSubmit = this.onSubmit.bind( this ); | ||
this.onResolved = this.onResolved.bind( this ); | ||
} | ||
render() { | ||
return ( | ||
<div> | ||
<input | ||
type="text" | ||
value={ this.state.value } | ||
onChange={ event => this.setState( { value: event.target.value } ) } /> | ||
<button onClick={ this.onSubmit }>Submit</button> | ||
<Recaptcha | ||
ref={ ref => this.recaptcha = ref } | ||
sitekey="<sitekey>" | ||
onResolved={ this.onResolved } /> | ||
</div> | ||
); | ||
} | ||
onSubmit() { | ||
if ( '' == this.state.value ) { | ||
alert( 'Validation failed! Input cannot be empty.' ); | ||
this.recaptcha.reset(); | ||
} else { | ||
this.recaptcha.execute(); | ||
} | ||
} | ||
onResolved() { | ||
alert( 'Recaptcha resolved with response: ' + this.recaptcha.getResponse() ); | ||
} | ||
} | ||
``` | ||
## Install ## | ||
@@ -68,5 +46,5 @@ | ||
<Recaptcha | ||
ref={ ref => this.recaptcha = ref } | ||
sitekey={ <sitekey> } | ||
onResolved={ () => console.log( 'Human detected.' ) } /> | ||
onResolved={() => console.log('Human detected.')} /> | ||
ref={refRecaptcha} | ||
sitekey={<sitekey>} | ||
``` | ||
@@ -82,10 +60,11 @@ | ||
* badge: `bottomright`, `bottomleft`, or `inline`. **Default: bottomright.** | ||
* locale: in which language it speaks. **Default: en.** | ||
* badge: `bottomright`, `bottomleft`, or `inline`. **Default: bottomright.** | ||
* tabindex: tabindex of the challenge. **Default: 0.** | ||
* onResolved: callback when the recaptcha is resolved. **Default: noop.** | ||
* nonce: nonce included in the reCAPTCHA script tag. **Default: undefined.** | ||
* onExpired: callback when the recaptcha response expires. **Default: noop.** | ||
* onError: callback when the recaptcha encounters an error. **Default: noop.** | ||
* onExpired: callback when the recaptcha response expires. **Default: noop.** | ||
* onLoaded: callback when the recaptcha is loaded. **Default: noop.** | ||
* onResolved: callback when the recaptcha is resolved. **Default: noop.** | ||
* style: custom CSS applied to the root node. **Default: undefined.** | ||
* tabindex: tabindex of the challenge. **Default: 0.** | ||
@@ -95,9 +74,15 @@ ## APIs ## | ||
```js | ||
<Recaptcha ref={ ref => this.recaptcha = ref } ... /> | ||
// Functional component with React hooks. | ||
const refRecaptcha = React.useRef(null); | ||
<Recaptcha ref={refRecaptcha} ... /> | ||
// Class component. | ||
this.refRecaptcha = React.createRef(); | ||
<Recaptcha ref={refRecaptcha} ... /> | ||
// refRecaptcha.current.callbacks.execute function which invokes the reCAPTCHA check. | ||
// refRecaptcha.current.callbacks.reset function which resets the reCAPTCHA widget. | ||
// refRecaptcha.current.callbacks.getResponse function which returns the response token. | ||
``` | ||
* _this.recaptcha.execute_ function which invokes the reCAPTCHA check. | ||
* _this.recaptcha.reset_ function which resets the reCAPTCHA widget. | ||
* _this.recaptcha.getResponse_ function which returns the response token. | ||
## License ## | ||
@@ -104,0 +89,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
15281
19
7
195
89
1
+ Added@types/uuid@^8.3.0
+ Added@types/uuid@8.3.4(transitive)
+ Addedreact@17.0.2(transitive)
+ Addeduuid@8.3.2(transitive)
- Removedprop-types@^15.6.0
- Removedprop-types@15.8.1(transitive)
- Removedreact@16.14.0(transitive)
- Removedreact-is@16.13.1(transitive)
- Removeduuid@3.4.0(transitive)
Updateduuid@^8.3.2