@prosopo/procaptcha-react 2.9.95 → 2.9.97

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,8 +1,9 @@
1
+ import React from "react";
1
2
  import { jsx } from "@emotion/react/jsx-runtime";
2
3
  import { css } from "@emotion/react";
3
- import React from "react";
4
4
  import { createPortal } from "react-dom";
5
- const ModalInnerDivCSS = css`
5
+ //#region src/components/Modal.tsx
6
+ var ModalInnerDivCSS = css`
6
7
  position: absolute;
7
8
  top: 50%;
8
9
  left: 50%;
@@ -22,23 +23,25 @@ const ModalInnerDivCSS = css`
22
23
  transform: translate(-50%, -100%);
23
24
  }
24
25
  `;
25
- const ModalComponent = React.memo((props) => {
26
- const { show, children } = props;
27
- const display = show ? "flex" : "none";
28
- const ModalOuterDivCss = {
29
- position: "fixed",
30
- zIndex: 2147483646,
31
- inset: 0,
32
- display,
33
- alignItems: "center",
34
- justifyContent: "center",
35
- minHeight: "100vh"
36
- };
37
- return createPortal(
38
- /* @__PURE__ */ jsx("div", { className: "prosopo-modalOuter", style: ModalOuterDivCss, children: /* @__PURE__ */ jsx("div", { className: "prosopo-modalInner", css: ModalInnerDivCSS, children }) }),
39
- document.body
40
- );
26
+ var ModalComponent = React.memo((props) => {
27
+ const { show, children } = props;
28
+ return createPortal(/* @__PURE__ */ jsx("div", {
29
+ className: "prosopo-modalOuter",
30
+ style: {
31
+ position: "fixed",
32
+ zIndex: 2147483646,
33
+ inset: 0,
34
+ display: show ? "flex" : "none",
35
+ alignItems: "center",
36
+ justifyContent: "center",
37
+ minHeight: "100vh"
38
+ },
39
+ children: /* @__PURE__ */ jsx("div", {
40
+ className: "prosopo-modalInner",
41
+ css: ModalInnerDivCSS,
42
+ children
43
+ })
44
+ }), document.body);
41
45
  });
42
- export {
43
- ModalComponent as default
44
- };
46
+ //#endregion
47
+ export { ModalComponent as default };
@@ -1,7 +1,7 @@
1
+ import { Suspense, lazy } from "react";
1
2
  import { jsx } from "@emotion/react/jsx-runtime";
2
- import { lazy, Suspense } from "react";
3
- const ProcaptchaWidget = lazy(async () => import("./ProcaptchaWidget.js"));
4
- const Procaptcha = (props) => /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(ProcaptchaWidget, { ...props }) });
5
- export {
6
- Procaptcha as default
7
- };
3
+ //#region src/components/Procaptcha.tsx
4
+ var ProcaptchaWidget = lazy(async () => import("./ProcaptchaWidget.js"));
5
+ var Procaptcha = (props) => /* @__PURE__ */ jsx(Suspense, { children: /* @__PURE__ */ jsx(ProcaptchaWidget, { ...props }) });
6
+ //#endregion
7
+ export { Procaptcha as default };
@@ -1,165 +1,147 @@
1
- import { jsx, jsxs, Fragment } from "@emotion/react/jsx-runtime";
2
- import { useTranslation, loadI18next } from "@prosopo/locale";
3
- import { Manager } from "@prosopo/procaptcha";
4
- import { useProcaptcha, Honeypot, TestModeBanner, Checkbox } from "@prosopo/procaptcha-common";
5
- import { ProcaptchaConfigSchema } from "@prosopo/types";
6
- import { lightTheme, darkTheme } from "@prosopo/widget-skeleton";
7
- import { useState, useRef, useEffect } from "react";
1
+ import "../_virtual/_rolldown/runtime.js";
8
2
  import CaptchaComponent from "./CaptchaComponent.js";
9
3
  import ModalComponent from "./Modal.js";
10
- const PROCAPTCHA_EXECUTE_EVENT = "procaptcha:execute";
11
- const ProcaptchaWidget = (props) => {
12
- const { t, ready: isTranslationReady } = useTranslation();
13
- const config = ProcaptchaConfigSchema.parse(props.config);
14
- const frictionlessState = props.frictionlessState;
15
- const i18n = props.i18n;
16
- const callbacks = props.callbacks || {};
17
- const [state, updateState] = useProcaptcha(useState, useRef);
18
- const [loading, setLoading] = useState(false);
19
- const hpRef = useRef(null);
20
- const manager = useRef(
21
- Manager(
22
- config,
23
- state,
24
- updateState,
25
- callbacks,
26
- frictionlessState,
27
- () => hpRef.current?.value || void 0
28
- )
29
- );
30
- const lastCoordsRef = useRef(null);
31
- const sessionInvalidatedFiredRef = useRef(false);
32
- const theme = "light" === props.config.theme ? lightTheme : darkTheme;
33
- useEffect(() => {
34
- if (!config.language) return;
35
- if (i18n) {
36
- if (i18n.language !== config.language) {
37
- void i18n.changeLanguage(config.language);
38
- }
39
- return;
40
- }
41
- void loadI18next(false, config.language);
42
- }, [i18n, config.language]);
43
- useEffect(() => {
44
- if (!props.autoStart) return;
45
- setLoading(true);
46
- const coords = props.startCoords;
47
- lastCoordsRef.current = coords ?? null;
48
- manager.current.start(coords?.x ?? 0, coords?.y ?? 0).then(
49
- () => setLoading(false),
50
- () => setLoading(false)
51
- );
52
- }, [props.autoStart, props.startCoords]);
53
- useEffect(() => {
54
- if (!state.error) return;
55
- setLoading(false);
56
- if (state.error.key !== "CAPTCHA.NO_SESSION_FOUND") return;
57
- if (props.onSessionInvalidated && !sessionInvalidatedFiredRef.current) {
58
- sessionInvalidatedFiredRef.current = true;
59
- const coords = lastCoordsRef.current;
60
- props.onSessionInvalidated(coords?.x, coords?.y);
61
- return;
62
- }
63
- if (frictionlessState) {
64
- setTimeout(() => {
65
- frictionlessState.restart();
66
- }, 100);
67
- }
68
- }, [state.error, frictionlessState, props.onSessionInvalidated]);
69
- useEffect(() => {
70
- const handleExecuteEvent = (event) => {
71
- updateState({
72
- showModal: true
73
- });
74
- if (!state.challenge && manager.current.start) {
75
- console.log("No challenge set, attempting to start verification");
76
- try {
77
- manager.current.start();
78
- } catch (error) {
79
- console.error("Error starting verification:", error);
80
- }
81
- }
82
- };
83
- document.addEventListener(PROCAPTCHA_EXECUTE_EVENT, handleExecuteEvent);
84
- return () => {
85
- document.removeEventListener(
86
- PROCAPTCHA_EXECUTE_EVENT,
87
- handleExecuteEvent
88
- );
89
- };
90
- }, [state.challenge, updateState]);
91
- const honeypot = frictionlessState?.hp ? /* @__PURE__ */ jsx(Honeypot, { ref: hpRef, encodedQuestion: frictionlessState.hp }) : null;
92
- if (config.mode === "invisible") {
93
- return /* @__PURE__ */ jsxs(Fragment, { children: [
94
- honeypot,
95
- /* @__PURE__ */ jsx(ModalComponent, { show: state.showModal, children: state.challenge ? /* @__PURE__ */ jsx(
96
- CaptchaComponent,
97
- {
98
- challenge: state.challenge,
99
- index: state.index,
100
- solutions: state.solutions,
101
- onSubmit: manager.current.submit,
102
- onCancel: manager.current.cancel,
103
- onClick: manager.current.select,
104
- onNext: manager.current.nextRound,
105
- onReload: manager.current.reload,
106
- themeColor: config.theme ?? "light"
107
- }
108
- ) : null })
109
- ] });
110
- }
111
- return /* @__PURE__ */ jsxs("div", { className: "image-captcha", children: [
112
- honeypot,
113
- /* @__PURE__ */ jsx(ModalComponent, { show: state.showModal, children: state.challenge ? /* @__PURE__ */ jsx(
114
- CaptchaComponent,
115
- {
116
- challenge: state.challenge,
117
- index: state.index,
118
- solutions: state.solutions,
119
- onSubmit: manager.current.submit,
120
- onCancel: manager.current.cancel,
121
- onClick: manager.current.select,
122
- onNext: manager.current.nextRound,
123
- onReload: manager.current.reload,
124
- themeColor: config.theme ?? "light"
125
- }
126
- ) : /* @__PURE__ */ jsx("div", { children: "No challenge set." }) }),
127
- /* @__PURE__ */ jsx(TestModeBanner, { siteKey: config.account.address ?? "" }),
128
- /* @__PURE__ */ jsx(
129
- Checkbox,
130
- {
131
- theme,
132
- onChange: async (event) => {
133
- if (!event.isTrusted) {
134
- return;
135
- }
136
- if (loading) {
137
- return;
138
- }
139
- setLoading(true);
140
- let x = 0;
141
- let y = 0;
142
- const nativeEvent = event.nativeEvent;
143
- if ("touches" in nativeEvent && nativeEvent.touches.length > 0 && nativeEvent.touches[0]) {
144
- x = nativeEvent.touches[0].clientX;
145
- y = nativeEvent.touches[0].clientY;
146
- } else if ("clientX" in nativeEvent && "clientY" in nativeEvent) {
147
- x = nativeEvent.clientX;
148
- y = nativeEvent.clientY;
149
- }
150
- lastCoordsRef.current = { x, y };
151
- await manager.current.start(x, y);
152
- setLoading(false);
153
- },
154
- checked: state.isHuman,
155
- labelText: isTranslationReady ? t("WIDGET.I_AM_HUMAN") : "",
156
- error: state.error?.message,
157
- "aria-label": "human checkbox",
158
- loading
159
- }
160
- )
161
- ] });
162
- };
163
- export {
164
- ProcaptchaWidget as default
4
+ import { darkTheme, lightTheme } from "@prosopo/widget-skeleton";
5
+ import { useEffect, useRef, useState } from "react";
6
+ import { Fragment, jsx, jsxs } from "@emotion/react/jsx-runtime";
7
+ import { loadI18next, useTranslation } from "@prosopo/locale";
8
+ import { Checkbox, Honeypot, TestModeBanner, useProcaptcha } from "@prosopo/procaptcha-common";
9
+ import { Manager } from "@prosopo/procaptcha";
10
+ import { ProcaptchaConfigSchema } from "@prosopo/types";
11
+ //#region src/components/ProcaptchaWidget.tsx
12
+ /** @jsxImportSource @emotion/react */
13
+ var PROCAPTCHA_EXECUTE_EVENT = "procaptcha:execute";
14
+ var ProcaptchaWidget = (props) => {
15
+ const { t, ready: isTranslationReady } = useTranslation();
16
+ const config = ProcaptchaConfigSchema.parse(props.config);
17
+ const frictionlessState = props.frictionlessState;
18
+ const i18n = props.i18n;
19
+ const callbacks = props.callbacks || {};
20
+ const [state, updateState] = useProcaptcha(useState, useRef);
21
+ const [loading, setLoading] = useState(false);
22
+ const hpRef = useRef(null);
23
+ const manager = useRef(Manager(config, state, updateState, callbacks, frictionlessState, () => hpRef.current?.value || void 0));
24
+ const lastCoordsRef = useRef(null);
25
+ const sessionInvalidatedFiredRef = useRef(false);
26
+ const theme = "light" === props.config.theme ? lightTheme : darkTheme;
27
+ useEffect(() => {
28
+ if (!config.language) return;
29
+ if (i18n) {
30
+ if (i18n.language !== config.language) i18n.changeLanguage(config.language);
31
+ return;
32
+ }
33
+ loadI18next(false, config.language);
34
+ }, [i18n, config.language]);
35
+ useEffect(() => {
36
+ if (!props.autoStart) return;
37
+ setLoading(true);
38
+ const coords = props.startCoords;
39
+ lastCoordsRef.current = coords ?? null;
40
+ manager.current.start(coords?.x ?? 0, coords?.y ?? 0).then(() => setLoading(false), () => setLoading(false));
41
+ }, [props.autoStart, props.startCoords]);
42
+ useEffect(() => {
43
+ if (!state.error) return;
44
+ setLoading(false);
45
+ if (state.error.key !== "CAPTCHA.NO_SESSION_FOUND") return;
46
+ if (props.onSessionInvalidated && !sessionInvalidatedFiredRef.current) {
47
+ sessionInvalidatedFiredRef.current = true;
48
+ const coords = lastCoordsRef.current;
49
+ props.onSessionInvalidated(coords?.x, coords?.y);
50
+ return;
51
+ }
52
+ if (frictionlessState) setTimeout(() => {
53
+ frictionlessState.restart();
54
+ }, 100);
55
+ }, [
56
+ state.error,
57
+ frictionlessState,
58
+ props.onSessionInvalidated
59
+ ]);
60
+ useEffect(() => {
61
+ const handleExecuteEvent = (event) => {
62
+ updateState({ showModal: true });
63
+ if (!state.challenge && manager.current.start) {
64
+ console.log("No challenge set, attempting to start verification");
65
+ try {
66
+ manager.current.start();
67
+ } catch (error) {
68
+ console.error("Error starting verification:", error);
69
+ }
70
+ }
71
+ };
72
+ document.addEventListener(PROCAPTCHA_EXECUTE_EVENT, handleExecuteEvent);
73
+ return () => {
74
+ document.removeEventListener(PROCAPTCHA_EXECUTE_EVENT, handleExecuteEvent);
75
+ };
76
+ }, [state.challenge, updateState]);
77
+ const honeypot = frictionlessState?.hp ? /* @__PURE__ */ jsx(Honeypot, {
78
+ ref: hpRef,
79
+ encodedQuestion: frictionlessState.hp
80
+ }) : null;
81
+ if (config.mode === "invisible") return /* @__PURE__ */ jsxs(Fragment, { children: [honeypot, /* @__PURE__ */ jsx(ModalComponent, {
82
+ show: state.showModal,
83
+ children: state.challenge ? /* @__PURE__ */ jsx(CaptchaComponent, {
84
+ challenge: state.challenge,
85
+ index: state.index,
86
+ solutions: state.solutions,
87
+ onSubmit: manager.current.submit,
88
+ onCancel: manager.current.cancel,
89
+ onClick: manager.current.select,
90
+ onNext: manager.current.nextRound,
91
+ onReload: manager.current.reload,
92
+ themeColor: config.theme ?? "light"
93
+ }) : null
94
+ })] });
95
+ return /* @__PURE__ */ jsxs("div", {
96
+ className: "image-captcha",
97
+ children: [
98
+ honeypot,
99
+ /* @__PURE__ */ jsx(ModalComponent, {
100
+ show: state.showModal,
101
+ children: state.challenge ? /* @__PURE__ */ jsx(CaptchaComponent, {
102
+ challenge: state.challenge,
103
+ index: state.index,
104
+ solutions: state.solutions,
105
+ onSubmit: manager.current.submit,
106
+ onCancel: manager.current.cancel,
107
+ onClick: manager.current.select,
108
+ onNext: manager.current.nextRound,
109
+ onReload: manager.current.reload,
110
+ themeColor: config.theme ?? "light"
111
+ }) : /* @__PURE__ */ jsx("div", { children: "No challenge set." })
112
+ }),
113
+ /* @__PURE__ */ jsx(TestModeBanner, { siteKey: config.account.address ?? "" }),
114
+ /* @__PURE__ */ jsx(Checkbox, {
115
+ theme,
116
+ onChange: async (event) => {
117
+ if (!event.isTrusted) return;
118
+ if (loading) return;
119
+ setLoading(true);
120
+ let x = 0;
121
+ let y = 0;
122
+ const nativeEvent = event.nativeEvent;
123
+ if ("touches" in nativeEvent && nativeEvent.touches.length > 0 && nativeEvent.touches[0]) {
124
+ x = nativeEvent.touches[0].clientX;
125
+ y = nativeEvent.touches[0].clientY;
126
+ } else if ("clientX" in nativeEvent && "clientY" in nativeEvent) {
127
+ x = nativeEvent.clientX;
128
+ y = nativeEvent.clientY;
129
+ }
130
+ lastCoordsRef.current = {
131
+ x,
132
+ y
133
+ };
134
+ await manager.current.start(x, y);
135
+ setLoading(false);
136
+ },
137
+ checked: state.isHuman,
138
+ labelText: isTranslationReady ? t("WIDGET.I_AM_HUMAN") : "",
139
+ error: state.error?.message,
140
+ "aria-label": "human checkbox",
141
+ loading
142
+ })
143
+ ]
144
+ });
165
145
  };
146
+ //#endregion
147
+ export { ProcaptchaWidget as default };
@@ -1,9 +1,4 @@
1
1
  import { CaptchaWidget } from "./CaptchaWidget.js";
2
- import "./CaptchaComponent.js";
3
- import { default as default2 } from "./ProcaptchaWidget.js";
4
- import { default as default3 } from "./Procaptcha.js";
5
- export {
6
- CaptchaWidget,
7
- default3 as Procaptcha,
8
- default2 as ProcaptchaWidget
9
- };
2
+ import ProcaptchaWidget from "./ProcaptchaWidget.js";
3
+ import Procaptcha from "./Procaptcha.js";
4
+ export { CaptchaWidget, Procaptcha, ProcaptchaWidget };
package/dist/index.js CHANGED
@@ -1,10 +1,5 @@
1
- import "./components/index.js";
2
- import "./util/index.js";
3
- import { default as default2 } from "./components/ProcaptchaWidget.js";
4
- import { default as default3 } from "./components/Procaptcha.js";
1
+ import "./_virtual/_rolldown/runtime.js";
5
2
  import { CaptchaWidget } from "./components/CaptchaWidget.js";
6
- export {
7
- CaptchaWidget,
8
- default3 as Procaptcha,
9
- default2 as ProcaptchaWidget
10
- };
3
+ import ProcaptchaWidget from "./components/ProcaptchaWidget.js";
4
+ import Procaptcha from "./components/Procaptcha.js";
5
+ export { CaptchaWidget, Procaptcha, ProcaptchaWidget };
@@ -1,19 +1,20 @@
1
+ //#region src/util/index.ts
1
2
  function renameKeysForDataAttr(data = {}) {
2
- return Object.keys(data).reduce(
3
- // biome-ignore lint/performance/noAccumulatingSpread: TODO fix
4
- (prev, curr) => ({ ...prev, [`data-${curr}`]: data[curr] }),
5
- {}
6
- );
3
+ return Object.keys(data).reduce((prev, curr) => ({
4
+ ...prev,
5
+ [`data-${curr}`]: data[curr]
6
+ }), {});
7
7
  }
8
- function addDataAttr({
9
- general,
10
- dev
11
- }) {
12
- return {
13
- ...renameKeysForDataAttr(general),
14
- ...process.env.NODE_ENV !== "production" ? renameKeysForDataAttr(dev) : {}
15
- };
8
+ /**
9
+ * maps any data to data attributes (mapped to { data-[key]: value })
10
+ *
11
+ * dev - only in development mode
12
+ */
13
+ function addDataAttr({ general, dev }) {
14
+ return {
15
+ ...renameKeysForDataAttr(general),
16
+ ...process.env.NODE_ENV !== "production" ? renameKeysForDataAttr(dev) : {}
17
+ };
16
18
  }
17
- export {
18
- addDataAttr as default
19
- };
19
+ //#endregion
20
+ export { addDataAttr as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/procaptcha-react",
3
- "version": "2.9.95",
3
+ "version": "2.9.97",
4
4
  "author": "PROSOPO LIMITED <info@prosopo.io>",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -29,31 +29,31 @@
29
29
  },
30
30
  "browserslist": ["> 0.5%, last 2 versions, not dead"],
31
31
  "dependencies": {
32
- "@prosopo/common": "3.1.47",
33
- "@prosopo/locale": "3.2.7",
34
- "@prosopo/procaptcha": "2.10.56",
35
- "@prosopo/procaptcha-common": "2.11.16",
36
- "@prosopo/types": "4.9.11",
37
- "@prosopo/util": "3.3.4",
32
+ "@prosopo/common": "3.1.48",
33
+ "@prosopo/locale": "3.2.8",
34
+ "@prosopo/procaptcha": "2.10.58",
35
+ "@prosopo/procaptcha-common": "2.11.18",
36
+ "@prosopo/types": "4.10.0",
37
+ "@prosopo/util": "3.3.5",
38
38
  "@prosopo/widget-skeleton": "2.8.4",
39
39
  "csstype": "3.1.3",
40
40
  "react": "18.3.1",
41
41
  "react-dom": "18.3.1"
42
42
  },
43
43
  "devDependencies": {
44
- "@prosopo/config": "3.3.4",
44
+ "@prosopo/config": "3.3.5",
45
45
  "@emotion/react": "11.11.1",
46
46
  "@types/node": "22.10.2",
47
47
  "@types/react-dom": "18.3.1",
48
- "@vitest/coverage-v8": "3.2.4",
48
+ "@vitest/coverage-v8": "4.1.10",
49
49
  "concurrently": "9.0.1",
50
50
  "del-cli": "6.0.0",
51
51
  "npm-run-all": "4.1.5",
52
52
  "tslib": "2.7.0",
53
53
  "tsx": "4.20.3",
54
54
  "typescript": "5.6.2",
55
- "vite": "6.4.1",
56
- "vitest": "3.2.4"
55
+ "vite": "8.1.5",
56
+ "vitest": "4.1.10"
57
57
  },
58
58
  "repository": {
59
59
  "type": "git",