@gahojin-inc/react-google-recaptcha 2025.8.0 → 2025.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { type Context, type JSX } from "react";
2
2
  import type { GoogleReCaptchaContextType, GoogleReCaptchaProviderProps } from "./types.mjs";
3
- declare const GoogleReCaptchaContext: Context<GoogleReCaptchaContextType | undefined>;
4
- declare const GoogleReCaptchaProvider: ({ siteKey, language, script, children }: GoogleReCaptchaProviderProps) => JSX.Element;
3
+ declare const GoogleReCaptchaContext: Context<GoogleReCaptchaContextType>;
4
+ declare const GoogleReCaptchaProvider: ({ siteKey, language, useRecaptchaNet, useEnterprise, container, badge, theme, children }: GoogleReCaptchaProviderProps) => JSX.Element;
5
5
  export { GoogleReCaptchaProvider, GoogleReCaptchaContext };
6
6
  export type { GoogleReCaptchaContextType, GoogleReCaptchaProviderProps };
package/dist/index.mjs CHANGED
@@ -1,87 +1,149 @@
1
- import { createContext, useCallback, useContext, useEffect, useMemo, useState } from "react";
2
- import { jsx } from "react/jsx-runtime";
1
+ import { createContext, useCallback, useContext, useEffect, useId, useMemo, useRef, useState } from "react";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
3
 
4
+ //#region src/utils.ts
5
+ const getRecaptchaScriptSrc = (render, language, useRecaptchaNet, useEnterprise) => {
6
+ const hostName = useRecaptchaNet ? "recaptcha.net" : "google.com";
7
+ const script = useEnterprise ? "enterprise.js" : "api.js";
8
+ return `https://${hostName}/recaptcha/${script}?render=${render}${language ? `&hl=${language}` : ""}`;
9
+ };
10
+ const injectScriptTag = (scriptId, language, useRecaptchaNet, useEnterprise, onLoad) => {
11
+ const script = document.createElement("script");
12
+ script.type = "text/javascript";
13
+ script.id = scriptId;
14
+ script.src = getRecaptchaScriptSrc("explicit", language, useRecaptchaNet, useEnterprise);
15
+ script.async = true;
16
+ script.defer = true;
17
+ script.onload = onLoad;
18
+ const head = document.getElementsByTagName("head")[0];
19
+ head.appendChild(script);
20
+ return script;
21
+ };
22
+ const removeScriptTag = () => {
23
+ removeRecaptchBadge();
24
+ const script = document.querySelector("script[src^=\"https://www.gstatic.com/recaptcha/releases\"]");
25
+ if (script) script.remove();
26
+ };
27
+ const removeRecaptchBadge = () => {
28
+ const nodeBadge = document.querySelector(".grecaptcha-badge");
29
+ if (nodeBadge?.parentNode) document.body.removeChild(nodeBadge.parentNode);
30
+ };
31
+
32
+ //#endregion
4
33
  //#region src/context.tsx
5
- const GoogleReCaptchaContext = createContext(void 0);
6
- const GoogleReCaptchaProvider = ({ siteKey, language, script, children }) => {
7
- const [state, setState] = useState({ isLoading: true });
34
+ const GoogleReCaptchaContext = createContext({
35
+ isLoading: true,
36
+ error: null,
37
+ execute: () => Promise.reject("useGoogleRecaptcha must be used within an GoogleReCaptchaProvider"),
38
+ reset: () => []
39
+ });
40
+ const GoogleReCaptchaProvider = ({ siteKey, language, useRecaptchaNet, useEnterprise, container, badge, theme, children }) => {
41
+ const id = useId();
42
+ const containerId = useMemo(() => container ? container : `${id}-container`, [id, container]);
43
+ const [state, setState] = useState({
44
+ isLoading: true,
45
+ widgetId: siteKey
46
+ });
47
+ const successHandler = useRef(null);
48
+ const errorHandler = useRef(null);
49
+ const handleSuccess = useCallback((token) => {
50
+ if (successHandler.current) {
51
+ successHandler.current?.(token);
52
+ successHandler.current = null;
53
+ errorHandler.current = null;
54
+ }
55
+ }, []);
56
+ const handleError = useCallback((error) => {
57
+ if (errorHandler.current) {
58
+ errorHandler.current?.(error);
59
+ successHandler.current = null;
60
+ errorHandler.current = null;
61
+ }
62
+ }, []);
8
63
  const onLoad = useCallback(() => {
9
- if (!window || !window.grecaptcha) {
64
+ const grecaptcha = window.grecaptcha?.enterprise ?? window.grecaptcha;
65
+ if (!grecaptcha) {
10
66
  setState({
11
67
  isLoading: false,
12
- error: "ReCaptcha is not available"
68
+ widgetId: siteKey,
69
+ error: /* @__PURE__ */ new Error("ReCaptcha is not available")
13
70
  });
14
71
  return;
15
72
  }
16
- const tmp = window.grecaptcha;
17
- tmp.ready(() => {
73
+ grecaptcha.ready(() => {
74
+ const widgetId = grecaptcha.render(containerId, {
75
+ sitekey: siteKey,
76
+ badge,
77
+ theme,
78
+ size: "invisible",
79
+ callback: (token) => handleSuccess(token),
80
+ "error-callback": (error) => handleError(error)
81
+ });
18
82
  setState({
19
- grecaptcha: tmp,
83
+ widgetId,
84
+ grecaptcha,
20
85
  error: null,
21
86
  isLoading: false
22
87
  });
23
88
  });
24
- }, []);
25
- const execute = useCallback(async (action) => {
89
+ }, [
90
+ siteKey,
91
+ containerId,
92
+ badge,
93
+ theme,
94
+ handleSuccess,
95
+ handleError
96
+ ]);
97
+ const execute = useCallback((action) => {
26
98
  const grecaptcha = state?.grecaptcha;
27
- if (grecaptcha?.execute) return await grecaptcha.execute(siteKey, { action });
28
- throw new Error("aaaReCaptcha is not available");
29
- }, [siteKey, state.grecaptcha]);
99
+ if (grecaptcha?.execute) {
100
+ const promise = new Promise((resolve, reject) => {
101
+ successHandler.current = resolve;
102
+ errorHandler.current = reject;
103
+ });
104
+ return grecaptcha.execute(state.widgetId, action ? { action } : void 0).then((token) => {
105
+ if (token) handleSuccess(token);
106
+ return promise;
107
+ });
108
+ }
109
+ return Promise.reject("ReCaptcha is not available");
110
+ }, [state, handleSuccess]);
111
+ const reset = useCallback(() => {
112
+ state?.grecaptcha?.reset(state.widgetId);
113
+ }, [state]);
30
114
  useEffect(() => {
31
- if (!isScriptInjected(siteKey)) injectScriptTag(siteKey, language, script?.async ?? true, script?.defer ?? true, script?.nonce, script?.trustedtypes ?? false, onLoad);
115
+ const removeScript = injectScriptTag(id, language, useRecaptchaNet, useEnterprise, onLoad);
32
116
  return () => {
33
- removeScriptTag(siteKey);
117
+ removeScript?.remove();
118
+ removeScriptTag();
34
119
  };
35
120
  }, [
36
- onLoad,
37
- siteKey,
121
+ id,
38
122
  language,
39
- script
123
+ useRecaptchaNet,
124
+ useEnterprise,
125
+ onLoad
40
126
  ]);
41
127
  const value = useMemo(() => ({
42
128
  isLoading: state.isLoading,
43
- error: state.error,
44
- execute
45
- }), [state, execute]);
46
- return /* @__PURE__ */ jsx(GoogleReCaptchaContext.Provider, {
129
+ error: state.error ?? null,
130
+ execute,
131
+ reset
132
+ }), [
133
+ state,
134
+ execute,
135
+ reset
136
+ ]);
137
+ return /* @__PURE__ */ jsxs(GoogleReCaptchaContext.Provider, {
47
138
  value,
48
- children
139
+ children: [children, container ? null : /* @__PURE__ */ jsx("div", { id: `${id}-container` })]
49
140
  });
50
141
  };
51
- const isScriptInjected = (siteKey) => {
52
- return !!document.getElementById(siteKey);
53
- };
54
- const injectScriptTag = (siteKey, language, async, defer, nonce, trustedtypes, onLoad) => {
55
- const script = document.createElement("script");
56
- script.id = siteKey;
57
- script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}${language ? "&hl=${language}" : ""}${trustedtypes ? "&trustedtypes=true" : ""}`;
58
- script.async = async;
59
- script.defer = defer;
60
- if (nonce) script.nonce = nonce;
61
- script.type = "text/javascript";
62
- script.onload = onLoad;
63
- const head = document.getElementsByTagName("head")[0];
64
- head.appendChild(script);
65
- };
66
- const removeScriptTag = (siteKey) => {
67
- if (!document) return;
68
- removeRecaptchBadge();
69
- let script = document.getElementById(siteKey);
70
- if (script) script.remove();
71
- script = document.querySelector("script[src^=\"https://www.gstatic.com/recaptcha/releases\"]");
72
- if (script) script.remove();
73
- };
74
- const removeRecaptchBadge = () => {
75
- const nodeBadge = document.querySelector(".grecaptcha-badge");
76
- if (nodeBadge && nodeBadge.parentNode) document.body.removeChild(nodeBadge.parentNode);
77
- };
78
142
 
79
143
  //#endregion
80
144
  //#region src/hooks.ts
81
145
  const useGoogleRecaptcha = () => {
82
- const context = useContext(GoogleReCaptchaContext);
83
- if (context === void 0) throw new Error("useGoogleRecaptcha must be used within an GoogleReCaptchaProvider");
84
- return context;
146
+ return useContext(GoogleReCaptchaContext);
85
147
  };
86
148
 
87
149
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["GoogleReCaptchaContext: Context<GoogleReCaptchaContextType | undefined>","value: GoogleReCaptchaContextType"],"sources":["../src/context.tsx","../src/hooks.ts"],"sourcesContent":["import { type Context, createContext, type JSX, useCallback, useEffect, useMemo, useState } from 'react'\nimport type { GoogleReCaptchaContextType, GoogleReCaptchaProviderProps, Grecaptcha } from './types'\n\nconst GoogleReCaptchaContext: Context<GoogleReCaptchaContextType | undefined> = createContext<GoogleReCaptchaContextType | undefined>(undefined)\n\ntype State = {\n isLoading: boolean\n error?: string | null\n grecaptcha?: Grecaptcha | null\n}\n\nconst GoogleReCaptchaProvider = ({ siteKey, language, script, children }: GoogleReCaptchaProviderProps): JSX.Element => {\n const [state, setState] = useState<State>({ isLoading: true })\n\n // loaded script\n const onLoad = useCallback(() => {\n if (!window || !(window as any).grecaptcha) {\n setState({\n isLoading: false,\n error: 'ReCaptcha is not available',\n })\n return\n }\n const tmp = (window as any).grecaptcha\n tmp.ready(() => {\n setState({\n grecaptcha: tmp,\n error: null,\n isLoading: false,\n })\n })\n }, [])\n\n const execute = useCallback(\n async (action?: string) => {\n const grecaptcha = state?.grecaptcha\n if (grecaptcha?.execute) {\n return await grecaptcha.execute(siteKey, { action })\n }\n throw new Error('aaaReCaptcha is not available')\n },\n [siteKey, state.grecaptcha],\n )\n\n useEffect(() => {\n if (!isScriptInjected(siteKey)) {\n injectScriptTag(siteKey, language, script?.async ?? true, script?.defer ?? true, script?.nonce, script?.trustedtypes ?? false, onLoad)\n }\n\n return () => {\n removeScriptTag(siteKey)\n }\n }, [onLoad, siteKey, language, script])\n\n const value: GoogleReCaptchaContextType = useMemo(\n () => ({\n isLoading: state.isLoading,\n error: state.error,\n execute,\n }),\n [state, execute],\n )\n\n return <GoogleReCaptchaContext.Provider value={value}>{children}</GoogleReCaptchaContext.Provider>\n}\n\nconst isScriptInjected = (siteKey: string) => {\n return !!document.getElementById(siteKey)\n}\n\nconst injectScriptTag = (\n siteKey: string,\n language: string | undefined,\n async: boolean,\n defer: boolean,\n nonce: string | undefined,\n trustedtypes: boolean,\n onLoad: () => void,\n) => {\n const script = document.createElement('script')\n script.id = siteKey\n script.src = `https://www.google.com/recaptcha/api.js?render=${siteKey}${language ? '&hl=${language}' : ''}${trustedtypes ? '&trustedtypes=true' : ''}`\n script.async = async\n script.defer = defer\n if (nonce) {\n script.nonce = nonce\n }\n script.type = 'text/javascript'\n script.onload = onLoad\n\n const head = document.getElementsByTagName('head')[0]\n head.appendChild(script)\n}\n\nconst removeScriptTag = (siteKey: string) => {\n if (!document) {\n return\n }\n\n removeRecaptchBadge()\n\n let script = document.getElementById(siteKey)\n if (script) {\n script.remove()\n }\n\n script = document.querySelector('script[src^=\"https://www.gstatic.com/recaptcha/releases\"]')\n if (script) {\n script.remove()\n }\n}\n\nconst removeRecaptchBadge = () => {\n const nodeBadge = document.querySelector('.grecaptcha-badge')\n if (nodeBadge && nodeBadge.parentNode) {\n document.body.removeChild(nodeBadge.parentNode)\n }\n}\n\nexport { GoogleReCaptchaProvider, GoogleReCaptchaContext }\nexport type { GoogleReCaptchaContextType, GoogleReCaptchaProviderProps }\n","import { useContext } from 'react'\nimport { GoogleReCaptchaContext, type GoogleReCaptchaContextType } from './context'\n\nconst useGoogleRecaptcha = (): GoogleReCaptchaContextType => {\n const context = useContext(GoogleReCaptchaContext)\n if (context === undefined) {\n throw new Error('useGoogleRecaptcha must be used within an GoogleReCaptchaProvider')\n }\n return context\n}\n\nexport { useGoogleRecaptcha }\n"],"mappings":";;;;AAGA,MAAMA,yBAA0E,cAAsD;AAQtI,MAAM,2BAA2B,EAAE,SAAS,UAAU,QAAQ,UAAwC,KAAkB;CACtH,MAAM,CAAC,OAAO,SAAS,GAAG,SAAgB,EAAE,WAAW,MAAM;CAG7D,MAAM,SAAS,kBAAkB;AAC/B,MAAI,CAAC,UAAU,CAAE,OAAe,YAAY;AAC1C,YAAS;IACP,WAAW;IACX,OAAO;IACR;AACD;EACD;EACD,MAAM,MAAO,OAAe;AAC5B,MAAI,YAAY;AACd,YAAS;IACP,YAAY;IACZ,OAAO;IACP,WAAW;IACZ;EACF;CACF,GAAE,EAAE;CAEL,MAAM,UAAU,YACd,OAAO,WAAoB;EACzB,MAAM,aAAa,OAAO;AAC1B,MAAI,YAAY,QACd,QAAO,MAAM,WAAW,QAAQ,SAAS,EAAE,QAAQ;AAErD,QAAM,IAAI,MAAM;CACjB,GACD,CAAC,SAAS,MAAM,WAAW;AAG7B,iBAAgB;AACd,MAAI,CAAC,iBAAiB,SACpB,iBAAgB,SAAS,UAAU,QAAQ,SAAS,MAAM,QAAQ,SAAS,MAAM,QAAQ,OAAO,QAAQ,gBAAgB,OAAO;AAGjI,eAAa;AACX,mBAAgB;EACjB;CACF,GAAE;EAAC;EAAQ;EAAS;EAAU;EAAO;CAEtC,MAAMC,QAAoC,eACjC;EACL,WAAW,MAAM;EACjB,OAAO,MAAM;EACb;EACD,GACD,CAAC,OAAO,QAAQ;AAGlB,QAAO,oBAAC,uBAAuB;EAAgB;EAAQ;;AACxD;AAED,MAAM,oBAAoB,YAAoB;AAC5C,QAAO,CAAC,CAAC,SAAS,eAAe;AAClC;AAED,MAAM,mBACJ,SACA,UACA,OACA,OACA,OACA,cACA,WACG;CACH,MAAM,SAAS,SAAS,cAAc;AACtC,QAAO,KAAK;AACZ,QAAO,MAAM,kDAAkD,UAAU,WAAW,oBAAoB,KAAK,eAAe,uBAAuB;AACnJ,QAAO,QAAQ;AACf,QAAO,QAAQ;AACf,KAAI,MACF,QAAO,QAAQ;AAEjB,QAAO,OAAO;AACd,QAAO,SAAS;CAEhB,MAAM,OAAO,SAAS,qBAAqB,QAAQ;AACnD,MAAK,YAAY;AAClB;AAED,MAAM,mBAAmB,YAAoB;AAC3C,KAAI,CAAC,SACH;AAGF;CAEA,IAAI,SAAS,SAAS,eAAe;AACrC,KAAI,OACF,QAAO;AAGT,UAAS,SAAS,cAAc;AAChC,KAAI,OACF,QAAO;AAEV;AAED,MAAM,4BAA4B;CAChC,MAAM,YAAY,SAAS,cAAc;AACzC,KAAI,aAAa,UAAU,WACzB,UAAS,KAAK,YAAY,UAAU;AAEvC;;;;AClHD,MAAM,2BAAuD;CAC3D,MAAM,UAAU,WAAW;AAC3B,KAAI,YAAY,OACd,OAAM,IAAI,MAAM;AAElB,QAAO;AACR"}
1
+ {"version":3,"file":"index.mjs","names":["GoogleReCaptchaContext: Context<GoogleReCaptchaContextType>","value: GoogleReCaptchaContextType"],"sources":["../src/utils.ts","../src/context.tsx","../src/hooks.ts"],"sourcesContent":["export const getRecaptchaScriptSrc = (\n render: string,\n language: string | null | undefined,\n useRecaptchaNet: boolean | undefined,\n useEnterprise: boolean | undefined,\n): string => {\n const hostName = useRecaptchaNet ? 'recaptcha.net' : 'google.com'\n const script = useEnterprise ? 'enterprise.js' : 'api.js'\n\n return `https://${hostName}/recaptcha/${script}?render=${render}${language ? `&hl=${language}` : ''}`\n}\n\nexport const injectScriptTag = (\n scriptId: string,\n language: string | null | undefined,\n useRecaptchaNet: boolean | undefined,\n useEnterprise: boolean | undefined,\n onLoad: () => void,\n): HTMLScriptElement => {\n const script = document.createElement('script')\n script.type = 'text/javascript'\n script.id = scriptId\n script.src = getRecaptchaScriptSrc('explicit', language, useRecaptchaNet, useEnterprise)\n script.async = true\n script.defer = true\n script.onload = onLoad\n\n const head = document.getElementsByTagName('head')[0]\n head.appendChild(script)\n return script\n}\n\nexport const removeScriptTag = (): void => {\n removeRecaptchBadge()\n\n const script = document.querySelector('script[src^=\"https://www.gstatic.com/recaptcha/releases\"]')\n if (script) {\n script.remove()\n }\n}\n\nexport const removeRecaptchBadge = (): void => {\n const nodeBadge = document.querySelector('.grecaptcha-badge')\n if (nodeBadge?.parentNode) {\n document.body.removeChild(nodeBadge.parentNode)\n }\n}\n","import { type Context, createContext, type JSX, useCallback, useEffect, useId, useMemo, useRef, useState } from 'react'\nimport type { GoogleReCaptchaContextType, GoogleReCaptchaProviderProps, Grecaptcha } from './types'\nimport { injectScriptTag, removeScriptTag } from './utils.ts'\n\nconst GoogleReCaptchaContext: Context<GoogleReCaptchaContextType> = createContext<GoogleReCaptchaContextType>({\n isLoading: true,\n error: null,\n execute: () => Promise.reject('useGoogleRecaptcha must be used within an GoogleReCaptchaProvider'),\n reset: () => [],\n})\n\ntype State = {\n isLoading: boolean\n error?: Error | null\n widgetId: string\n grecaptcha?: Grecaptcha | null\n}\n\nconst GoogleReCaptchaProvider = ({\n siteKey,\n language,\n useRecaptchaNet,\n useEnterprise,\n container,\n badge,\n theme,\n children,\n}: GoogleReCaptchaProviderProps): JSX.Element => {\n const id = useId()\n const containerId = useMemo(() => (container ? container : `${id}-container`), [id, container])\n const [state, setState] = useState<State>({ isLoading: true, widgetId: siteKey })\n const successHandler = useRef<(token: string) => void>(null)\n const errorHandler = useRef<(error: Error | undefined) => void>(null)\n\n const handleSuccess = useCallback((token: string) => {\n if (successHandler.current) {\n successHandler.current?.(token)\n successHandler.current = null\n errorHandler.current = null\n }\n }, [])\n\n const handleError = useCallback((error: Error | undefined) => {\n if (errorHandler.current) {\n errorHandler.current?.(error)\n successHandler.current = null\n errorHandler.current = null\n }\n }, [])\n\n // ReCaptcha初期化\n const onLoad = useCallback(() => {\n const grecaptcha = window.grecaptcha?.enterprise ?? window.grecaptcha\n if (!grecaptcha) {\n setState({\n isLoading: false,\n widgetId: siteKey,\n error: new Error('ReCaptcha is not available'),\n })\n return\n }\n grecaptcha.ready(() => {\n const widgetId = grecaptcha.render(containerId, {\n sitekey: siteKey,\n badge,\n theme,\n size: 'invisible',\n callback: (token) => handleSuccess(token),\n 'error-callback': (error) => handleError(error),\n })\n setState({\n widgetId,\n grecaptcha,\n error: null,\n isLoading: false,\n })\n })\n }, [siteKey, containerId, badge, theme, handleSuccess, handleError])\n\n const execute = useCallback(\n (action?: string) => {\n const grecaptcha = state?.grecaptcha\n if (grecaptcha?.execute) {\n const promise = new Promise<string>((resolve, reject) => {\n successHandler.current = resolve\n errorHandler.current = reject\n })\n return grecaptcha.execute(state.widgetId, action ? { action } : undefined).then((token) => {\n if (token) {\n handleSuccess(token)\n }\n // token = nullの場合、v2動作\n return promise\n })\n }\n return Promise.reject('ReCaptcha is not available')\n },\n [state, handleSuccess],\n )\n\n const reset = useCallback(() => {\n state?.grecaptcha?.reset(state.widgetId)\n }, [state])\n\n // scriptタグを追加/削除する\n useEffect(() => {\n const removeScript = injectScriptTag(id, language, useRecaptchaNet, useEnterprise, onLoad)\n return () => {\n removeScript?.remove()\n removeScriptTag()\n }\n }, [id, language, useRecaptchaNet, useEnterprise, onLoad])\n\n const value: GoogleReCaptchaContextType = useMemo(\n () => ({\n isLoading: state.isLoading,\n error: state.error ?? null,\n execute,\n reset,\n }),\n [state, execute, reset],\n )\n\n return (\n <GoogleReCaptchaContext.Provider value={value}>\n {children}\n {container ? null : <div id={`${id}-container`} />}\n </GoogleReCaptchaContext.Provider>\n )\n}\n\nexport { GoogleReCaptchaProvider, GoogleReCaptchaContext }\nexport type { GoogleReCaptchaContextType, GoogleReCaptchaProviderProps }\n","import { useContext } from 'react'\nimport { GoogleReCaptchaContext, type GoogleReCaptchaContextType } from './context'\n\nconst useGoogleRecaptcha = (): GoogleReCaptchaContextType => {\n return useContext(GoogleReCaptchaContext)\n}\n\nexport { useGoogleRecaptcha }\n"],"mappings":"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"}
package/dist/types.d.mts CHANGED
@@ -1,23 +1,42 @@
1
1
  import type { PropsWithChildren } from "react";
2
- type ScriptProps = {
3
- async?: boolean;
4
- defer?: boolean;
5
- nonce?: string;
6
- trustedtypes?: boolean;
2
+ export type Theme = "light" | "dark";
3
+ export type Type = "image" | "audio";
4
+ export type Size = "normal" | "compact" | "invisible";
5
+ export type Badge = "bottomright" | "bottomleft" | "inline";
6
+ export type Parameters = {
7
+ sitekey: string;
8
+ badge?: Badge;
9
+ size?: Size;
10
+ theme?: Theme;
11
+ callback?: (token: string) => void;
12
+ "error-callback"?: (error?: Error) => void;
7
13
  };
8
- type GoogleReCaptchaProviderProps = PropsWithChildren<{
9
- siteKey: string;
10
- language?: string;
11
- script?: ScriptProps;
14
+ export type GoogleReCaptchaProviderProps = PropsWithChildren<{
15
+ readonly siteKey: string;
16
+ readonly language?: string | null;
17
+ readonly useRecaptchaNet?: boolean;
18
+ readonly useEnterprise?: boolean;
19
+ readonly container?: string | HTMLElement | null;
20
+ readonly badge?: Badge;
21
+ readonly theme?: Theme;
12
22
  }>;
13
- type Grecaptcha = {
14
- execute: (siteKey: string, params: {
15
- action?: string;
16
- }) => Promise<string>;
23
+ export type Action = {
24
+ action: string;
17
25
  };
18
- type GoogleReCaptchaContextType = {
19
- isLoading: boolean;
20
- error: string | null | undefined;
26
+ export type Grecaptcha = {
27
+ ready: (onReady: () => void) => void;
28
+ render: (container: string | HTMLElement, params: Parameters) => string;
29
+ execute: (widgetId: string, params?: Action) => Promise<string | null>;
30
+ reset: (widgetId: string) => void;
31
+ };
32
+ export type GoogleReCaptchaContextType = {
33
+ readonly isLoading: boolean;
34
+ readonly error: Error | null;
21
35
  execute: (action?: string) => Promise<string>;
36
+ reset: () => void;
22
37
  };
23
- export type { GoogleReCaptchaProviderProps, Grecaptcha, GoogleReCaptchaContextType };
38
+ declare global {
39
+ var grecaptcha: Grecaptcha & {
40
+ enterprise: Grecaptcha;
41
+ };
42
+ }
@@ -0,0 +1,4 @@
1
+ export declare const getRecaptchaScriptSrc: (render: string, language: string | null | undefined, useRecaptchaNet: boolean | undefined, useEnterprise: boolean | undefined) => string;
2
+ export declare const injectScriptTag: (scriptId: string, language: string | null | undefined, useRecaptchaNet: boolean | undefined, useEnterprise: boolean | undefined, onLoad: () => void) => HTMLScriptElement;
3
+ export declare const removeScriptTag: () => void;
4
+ export declare const removeRecaptchBadge: () => void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gahojin-inc/react-google-recaptcha",
3
- "version": "2025.8.0",
3
+ "version": "2025.9.0",
4
4
  "description": "Hooks for Google ReCaptcha V3",
5
5
  "author": "GAHOJIN, Inc.",
6
6
  "license": "Apache-2.0",
@@ -17,6 +17,8 @@
17
17
  ],
18
18
  "keywords": [
19
19
  "google-recaptcha",
20
+ "google-recaptcha-v2",
21
+ "google-recaptcha-v3",
20
22
  "react"
21
23
  ],
22
24
  "publishConfig": {