@wojtekmaj/react-recaptcha-v3
Version:
Integrate Google reCAPTCHA v3 with your React app
131 lines (130 loc) • 7.56 kB
JavaScript
import { jsx as _jsx } from "react/jsx-runtime";
import { useEffect, useId, useMemo, useRef, useState } from 'react';
import warning from 'warning';
import ReCaptchaContext from './ReCaptchaContext.js';
import { registerInstance, removeClient, unregisterInstance } from './manager.js';
let didWarnAboutHiddenBadge = false;
export default function ReCaptchaProvider({ container, children, language, reCaptchaKey, scriptProps, useEnterprise, useRecaptchaNet, }) {
var _a, _b, _c, _d, _e, _f, _g;
const id = useId();
const [reCaptchaInstance, setReCaptchaInstance] = useState(null);
const [clientId, setClientId] = useState(null);
const clientIdMounted = useRef(false);
useEffect(() => {
function onLoadCallback() {
var _a;
const nextReCaptchaInstance = useEnterprise
? (_a = window.grecaptcha) === null || _a === void 0 ? void 0 : _a.enterprise
: window.grecaptcha;
if (!nextReCaptchaInstance) {
throw new Error('reCAPTCHA not found');
}
if (!nextReCaptchaInstance.ready) {
throw new Error('reCAPTCHA ready callback not found');
}
nextReCaptchaInstance.ready(() => {
setReCaptchaInstance(nextReCaptchaInstance);
});
}
registerInstance(id, {
language,
onLoadCallback,
onLoadCallbackName: scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.onLoadCallbackName,
render: (container === null || container === void 0 ? void 0 : container.element) ? 'explicit' : reCaptchaKey,
scriptProps: {
appendTo: scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.appendTo,
async: scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.async,
defer: scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.defer,
id: scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.id,
nonce: scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.nonce,
},
useEnterprise,
useRecaptchaNet,
});
return () => {
unregisterInstance(id);
setReCaptchaInstance(null);
};
}, [
container === null || container === void 0 ? void 0 : container.element,
id,
language,
reCaptchaKey,
scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.appendTo,
scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.async,
scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.defer,
scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.id,
scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.nonce,
scriptProps === null || scriptProps === void 0 ? void 0 : scriptProps.onLoadCallbackName,
useEnterprise,
useRecaptchaNet,
]);
useEffect(() => {
var _a, _b, _c;
if (!(container === null || container === void 0 ? void 0 : container.element) || !(reCaptchaInstance === null || reCaptchaInstance === void 0 ? void 0 : reCaptchaInstance.render)) {
return;
}
const params = {
'error-callback': container.parameters.errorCallback,
'expired-callback': container.parameters.expiredCallback,
badge: ((_a = container.parameters) === null || _a === void 0 ? void 0 : _a.badge) || 'inline',
callback: container.parameters.callback,
sitekey: reCaptchaKey,
size: 'invisible',
tabindex: container.parameters.tabindex,
theme: container.parameters.theme,
};
const actualContainerElement = typeof (container === null || container === void 0 ? void 0 : container.element) === 'string'
? document.getElementById(container.element)
: container === null || container === void 0 ? void 0 : container.element;
if (!actualContainerElement) {
throw new Error('reCAPTCHA container element not found');
}
const nextClientId = reCaptchaInstance.render(actualContainerElement, params);
if ((_b = container === null || container === void 0 ? void 0 : container.parameters) === null || _b === void 0 ? void 0 : _b.hidden) {
if (!didWarnAboutHiddenBadge) {
warning(false, 'reCAPTCHA badge hidden. See https://cloud.google.com/recaptcha/docs/faq#id_like_to_hide_the_badge_what_is_allowed for more information.');
didWarnAboutHiddenBadge = true;
}
(_c = actualContainerElement.querySelector('.grecaptcha-badge')) === null || _c === void 0 ? void 0 : _c.style.setProperty('display', 'none');
}
setClientId(nextClientId);
clientIdMounted.current = true;
return () => {
setClientId(null);
clientIdMounted.current = false;
removeClient(nextClientId);
actualContainerElement.innerHTML = '';
};
}, [
container === null || container === void 0 ? void 0 : container.element,
(_a = container === null || container === void 0 ? void 0 : container.parameters) === null || _a === void 0 ? void 0 : _a.badge,
(_b = container === null || container === void 0 ? void 0 : container.parameters) === null || _b === void 0 ? void 0 : _b.hidden,
(_c = container === null || container === void 0 ? void 0 : container.parameters) === null || _c === void 0 ? void 0 : _c.callback,
(_d = container === null || container === void 0 ? void 0 : container.parameters) === null || _d === void 0 ? void 0 : _d.errorCallback,
(_e = container === null || container === void 0 ? void 0 : container.parameters) === null || _e === void 0 ? void 0 : _e.expiredCallback,
(_f = container === null || container === void 0 ? void 0 : container.parameters) === null || _f === void 0 ? void 0 : _f.tabindex,
(_g = container === null || container === void 0 ? void 0 : container.parameters) === null || _g === void 0 ? void 0 : _g.theme,
reCaptchaInstance,
reCaptchaKey,
]);
const shouldUseClientId = Boolean(container === null || container === void 0 ? void 0 : container.element);
const clientIdOrReCaptchaKey = shouldUseClientId ? clientId : reCaptchaKey;
const executeRecaptcha = useMemo(() => clientIdOrReCaptchaKey !== null && (reCaptchaInstance === null || reCaptchaInstance === void 0 ? void 0 : reCaptchaInstance.execute)
? (action) => {
if (clientIdOrReCaptchaKey === null || !(reCaptchaInstance === null || reCaptchaInstance === void 0 ? void 0 : reCaptchaInstance.execute)) {
throw new Error('reCAPTCHA has not been loaded');
}
if (shouldUseClientId && !clientIdMounted.current) {
console.warn('Client ID not mounted');
return null;
}
return reCaptchaInstance.execute(clientIdOrReCaptchaKey, { action });
}
: undefined, [clientIdOrReCaptchaKey, reCaptchaInstance, shouldUseClientId]);
return (_jsx(ReCaptchaContext.Provider, { value: {
container: container === null || container === void 0 ? void 0 : container.element,
executeRecaptcha,
reCaptchaInstance,
}, children: children }));
}