@elsikora/x-captcha-react
Version:
React components for X-Captcha service
64 lines (61 loc) • 3.97 kB
JavaScript
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
import { useState, useMemo, useCallback } from 'react';
import { detectLanguage, createTranslator } from '../i18n/i18n.js';
import '../i18n/translations/index.js';
import { GenerateThemeVariables } from '../utility/generate-theme-variables.utility.js';
import { CaptchaWidget } from './CaptchaWidget.js';
import styles from '../styles/captcha-form.module.css.js';
/**
* Form component with integrated captcha and modern styling
* @param {ICaptchaFormProperties} props - The properties
* @returns {React.ReactElement} The captcha form
*/
const CaptchaForm = ({ apiUrl, buttonColor, children, className = "", language, onSubmit, publicKey, submitButtonText, themeColor = "#4285F4", ...captchaProperties }) => {
const [token, setToken] = useState(null);
const [error, setError] = useState(null);
const [isHovering, setIsHovering] = useState(false);
const [isFocused, setIsFocused] = useState(false);
// eslint-disable-next-line @elsikora/react/1/naming-convention/use-state
const [translate] = useState(() => {
const detectedLanguage = language ?? detectLanguage();
return createTranslator(detectedLanguage);
});
// Generate CSS variables from theme props
const themeVariables = useMemo(() => GenerateThemeVariables({
buttonColor,
themeColor,
}), [buttonColor, themeColor]);
const defaultSubmitText = submitButtonText ?? "Submit";
const handleVerify = useCallback((newToken) => {
setToken(newToken);
setError(null);
}, []);
const handleError = useCallback((errorMessage) => {
setToken(null);
setError(errorMessage);
}, []);
const handleSubmit = useCallback((event) => {
event.preventDefault();
if (!token) {
setError(translate("pleaseCompleteCaptcha"));
return;
}
onSubmit(token, event);
}, [token, onSubmit, translate]);
const buttonClasses = [styles["x-captcha-submit-button"], token ? styles["x-captcha-submit-button-active"] : styles["x-captcha-submit-button-disabled"], token && isHovering ? styles["x-captcha-submit-button-hover"] : "", token && isFocused ? styles["x-captcha-submit-button-focus"] : ""].filter(Boolean).join(" ");
return (jsxs("form", { className: `${styles["x-captcha-form"]} ${className}`, onSubmit: handleSubmit, style: themeVariables, children: [children ? jsx("div", { className: styles["x-captcha-children-container"], children: children }) : jsx(Fragment, {}), jsx("div", { className: styles["x-captcha-captcha-container"], children: jsx(CaptchaWidget, { apiUrl: apiUrl, language: language, onError: handleError, onVerify: handleVerify, publicKey: publicKey, themeColor: themeColor, ...captchaProperties }) }), error && (jsxs("div", { className: styles["x-captcha-error"], children: [jsx("span", { className: styles["x-captcha-error-icon"], children: jsxs("svg", { fill: "none", height: "16", stroke: "currentColor", strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: "2", viewBox: "0 0 24 24", width: "16", xmlns: "http://www.w3.org/2000/svg", children: [jsx("circle", { cx: "12", cy: "12", r: "10" }), jsx("line", { x1: "12", x2: "12", y1: "8", y2: "12" }), jsx("line", { x1: "12", x2: "12.01", y1: "16", y2: "16" })] }) }), error] })), jsx("button", { className: buttonClasses, disabled: !token, onBlur: () => {
if (token)
setIsFocused(false);
}, onFocus: () => {
if (token)
setIsFocused(true);
}, onMouseEnter: () => {
if (token)
setIsHovering(true);
}, onMouseLeave: () => {
if (token)
setIsHovering(false);
}, type: "submit", children: defaultSubmitText })] }));
};
export { CaptchaForm };
//# sourceMappingURL=CaptchaForm.js.map