@captchafox/react 1.0.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.
package/README.md ADDED
@@ -0,0 +1,93 @@
1
+ # @captchafox/react
2
+
3
+ [![NPM version](https://img.shields.io/npm/v/@captchafox/react.svg)](https://www.npmjs.com/package/@captchafox/react)
4
+
5
+ ## Installation
6
+
7
+ Install the library using your prefered package manager
8
+
9
+ ```sh
10
+ npm install @captchafox/react
11
+ ```
12
+
13
+ ```sh
14
+ yarn add @captchafox/react
15
+ ```
16
+
17
+ ```sh
18
+ pnpm add @captchafox/react
19
+ ```
20
+
21
+ ## Usage
22
+
23
+ ```tsx
24
+ import { CaptchaFox } from '@captchafox/react'
25
+
26
+ function Example() {
27
+ return <CaptchaFox sitekey="sk_11111111000000001111111100000000" />
28
+ }
29
+ ```
30
+
31
+ ### Props
32
+
33
+ | **Prop** | **Type** | **Description** | **Required** |
34
+ | -------- | ----------------------- | ------------------------------------------------------------------------------- | ------------ |
35
+ | sitekey | `string` | The sitekey for the widget | ✅ |
36
+ | lng | `string` | The language the widget should display. Defaults to automatically detecting it. | |
37
+ | mode | `inline\|popup\|hidden` | The mode the widget should be displayed in | |
38
+ | onVerify | `function` | Called with the response token after successful verification | |
39
+ | onFail | `function` | Called after unsuccessful verification | |
40
+ | onError | `function` | Called if an error occured | |
41
+ | onExpire | `function` | Called if the challenge expired | |
42
+ | onClose | `function` | Called if the challenge was closed | |
43
+
44
+ ### Using the verification callback
45
+
46
+ ```jsx
47
+ import { CaptchaFox, CAPTCHA_RESPONSE_KEY } from '@captchafox/react'
48
+
49
+ function Example() {
50
+ const handleVerify = (token: string) => {
51
+ // do something with the token here (e.g. submit the form)
52
+ const formData = {
53
+ // your form data
54
+ [CAPTCHA_RESPONSE_KEY]: token
55
+ };
56
+ }
57
+
58
+ return (
59
+ <CaptchaFox
60
+ sitekey="sk_11111111000000001111111100000000"
61
+ onVerify={handleVerify}
62
+ />
63
+ )
64
+ }
65
+ ```
66
+
67
+ ### Interacting with the instance
68
+
69
+ ```jsx
70
+ import { useRef } from 'react'
71
+ import { CaptchaFox, CaptchaFoxInstance } from '@captchafox/react'
72
+
73
+ function Example() {
74
+ const captchaRef = useRef<CaptchaFoxInstance | null>(null);
75
+
76
+ const triggerAction = async () => {
77
+ // execute the captcha
78
+ try {
79
+ const token = await captchaRef.current?.execute()
80
+ } catch {
81
+ // unsuccessful verification
82
+ }
83
+ }
84
+
85
+ return (
86
+ <CaptchaFox
87
+ sitekey="sk_11111111000000001111111100000000"
88
+ ref={captchaRef}
89
+ />
90
+ <button onClick={triggerAction}>Action</button>
91
+ )
92
+ }
93
+ ```
@@ -0,0 +1,13 @@
1
+ import * as react from 'react';
2
+ import { WidgetApi, WidgetOptions } from '@captchafox/types';
3
+
4
+ type CaptchaFoxInstance = Omit<WidgetApi, 'render'>;
5
+ declare const CaptchaFox: react.ForwardRefExoticComponent<WidgetOptions & {
6
+ /** Called after the widget has been loaded */
7
+ onLoad?: (() => void) | undefined;
8
+ className?: string | undefined;
9
+ } & react.RefAttributes<CaptchaFoxInstance>>;
10
+
11
+ declare const CAPTCHA_RESPONSE_KEY = "cf-captcha-response";
12
+
13
+ export { CAPTCHA_RESPONSE_KEY, CaptchaFox, CaptchaFoxInstance };
package/dist/index.js ADDED
@@ -0,0 +1,163 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var __async = (__this, __arguments, generator) => {
20
+ return new Promise((resolve, reject) => {
21
+ var fulfilled = (value) => {
22
+ try {
23
+ step(generator.next(value));
24
+ } catch (e) {
25
+ reject(e);
26
+ }
27
+ };
28
+ var rejected = (value) => {
29
+ try {
30
+ step(generator.throw(value));
31
+ } catch (e) {
32
+ reject(e);
33
+ }
34
+ };
35
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
36
+ step((generator = generator.apply(__this, __arguments)).next());
37
+ });
38
+ };
39
+
40
+ // src/index.tsx
41
+ var src_exports = {};
42
+ __export(src_exports, {
43
+ CAPTCHA_RESPONSE_KEY: () => CAPTCHA_RESPONSE_KEY,
44
+ CaptchaFox: () => CaptchaFox
45
+ });
46
+ module.exports = __toCommonJS(src_exports);
47
+
48
+ // ../internal/dist/index.mjs
49
+ var resolveFn;
50
+ var rejectFn;
51
+ var mountInstance = new Promise((resolve, reject) => {
52
+ resolveFn = resolve;
53
+ rejectFn = reject;
54
+ });
55
+ var LOAD_FUNC_KEY = "captchaFoxOnLoad";
56
+ var SCRIPT_SRC = `https://cdn.captchafox.com/api.js?render=explicit&onload=${LOAD_FUNC_KEY}`;
57
+ function loadCaptchaScript() {
58
+ return __async(this, null, function* () {
59
+ if (document.querySelector(`script[src="${SCRIPT_SRC}"]`))
60
+ return mountInstance;
61
+ window[LOAD_FUNC_KEY] = resolveFn;
62
+ const script = document.createElement("script");
63
+ script.src = SCRIPT_SRC;
64
+ script.async = true;
65
+ script.defer = true;
66
+ script.type = "module";
67
+ script.onerror = rejectFn;
68
+ document.body.appendChild(script);
69
+ return mountInstance;
70
+ });
71
+ }
72
+ var isApiReady = () => typeof (window == null ? void 0 : window.captchafox) !== "undefined";
73
+
74
+ // src/CaptchaFox.tsx
75
+ var import_react = require("react");
76
+ var import_jsx_runtime = require("react/jsx-runtime");
77
+ var CaptchaFox = (0, import_react.forwardRef)(
78
+ ({ sitekey, lng, mode, className, onError, onVerify, onLoad, onFail, onClose }, ref) => {
79
+ const containerRef = (0, import_react.createRef)();
80
+ const [widgetId, setWidgetId] = (0, import_react.useState)();
81
+ const firstRendered = (0, import_react.useRef)(false);
82
+ (0, import_react.useImperativeHandle)(
83
+ ref,
84
+ () => {
85
+ return {
86
+ getResponse() {
87
+ if (!isApiReady() || !widgetId) {
88
+ console.warn("[CaptchaFox] Widget has not been loaded");
89
+ return "";
90
+ }
91
+ return window.captchafox.getResponse(widgetId);
92
+ },
93
+ reset() {
94
+ if (!isApiReady() || !widgetId) {
95
+ console.warn("[CaptchaFox] Widget has not been loaded");
96
+ return;
97
+ }
98
+ window.captchafox.reset(widgetId);
99
+ },
100
+ remove() {
101
+ if (!isApiReady() || !widgetId) {
102
+ console.warn("[CaptchaFox] Widget has not been loaded");
103
+ return;
104
+ }
105
+ setWidgetId("");
106
+ window.captchafox.remove(widgetId);
107
+ },
108
+ execute: () => {
109
+ if (!isApiReady() || !widgetId) {
110
+ return Promise.reject("[CaptchaFox] Widget has not been loaded");
111
+ }
112
+ return window.captchafox.execute(widgetId);
113
+ }
114
+ };
115
+ },
116
+ [widgetId]
117
+ );
118
+ const renderCaptcha = () => __async(void 0, null, function* () {
119
+ var _a, _b, _c, _d;
120
+ (_a = window.captchafox) == null ? void 0 : _a.remove(widgetId);
121
+ if (!containerRef.current || ((_c = (_b = containerRef.current) == null ? void 0 : _b.children) == null ? void 0 : _c.length) === 1)
122
+ return;
123
+ const newWidgetId = yield (_d = window.captchafox) == null ? void 0 : _d.render(containerRef.current, {
124
+ lng,
125
+ sitekey,
126
+ mode,
127
+ onError,
128
+ onFail,
129
+ onClose,
130
+ onVerify
131
+ });
132
+ setWidgetId(newWidgetId);
133
+ onLoad == null ? void 0 : onLoad();
134
+ });
135
+ (0, import_react.useEffect)(() => {
136
+ if (firstRendered.current) {
137
+ if (isApiReady()) {
138
+ renderCaptcha();
139
+ }
140
+ } else {
141
+ loadCaptchaScript().then(() => __async(void 0, null, function* () {
142
+ if (isApiReady()) {
143
+ firstRendered.current = true;
144
+ yield renderCaptcha();
145
+ }
146
+ })).catch((err) => {
147
+ onError == null ? void 0 : onError(err);
148
+ console.error("[CaptchaFox] Could not load script:", err);
149
+ });
150
+ }
151
+ }, [sitekey, lng, mode]);
152
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { ref: containerRef, id: widgetId, className });
153
+ }
154
+ );
155
+ CaptchaFox.displayName = "CaptchaFox";
156
+
157
+ // src/index.tsx
158
+ var CAPTCHA_RESPONSE_KEY = "cf-captcha-response";
159
+ // Annotate the CommonJS export names for ESM import in node:
160
+ 0 && (module.exports = {
161
+ CAPTCHA_RESPONSE_KEY,
162
+ CaptchaFox
163
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,136 @@
1
+ var __async = (__this, __arguments, generator) => {
2
+ return new Promise((resolve, reject) => {
3
+ var fulfilled = (value) => {
4
+ try {
5
+ step(generator.next(value));
6
+ } catch (e) {
7
+ reject(e);
8
+ }
9
+ };
10
+ var rejected = (value) => {
11
+ try {
12
+ step(generator.throw(value));
13
+ } catch (e) {
14
+ reject(e);
15
+ }
16
+ };
17
+ var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
18
+ step((generator = generator.apply(__this, __arguments)).next());
19
+ });
20
+ };
21
+
22
+ // ../internal/dist/index.mjs
23
+ var resolveFn;
24
+ var rejectFn;
25
+ var mountInstance = new Promise((resolve, reject) => {
26
+ resolveFn = resolve;
27
+ rejectFn = reject;
28
+ });
29
+ var LOAD_FUNC_KEY = "captchaFoxOnLoad";
30
+ var SCRIPT_SRC = `https://cdn.captchafox.com/api.js?render=explicit&onload=${LOAD_FUNC_KEY}`;
31
+ function loadCaptchaScript() {
32
+ return __async(this, null, function* () {
33
+ if (document.querySelector(`script[src="${SCRIPT_SRC}"]`))
34
+ return mountInstance;
35
+ window[LOAD_FUNC_KEY] = resolveFn;
36
+ const script = document.createElement("script");
37
+ script.src = SCRIPT_SRC;
38
+ script.async = true;
39
+ script.defer = true;
40
+ script.type = "module";
41
+ script.onerror = rejectFn;
42
+ document.body.appendChild(script);
43
+ return mountInstance;
44
+ });
45
+ }
46
+ var isApiReady = () => typeof (window == null ? void 0 : window.captchafox) !== "undefined";
47
+
48
+ // src/CaptchaFox.tsx
49
+ import { createRef, forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
50
+ import { jsx } from "react/jsx-runtime";
51
+ var CaptchaFox = forwardRef(
52
+ ({ sitekey, lng, mode, className, onError, onVerify, onLoad, onFail, onClose }, ref) => {
53
+ const containerRef = createRef();
54
+ const [widgetId, setWidgetId] = useState();
55
+ const firstRendered = useRef(false);
56
+ useImperativeHandle(
57
+ ref,
58
+ () => {
59
+ return {
60
+ getResponse() {
61
+ if (!isApiReady() || !widgetId) {
62
+ console.warn("[CaptchaFox] Widget has not been loaded");
63
+ return "";
64
+ }
65
+ return window.captchafox.getResponse(widgetId);
66
+ },
67
+ reset() {
68
+ if (!isApiReady() || !widgetId) {
69
+ console.warn("[CaptchaFox] Widget has not been loaded");
70
+ return;
71
+ }
72
+ window.captchafox.reset(widgetId);
73
+ },
74
+ remove() {
75
+ if (!isApiReady() || !widgetId) {
76
+ console.warn("[CaptchaFox] Widget has not been loaded");
77
+ return;
78
+ }
79
+ setWidgetId("");
80
+ window.captchafox.remove(widgetId);
81
+ },
82
+ execute: () => {
83
+ if (!isApiReady() || !widgetId) {
84
+ return Promise.reject("[CaptchaFox] Widget has not been loaded");
85
+ }
86
+ return window.captchafox.execute(widgetId);
87
+ }
88
+ };
89
+ },
90
+ [widgetId]
91
+ );
92
+ const renderCaptcha = () => __async(void 0, null, function* () {
93
+ var _a, _b, _c, _d;
94
+ (_a = window.captchafox) == null ? void 0 : _a.remove(widgetId);
95
+ if (!containerRef.current || ((_c = (_b = containerRef.current) == null ? void 0 : _b.children) == null ? void 0 : _c.length) === 1)
96
+ return;
97
+ const newWidgetId = yield (_d = window.captchafox) == null ? void 0 : _d.render(containerRef.current, {
98
+ lng,
99
+ sitekey,
100
+ mode,
101
+ onError,
102
+ onFail,
103
+ onClose,
104
+ onVerify
105
+ });
106
+ setWidgetId(newWidgetId);
107
+ onLoad == null ? void 0 : onLoad();
108
+ });
109
+ useEffect(() => {
110
+ if (firstRendered.current) {
111
+ if (isApiReady()) {
112
+ renderCaptcha();
113
+ }
114
+ } else {
115
+ loadCaptchaScript().then(() => __async(void 0, null, function* () {
116
+ if (isApiReady()) {
117
+ firstRendered.current = true;
118
+ yield renderCaptcha();
119
+ }
120
+ })).catch((err) => {
121
+ onError == null ? void 0 : onError(err);
122
+ console.error("[CaptchaFox] Could not load script:", err);
123
+ });
124
+ }
125
+ }, [sitekey, lng, mode]);
126
+ return /* @__PURE__ */ jsx("div", { ref: containerRef, id: widgetId, className });
127
+ }
128
+ );
129
+ CaptchaFox.displayName = "CaptchaFox";
130
+
131
+ // src/index.tsx
132
+ var CAPTCHA_RESPONSE_KEY = "cf-captcha-response";
133
+ export {
134
+ CAPTCHA_RESPONSE_KEY,
135
+ CaptchaFox
136
+ };
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@captchafox/react",
3
+ "version": "1.0.0",
4
+ "main": "./dist/index.js",
5
+ "module": "./dist/index.mjs",
6
+ "types": "./dist/index.d.ts",
7
+ "sideEffects": false,
8
+ "license": "MIT",
9
+ "files": [
10
+ "dist/**"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsup src/index.tsx --format esm,cjs --dts --external react",
14
+ "dev": "tsup src/index.tsx --format esm,cjs --watch --dts --external react",
15
+ "lint": "eslint \"src/**/*.ts*\"",
16
+ "clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist",
17
+ "test": "jest --coverage",
18
+ "test:watch": "jest --watch"
19
+ },
20
+ "peerDependencies": {
21
+ "react": ">=16.8.0",
22
+ "react-dom": ">=16.8.0"
23
+ },
24
+ "dependencies": {
25
+ "@captchafox/types": "*"
26
+ },
27
+ "devDependencies": {
28
+ "@captchafox/internal": "*",
29
+ "@testing-library/react": "^14.0.0",
30
+ "@testing-library/user-event": "^14.4.3",
31
+ "@testing-library/jest-dom": "^5.16.5",
32
+ "@types/jest": "^29.5.0",
33
+ "@types/react": "^18.0.9",
34
+ "@types/react-dom": "^18.0.4",
35
+ "eslint": "^8.15.0",
36
+ "eslint-config-captchafox": "*",
37
+ "jest": "^29.5.0",
38
+ "jest-environment-jsdom": "^29.5.0",
39
+ "react": "^18.1.0",
40
+ "tsup": "^6.6.3",
41
+ "ts-jest": "^29.0.5",
42
+ "typescript": "^4.9.5"
43
+ },
44
+ "bugs": {
45
+ "url": "https://github.com/CaptchaFox/javascript-integrations/issues"
46
+ },
47
+ "homepage": "https://github.com/CaptchaFox/javascript-integrations#readme"
48
+ }