@prosopo/procaptcha-react 2.5.5 → 2.6.1
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/CHANGELOG.md +27 -0
- package/dist/cjs/components/Button.cjs +77 -0
- package/dist/cjs/components/CaptchaComponent.cjs +230 -0
- package/dist/cjs/components/CaptchaWidget.cjs +141 -0
- package/dist/cjs/components/Modal.cjs +43 -0
- package/dist/cjs/components/Procaptcha.cjs +7 -0
- package/dist/cjs/components/ProcaptchaWidget.cjs +126 -0
- package/dist/cjs/components/index.cjs +9 -0
- package/dist/cjs/index.cjs +10 -0
- package/dist/cjs/util/index.cjs +18 -0
- package/package.json +14 -11
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# @prosopo/procaptcha-react
|
|
2
|
+
|
|
3
|
+
## 2.6.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies [52feffc]
|
|
8
|
+
- @prosopo/types@2.6.1
|
|
9
|
+
- @prosopo/procaptcha@2.6.1
|
|
10
|
+
- @prosopo/procaptcha-common@2.6.1
|
|
11
|
+
|
|
12
|
+
## 2.6.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- a0bfc8a: bump all pkg versions since independent versioning applied
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- Updated dependencies [a0bfc8a]
|
|
21
|
+
- @prosopo/common@2.6.0
|
|
22
|
+
- @prosopo/locale@2.6.0
|
|
23
|
+
- @prosopo/procaptcha@2.6.0
|
|
24
|
+
- @prosopo/procaptcha-common@2.6.0
|
|
25
|
+
- @prosopo/types@2.6.0
|
|
26
|
+
- @prosopo/util@2.6.0
|
|
27
|
+
- @prosopo/widget-skeleton@2.6.0
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const jsxRuntime = require("@emotion/react/jsx-runtime");
|
|
3
|
+
const widgetSkeleton = require("@prosopo/widget-skeleton");
|
|
4
|
+
const React = require("react");
|
|
5
|
+
const index = require("../util/index.cjs");
|
|
6
|
+
const buttonStyleBase = {
|
|
7
|
+
display: "inline-flex",
|
|
8
|
+
alignItems: "center",
|
|
9
|
+
justifyContent: "center",
|
|
10
|
+
position: "relative",
|
|
11
|
+
boxSizing: "border-box",
|
|
12
|
+
outline: "0px",
|
|
13
|
+
margin: "0px",
|
|
14
|
+
cursor: "pointer",
|
|
15
|
+
userSelect: "none",
|
|
16
|
+
verticalAlign: "middle",
|
|
17
|
+
appearance: void 0,
|
|
18
|
+
textDecoration: "none",
|
|
19
|
+
fontWeight: "500",
|
|
20
|
+
fontSize: "0.875rem",
|
|
21
|
+
lineHeight: "1.75",
|
|
22
|
+
letterSpacing: "0.02857em",
|
|
23
|
+
textTransform: "uppercase",
|
|
24
|
+
minWidth: "64px",
|
|
25
|
+
padding: "6px 16px",
|
|
26
|
+
borderRadius: "4px",
|
|
27
|
+
transition: "background-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, box-shadow 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, border-color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms, color 250ms cubic-bezier(0.4, 0, 0.2, 1) 0ms",
|
|
28
|
+
backgroundColor: "#ffffff"
|
|
29
|
+
};
|
|
30
|
+
const Button = ({
|
|
31
|
+
themeColor,
|
|
32
|
+
buttonType,
|
|
33
|
+
text,
|
|
34
|
+
onClick
|
|
35
|
+
}) => {
|
|
36
|
+
const theme = React.useMemo(
|
|
37
|
+
() => themeColor === "light" ? widgetSkeleton.lightTheme : widgetSkeleton.darkTheme,
|
|
38
|
+
[themeColor]
|
|
39
|
+
);
|
|
40
|
+
const [hover, setHover] = React.useState(false);
|
|
41
|
+
const buttonStyle = React.useMemo(() => {
|
|
42
|
+
const baseStyle = {
|
|
43
|
+
...buttonStyleBase,
|
|
44
|
+
border: `1px solid ${theme.palette.grey[500]}`,
|
|
45
|
+
boxShadow: `0px 1px 3px 0px ${theme.palette.grey[500]}`,
|
|
46
|
+
fontFamily: theme.font.fontFamily,
|
|
47
|
+
width: "100%",
|
|
48
|
+
color: hover ? theme.palette.primary.contrastText : theme.palette.background.contrastText
|
|
49
|
+
};
|
|
50
|
+
if (buttonType === "cancel") {
|
|
51
|
+
return {
|
|
52
|
+
...baseStyle,
|
|
53
|
+
backgroundColor: hover ? theme.palette.grey[600] : "transparent"
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
...baseStyle,
|
|
58
|
+
backgroundColor: hover ? theme.palette.primary.main : theme.palette.background.default
|
|
59
|
+
};
|
|
60
|
+
}, [buttonType, hover, theme]);
|
|
61
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
62
|
+
"button",
|
|
63
|
+
{
|
|
64
|
+
...index({ dev: { cy: `button-${buttonType}` } }),
|
|
65
|
+
onMouseEnter: () => setHover(true),
|
|
66
|
+
onMouseLeave: () => setHover(false),
|
|
67
|
+
style: buttonStyle,
|
|
68
|
+
onClick: (e) => {
|
|
69
|
+
e.preventDefault();
|
|
70
|
+
onClick();
|
|
71
|
+
},
|
|
72
|
+
"aria-label": text,
|
|
73
|
+
children: text
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
};
|
|
77
|
+
module.exports = Button;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const jsxRuntime = require("@emotion/react/jsx-runtime");
|
|
3
|
+
const locale = require("@prosopo/locale");
|
|
4
|
+
const procaptchaCommon = require("@prosopo/procaptcha-common");
|
|
5
|
+
const util = require("@prosopo/util");
|
|
6
|
+
const widgetSkeleton = require("@prosopo/widget-skeleton");
|
|
7
|
+
const React = require("react");
|
|
8
|
+
const index = require("../util/index.cjs");
|
|
9
|
+
const Button = require("./Button.cjs");
|
|
10
|
+
const CaptchaWidget = require("./CaptchaWidget.cjs");
|
|
11
|
+
const CaptchaComponent = ({
|
|
12
|
+
challenge,
|
|
13
|
+
index: index$1,
|
|
14
|
+
solutions,
|
|
15
|
+
onSubmit,
|
|
16
|
+
onCancel,
|
|
17
|
+
onClick,
|
|
18
|
+
onNext,
|
|
19
|
+
onReload,
|
|
20
|
+
themeColor
|
|
21
|
+
}) => {
|
|
22
|
+
const { t } = locale.useTranslation();
|
|
23
|
+
const captcha = challenge.captchas ? util.at(challenge.captchas, index$1) : null;
|
|
24
|
+
const solution = solutions ? util.at(solutions, index$1) : [];
|
|
25
|
+
const theme = React.useMemo(
|
|
26
|
+
() => themeColor === "light" ? widgetSkeleton.lightTheme : widgetSkeleton.darkTheme,
|
|
27
|
+
[themeColor]
|
|
28
|
+
);
|
|
29
|
+
const doubleSpacing = `${theme.spacing.unit * 2}px`;
|
|
30
|
+
const fullSpacing = `${theme.spacing.unit}px`;
|
|
31
|
+
const halfSpacing = `${theme.spacing.half}px`;
|
|
32
|
+
return /* @__PURE__ */ jsxRuntime.jsx(React.Suspense, { fallback: /* @__PURE__ */ jsxRuntime.jsx("div", { children: "Loading..." }), children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
33
|
+
"div",
|
|
34
|
+
{
|
|
35
|
+
style: {
|
|
36
|
+
// introduce scroll bars when screen < minWidth of children
|
|
37
|
+
overflowX: "auto",
|
|
38
|
+
overflowY: "auto",
|
|
39
|
+
maxWidth: "500px",
|
|
40
|
+
maxHeight: "100%",
|
|
41
|
+
display: "flex",
|
|
42
|
+
flexDirection: "column",
|
|
43
|
+
border: "1px solid #dddddd",
|
|
44
|
+
boxShadow: "rgba(255, 255, 255, 0.2) 0px 0px 4px",
|
|
45
|
+
borderRadius: "4px",
|
|
46
|
+
backgroundColor: theme.palette.background.default,
|
|
47
|
+
userSelect: "none",
|
|
48
|
+
touchAction: "none",
|
|
49
|
+
overscrollBehavior: "none"
|
|
50
|
+
},
|
|
51
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
52
|
+
"div",
|
|
53
|
+
{
|
|
54
|
+
style: {
|
|
55
|
+
backgroundColor: theme.palette.background.default,
|
|
56
|
+
display: "flex",
|
|
57
|
+
flexDirection: "column",
|
|
58
|
+
minWidth: "300px",
|
|
59
|
+
marginLeft: fullSpacing,
|
|
60
|
+
marginRight: fullSpacing,
|
|
61
|
+
justifyContent: "center"
|
|
62
|
+
},
|
|
63
|
+
children: [
|
|
64
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
65
|
+
"div",
|
|
66
|
+
{
|
|
67
|
+
style: {
|
|
68
|
+
display: "flex",
|
|
69
|
+
alignItems: "center",
|
|
70
|
+
width: "100%"
|
|
71
|
+
},
|
|
72
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
73
|
+
"div",
|
|
74
|
+
{
|
|
75
|
+
style: {
|
|
76
|
+
backgroundColor: theme.palette.primary.main,
|
|
77
|
+
width: "100%",
|
|
78
|
+
marginTop: fullSpacing
|
|
79
|
+
},
|
|
80
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
81
|
+
"div",
|
|
82
|
+
{
|
|
83
|
+
style: {
|
|
84
|
+
padding: `${theme.spacing.half}px`,
|
|
85
|
+
fontFamily: theme.font.fontFamily
|
|
86
|
+
},
|
|
87
|
+
children: [
|
|
88
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
89
|
+
"p",
|
|
90
|
+
{
|
|
91
|
+
style: {
|
|
92
|
+
color: "#ffffff",
|
|
93
|
+
fontWeight: 700,
|
|
94
|
+
lineHeight: 1.5
|
|
95
|
+
},
|
|
96
|
+
children: [
|
|
97
|
+
t("WIDGET.SELECT_ALL"),
|
|
98
|
+
":",
|
|
99
|
+
" ",
|
|
100
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: `${util.at(challenge.captchas, index$1).target} ` })
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
),
|
|
104
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
105
|
+
"p",
|
|
106
|
+
{
|
|
107
|
+
style: {
|
|
108
|
+
color: "#ffffff",
|
|
109
|
+
fontWeight: 500,
|
|
110
|
+
lineHeight: 0.8,
|
|
111
|
+
fontSize: "0.8rem"
|
|
112
|
+
},
|
|
113
|
+
children: t("WIDGET.IF_NONE_CLICK_NEXT")
|
|
114
|
+
}
|
|
115
|
+
)
|
|
116
|
+
]
|
|
117
|
+
}
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
),
|
|
123
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
124
|
+
"div",
|
|
125
|
+
{
|
|
126
|
+
...index({ dev: { cy: `captcha-${index$1}` } }),
|
|
127
|
+
style: { overflow: "hidden" },
|
|
128
|
+
children: captcha && /* @__PURE__ */ jsxRuntime.jsx(
|
|
129
|
+
CaptchaWidget.CaptchaWidget,
|
|
130
|
+
{
|
|
131
|
+
challenge: captcha,
|
|
132
|
+
solution,
|
|
133
|
+
onClick,
|
|
134
|
+
themeColor
|
|
135
|
+
}
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
),
|
|
139
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
140
|
+
"div",
|
|
141
|
+
{
|
|
142
|
+
style: {
|
|
143
|
+
display: "flex",
|
|
144
|
+
alignItems: "center",
|
|
145
|
+
justifyContent: "space-between",
|
|
146
|
+
lineHeight: 1.75,
|
|
147
|
+
padding: `${fullSpacing} 0 ${doubleSpacing} 0`
|
|
148
|
+
},
|
|
149
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
150
|
+
"div",
|
|
151
|
+
{
|
|
152
|
+
style: {
|
|
153
|
+
// expand to full height / width of parent
|
|
154
|
+
width: "100%",
|
|
155
|
+
height: "100%",
|
|
156
|
+
// display children in flex, spreading them evenly and wrapping when row length exceeded
|
|
157
|
+
display: "flex",
|
|
158
|
+
flexDirection: "row",
|
|
159
|
+
flexWrap: "wrap",
|
|
160
|
+
justifyContent: "space-between",
|
|
161
|
+
gap: "10px"
|
|
162
|
+
},
|
|
163
|
+
children: [
|
|
164
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
165
|
+
"div",
|
|
166
|
+
{
|
|
167
|
+
style: {
|
|
168
|
+
position: "relative",
|
|
169
|
+
flexGrow: 1,
|
|
170
|
+
// make the width of each item 1/3rd of the width overall, i.e. 3 columns
|
|
171
|
+
flexBasis: "calc(33.333% - 10px)"
|
|
172
|
+
},
|
|
173
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
174
|
+
Button,
|
|
175
|
+
{
|
|
176
|
+
themeColor,
|
|
177
|
+
buttonType: "cancel",
|
|
178
|
+
onClick: onCancel,
|
|
179
|
+
text: t("WIDGET.CANCEL"),
|
|
180
|
+
"aria-label": t("WIDGET.CANCEL")
|
|
181
|
+
}
|
|
182
|
+
)
|
|
183
|
+
}
|
|
184
|
+
),
|
|
185
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
186
|
+
"div",
|
|
187
|
+
{
|
|
188
|
+
style: {
|
|
189
|
+
position: "relative",
|
|
190
|
+
flexGrow: 1,
|
|
191
|
+
// make the width of each item 1/3rd of the width overall, i.e. 3 columns
|
|
192
|
+
flexBasis: "calc(33.333% - 10px)"
|
|
193
|
+
},
|
|
194
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(procaptchaCommon.ReloadButton, { themeColor, onReload })
|
|
195
|
+
}
|
|
196
|
+
),
|
|
197
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
198
|
+
"div",
|
|
199
|
+
{
|
|
200
|
+
style: {
|
|
201
|
+
position: "relative",
|
|
202
|
+
flexGrow: 1,
|
|
203
|
+
// make the width of each item 1/3rd of the width overall, i.e. 3 columns
|
|
204
|
+
flexBasis: "calc(33.333% - 10px)"
|
|
205
|
+
},
|
|
206
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
207
|
+
Button,
|
|
208
|
+
{
|
|
209
|
+
themeColor,
|
|
210
|
+
buttonType: "next",
|
|
211
|
+
text: index$1 < challenge.captchas.length - 1 ? t("WIDGET.NEXT") : t("WIDGET.SUBMIT"),
|
|
212
|
+
onClick: index$1 < challenge.captchas.length - 1 ? onNext : onSubmit,
|
|
213
|
+
"aria-label": index$1 < challenge.captchas.length - 1 ? t("WIDGET.NEXT") : t("WIDGET.SUBMIT"),
|
|
214
|
+
"data-cy": "button-next"
|
|
215
|
+
}
|
|
216
|
+
)
|
|
217
|
+
}
|
|
218
|
+
)
|
|
219
|
+
]
|
|
220
|
+
}
|
|
221
|
+
)
|
|
222
|
+
}
|
|
223
|
+
)
|
|
224
|
+
]
|
|
225
|
+
}
|
|
226
|
+
)
|
|
227
|
+
}
|
|
228
|
+
) });
|
|
229
|
+
};
|
|
230
|
+
module.exports = CaptchaComponent;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const jsxRuntime = require("@emotion/react/jsx-runtime");
|
|
4
|
+
const common = require("@prosopo/common");
|
|
5
|
+
const widgetSkeleton = require("@prosopo/widget-skeleton");
|
|
6
|
+
const React = require("react");
|
|
7
|
+
const getHash = (item) => {
|
|
8
|
+
if (!item.hash) {
|
|
9
|
+
throw new common.ProsopoDatasetError("CAPTCHA.MISSING_ITEM_HASH", {
|
|
10
|
+
context: { item }
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
return item.hash;
|
|
14
|
+
};
|
|
15
|
+
const CaptchaWidget = ({
|
|
16
|
+
challenge,
|
|
17
|
+
solution,
|
|
18
|
+
onClick,
|
|
19
|
+
themeColor
|
|
20
|
+
}) => {
|
|
21
|
+
const items = challenge.items;
|
|
22
|
+
const theme = React.useMemo(
|
|
23
|
+
() => themeColor === "light" ? widgetSkeleton.lightTheme : widgetSkeleton.darkTheme,
|
|
24
|
+
[themeColor]
|
|
25
|
+
);
|
|
26
|
+
const fullSpacing = `${theme.spacing.unit}px`;
|
|
27
|
+
const halfSpacing = `${theme.spacing.half}px`;
|
|
28
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
29
|
+
"div",
|
|
30
|
+
{
|
|
31
|
+
style: {
|
|
32
|
+
// expand to full height / width of parent
|
|
33
|
+
width: "100%",
|
|
34
|
+
height: "100%",
|
|
35
|
+
// display children in flex, spreading them evenly and wrapping when row length exceeded
|
|
36
|
+
display: "flex",
|
|
37
|
+
flexDirection: "row",
|
|
38
|
+
flexWrap: "wrap",
|
|
39
|
+
justifyContent: "space-between",
|
|
40
|
+
paddingBottom: fullSpacing,
|
|
41
|
+
paddingTop: fullSpacing,
|
|
42
|
+
gap: "10px"
|
|
43
|
+
},
|
|
44
|
+
children: items.map((item, index) => {
|
|
45
|
+
const hash = getHash(item);
|
|
46
|
+
const imageStyle = {
|
|
47
|
+
// enable the items in the grid to grow in width to use up excess space
|
|
48
|
+
flexGrow: 1,
|
|
49
|
+
// make the width of each item 1/3rd of the width overall, i.e. 3 columns
|
|
50
|
+
flexBasis: "calc(33.333% - 10px)",
|
|
51
|
+
// include the padding / margin / border in the width
|
|
52
|
+
boxSizing: "border-box"
|
|
53
|
+
};
|
|
54
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: imageStyle, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
55
|
+
"div",
|
|
56
|
+
{
|
|
57
|
+
style: {
|
|
58
|
+
position: "relative",
|
|
59
|
+
cursor: "pointer",
|
|
60
|
+
height: "100%",
|
|
61
|
+
width: "100%",
|
|
62
|
+
padding: 0,
|
|
63
|
+
margin: 0
|
|
64
|
+
},
|
|
65
|
+
onClick: () => onClick(hash),
|
|
66
|
+
children: [
|
|
67
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
68
|
+
"img",
|
|
69
|
+
{
|
|
70
|
+
style: {
|
|
71
|
+
width: "100%",
|
|
72
|
+
// image should be full width / height of the item
|
|
73
|
+
display: "block",
|
|
74
|
+
// removes whitespace below imgs
|
|
75
|
+
objectFit: "cover",
|
|
76
|
+
// contain the entire image in the img tag
|
|
77
|
+
aspectRatio: "1/1",
|
|
78
|
+
// force AR to be 1, letterboxing images with different aspect ratios
|
|
79
|
+
height: "auto",
|
|
80
|
+
// make the img tag responsive to its container
|
|
81
|
+
overflow: "hidden",
|
|
82
|
+
borderStyle: "solid",
|
|
83
|
+
borderWidth: "1px",
|
|
84
|
+
borderColor: theme.palette.grey[300]
|
|
85
|
+
},
|
|
86
|
+
src: item.data,
|
|
87
|
+
alt: `Captcha image ${index + 1}`
|
|
88
|
+
}
|
|
89
|
+
),
|
|
90
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
91
|
+
"div",
|
|
92
|
+
{
|
|
93
|
+
style: {
|
|
94
|
+
position: "absolute",
|
|
95
|
+
top: 0,
|
|
96
|
+
left: 0,
|
|
97
|
+
bottom: 0,
|
|
98
|
+
right: 0,
|
|
99
|
+
height: "100%",
|
|
100
|
+
width: "100%",
|
|
101
|
+
// display overlays in center
|
|
102
|
+
display: "flex",
|
|
103
|
+
alignItems: "center",
|
|
104
|
+
justifyContent: "center",
|
|
105
|
+
// make bg half opacity, i.e. shadowing the item's img
|
|
106
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
107
|
+
visibility: solution.includes(hash) ? "visible" : "hidden"
|
|
108
|
+
},
|
|
109
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
110
|
+
"svg",
|
|
111
|
+
{
|
|
112
|
+
style: {
|
|
113
|
+
backgroundColor: "transparent",
|
|
114
|
+
// img must be displayed as block otherwise gets a bottom whitespace border
|
|
115
|
+
display: "block",
|
|
116
|
+
// how big the overlay icon is
|
|
117
|
+
width: "35%",
|
|
118
|
+
height: "35%",
|
|
119
|
+
transition: "fill 200ms cubic-bezier(0.4, 0, 0.2, 1) 0ms",
|
|
120
|
+
userSelect: "none",
|
|
121
|
+
fill: "currentcolor"
|
|
122
|
+
},
|
|
123
|
+
focusable: "false",
|
|
124
|
+
color: "#fff",
|
|
125
|
+
"aria-hidden": "true",
|
|
126
|
+
viewBox: "0 0 24 24",
|
|
127
|
+
"data-testid": "CheckIcon",
|
|
128
|
+
"aria-label": "Check icon",
|
|
129
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M9 16.17 4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" })
|
|
130
|
+
}
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
)
|
|
134
|
+
]
|
|
135
|
+
}
|
|
136
|
+
) }, item.hash);
|
|
137
|
+
})
|
|
138
|
+
}
|
|
139
|
+
);
|
|
140
|
+
};
|
|
141
|
+
exports.CaptchaWidget = CaptchaWidget;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const jsxRuntime = require("@emotion/react/jsx-runtime");
|
|
3
|
+
const react = require("@emotion/react");
|
|
4
|
+
const React = require("react");
|
|
5
|
+
const reactDom = require("react-dom");
|
|
6
|
+
const ModalInnerDivCSS = react.css`
|
|
7
|
+
position: absolute;
|
|
8
|
+
top: 50%;
|
|
9
|
+
left: 50%;
|
|
10
|
+
transform: translate(-50%, -50%);
|
|
11
|
+
max-width: 500px;
|
|
12
|
+
background-color: transparent;
|
|
13
|
+
border: none;
|
|
14
|
+
border-radius: 4px;
|
|
15
|
+
z-index: 2147483647;
|
|
16
|
+
align-self: center;
|
|
17
|
+
box-shadow: rgba(0, 0, 0, 0.2) 0px 11px 15px -7px,
|
|
18
|
+
rgba(0, 0, 0, 0.14) 0px 24px 38px 3px,
|
|
19
|
+
rgba(0, 0, 0, 0.12) 0px 9px 46px 8px;
|
|
20
|
+
box-sizing: border-box; /* Ensures border is part of width */
|
|
21
|
+
/* iOS only */
|
|
22
|
+
@supports (-webkit-touch-callout: none) {
|
|
23
|
+
transform: translate(-50%, -100%);
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
const ModalComponent = React.memo((props) => {
|
|
27
|
+
const { show, children } = props;
|
|
28
|
+
const display = show ? "flex" : "none";
|
|
29
|
+
const ModalOuterDivCss = {
|
|
30
|
+
position: "fixed",
|
|
31
|
+
zIndex: 2147483646,
|
|
32
|
+
inset: 0,
|
|
33
|
+
display,
|
|
34
|
+
alignItems: "center",
|
|
35
|
+
justifyContent: "center",
|
|
36
|
+
minHeight: "100vh"
|
|
37
|
+
};
|
|
38
|
+
return reactDom.createPortal(
|
|
39
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "prosopo-modalOuter", style: ModalOuterDivCss, children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "prosopo-modalInner", css: ModalInnerDivCSS, children }) }),
|
|
40
|
+
document.body
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
module.exports = ModalComponent;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const jsxRuntime = require("@emotion/react/jsx-runtime");
|
|
3
|
+
const React = require("react");
|
|
4
|
+
const _interopNamespaceDefaultOnly = (e) => Object.freeze(Object.defineProperty({ __proto__: null, default: e }, Symbol.toStringTag, { value: "Module" }));
|
|
5
|
+
const ProcaptchaWidget = React.lazy(async () => Promise.resolve().then(() => /* @__PURE__ */ _interopNamespaceDefaultOnly(require("./ProcaptchaWidget.cjs"))));
|
|
6
|
+
const Procaptcha = (props) => /* @__PURE__ */ jsxRuntime.jsx(React.Suspense, { children: /* @__PURE__ */ jsxRuntime.jsx(ProcaptchaWidget, { ...props }) });
|
|
7
|
+
module.exports = Procaptcha;
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
const jsxRuntime = require("@emotion/react/jsx-runtime");
|
|
3
|
+
const locale = require("@prosopo/locale");
|
|
4
|
+
const procaptcha = require("@prosopo/procaptcha");
|
|
5
|
+
const procaptchaCommon = require("@prosopo/procaptcha-common");
|
|
6
|
+
const types = require("@prosopo/types");
|
|
7
|
+
const widgetSkeleton = require("@prosopo/widget-skeleton");
|
|
8
|
+
const React = require("react");
|
|
9
|
+
const CaptchaComponent = require("./CaptchaComponent.cjs");
|
|
10
|
+
const Modal = require("./Modal.cjs");
|
|
11
|
+
const PROCAPTCHA_EXECUTE_EVENT = "procaptcha:execute";
|
|
12
|
+
const ProcaptchaWidget = (props) => {
|
|
13
|
+
const { t } = locale.useTranslation();
|
|
14
|
+
const config = types.ProcaptchaConfigSchema.parse(props.config);
|
|
15
|
+
const frictionlessState = props.frictionlessState;
|
|
16
|
+
const i18n = props.i18n;
|
|
17
|
+
const callbacks = props.callbacks || {};
|
|
18
|
+
const [state, updateState] = procaptchaCommon.useProcaptcha(React.useState, React.useRef);
|
|
19
|
+
const [loading, setLoading] = React.useState(false);
|
|
20
|
+
const manager = procaptcha.Manager(
|
|
21
|
+
config,
|
|
22
|
+
state,
|
|
23
|
+
updateState,
|
|
24
|
+
callbacks,
|
|
25
|
+
frictionlessState
|
|
26
|
+
);
|
|
27
|
+
const theme = "light" === props.config.theme ? widgetSkeleton.lightTheme : widgetSkeleton.darkTheme;
|
|
28
|
+
React.useEffect(() => {
|
|
29
|
+
if (config.language) {
|
|
30
|
+
if (i18n) {
|
|
31
|
+
if (i18n.language !== config.language) {
|
|
32
|
+
i18n.changeLanguage(config.language).then((r) => r);
|
|
33
|
+
}
|
|
34
|
+
} else {
|
|
35
|
+
locale.loadI18next(false).then((i18n2) => {
|
|
36
|
+
if (i18n2.language !== config.language)
|
|
37
|
+
i18n2.changeLanguage(config.language).then((r) => r);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}, [i18n, config.language]);
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
if (state.error) {
|
|
44
|
+
setLoading(false);
|
|
45
|
+
if (state.error.key === "CAPTCHA.NO_SESSION_FOUND" && frictionlessState) {
|
|
46
|
+
setTimeout(() => {
|
|
47
|
+
frictionlessState.restart();
|
|
48
|
+
}, 3e3);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}, [state.error, frictionlessState]);
|
|
52
|
+
React.useEffect(() => {
|
|
53
|
+
const handleExecuteEvent = (event) => {
|
|
54
|
+
updateState({
|
|
55
|
+
showModal: true
|
|
56
|
+
});
|
|
57
|
+
if (!state.challenge && manager.start) {
|
|
58
|
+
console.log("No challenge set, attempting to start verification");
|
|
59
|
+
try {
|
|
60
|
+
manager.start();
|
|
61
|
+
} catch (error) {
|
|
62
|
+
console.error("Error starting verification:", error);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
document.addEventListener(PROCAPTCHA_EXECUTE_EVENT, handleExecuteEvent);
|
|
67
|
+
return () => {
|
|
68
|
+
document.removeEventListener(
|
|
69
|
+
PROCAPTCHA_EXECUTE_EVENT,
|
|
70
|
+
handleExecuteEvent
|
|
71
|
+
);
|
|
72
|
+
};
|
|
73
|
+
}, [manager, state.challenge, updateState]);
|
|
74
|
+
if (config.mode === "invisible") {
|
|
75
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Modal, { show: state.showModal, children: state.challenge ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
76
|
+
CaptchaComponent,
|
|
77
|
+
{
|
|
78
|
+
challenge: state.challenge,
|
|
79
|
+
index: state.index,
|
|
80
|
+
solutions: state.solutions,
|
|
81
|
+
onSubmit: manager.submit,
|
|
82
|
+
onCancel: manager.cancel,
|
|
83
|
+
onClick: manager.select,
|
|
84
|
+
onNext: manager.nextRound,
|
|
85
|
+
onReload: manager.reload,
|
|
86
|
+
themeColor: config.theme ?? "light"
|
|
87
|
+
}
|
|
88
|
+
) : null });
|
|
89
|
+
}
|
|
90
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "image-captcha", children: [
|
|
91
|
+
/* @__PURE__ */ jsxRuntime.jsx(Modal, { show: state.showModal, children: state.challenge ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
92
|
+
CaptchaComponent,
|
|
93
|
+
{
|
|
94
|
+
challenge: state.challenge,
|
|
95
|
+
index: state.index,
|
|
96
|
+
solutions: state.solutions,
|
|
97
|
+
onSubmit: manager.submit,
|
|
98
|
+
onCancel: manager.cancel,
|
|
99
|
+
onClick: manager.select,
|
|
100
|
+
onNext: manager.nextRound,
|
|
101
|
+
onReload: manager.reload,
|
|
102
|
+
themeColor: config.theme ?? "light"
|
|
103
|
+
}
|
|
104
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: "No challenge set." }) }),
|
|
105
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
106
|
+
procaptchaCommon.Checkbox,
|
|
107
|
+
{
|
|
108
|
+
theme,
|
|
109
|
+
onChange: async () => {
|
|
110
|
+
if (loading) {
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
setLoading(true);
|
|
114
|
+
await manager.start();
|
|
115
|
+
setLoading(false);
|
|
116
|
+
},
|
|
117
|
+
checked: state.isHuman,
|
|
118
|
+
labelText: t("WIDGET.I_AM_HUMAN"),
|
|
119
|
+
error: state.error?.message,
|
|
120
|
+
"aria-label": "human checkbox",
|
|
121
|
+
loading
|
|
122
|
+
}
|
|
123
|
+
)
|
|
124
|
+
] });
|
|
125
|
+
};
|
|
126
|
+
module.exports = ProcaptchaWidget;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
const CaptchaWidget = require("./CaptchaWidget.cjs");
|
|
4
|
+
require("./CaptchaComponent.cjs");
|
|
5
|
+
const ProcaptchaWidget = require("./ProcaptchaWidget.cjs");
|
|
6
|
+
const Procaptcha = require("./Procaptcha.cjs");
|
|
7
|
+
exports.CaptchaWidget = CaptchaWidget.CaptchaWidget;
|
|
8
|
+
exports.ProcaptchaWidget = ProcaptchaWidget;
|
|
9
|
+
exports.Procaptcha = Procaptcha;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
+
require("./components/index.cjs");
|
|
4
|
+
require("./util/index.cjs");
|
|
5
|
+
const ProcaptchaWidget = require("./components/ProcaptchaWidget.cjs");
|
|
6
|
+
const Procaptcha = require("./components/Procaptcha.cjs");
|
|
7
|
+
const CaptchaWidget = require("./components/CaptchaWidget.cjs");
|
|
8
|
+
exports.ProcaptchaWidget = ProcaptchaWidget;
|
|
9
|
+
exports.Procaptcha = Procaptcha;
|
|
10
|
+
exports.CaptchaWidget = CaptchaWidget.CaptchaWidget;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
function renameKeysForDataAttr(data = {}) {
|
|
3
|
+
return Object.keys(data).reduce(
|
|
4
|
+
// biome-ignore lint/performance/noAccumulatingSpread: TODO fix
|
|
5
|
+
(prev, curr) => ({ ...prev, [`data-${curr}`]: data[curr] }),
|
|
6
|
+
{}
|
|
7
|
+
);
|
|
8
|
+
}
|
|
9
|
+
function addDataAttr({
|
|
10
|
+
general,
|
|
11
|
+
dev
|
|
12
|
+
}) {
|
|
13
|
+
return {
|
|
14
|
+
...renameKeysForDataAttr(general),
|
|
15
|
+
...process.env.NODE_ENV !== "production" ? renameKeysForDataAttr(dev) : {}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
module.exports = addDataAttr;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@prosopo/procaptcha-react",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"author": "PROSOPO LIMITED <info@prosopo.io>",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -24,15 +24,17 @@
|
|
|
24
24
|
"build": "tsc --build --verbose",
|
|
25
25
|
"build:cjs": "npx vite --config vite.cjs.config.ts build"
|
|
26
26
|
},
|
|
27
|
-
"browserslist": [
|
|
27
|
+
"browserslist": [
|
|
28
|
+
"> 0.5%, last 2 versions, not dead"
|
|
29
|
+
],
|
|
28
30
|
"dependencies": {
|
|
29
|
-
"@prosopo/common": "2.
|
|
30
|
-
"@prosopo/locale": "2.
|
|
31
|
-
"@prosopo/procaptcha": "2.
|
|
32
|
-
"@prosopo/procaptcha-common": "2.
|
|
33
|
-
"@prosopo/types": "2.
|
|
34
|
-
"@prosopo/util": "2.
|
|
35
|
-
"@prosopo/widget-skeleton": "2.
|
|
31
|
+
"@prosopo/common": "2.6.0",
|
|
32
|
+
"@prosopo/locale": "2.6.0",
|
|
33
|
+
"@prosopo/procaptcha": "2.6.1",
|
|
34
|
+
"@prosopo/procaptcha-common": "2.6.1",
|
|
35
|
+
"@prosopo/types": "2.6.1",
|
|
36
|
+
"@prosopo/util": "2.6.0",
|
|
37
|
+
"@prosopo/widget-skeleton": "2.6.0",
|
|
36
38
|
"csstype": "3.1.3",
|
|
37
39
|
"express": "4.21.2",
|
|
38
40
|
"react": "18.3.1"
|
|
@@ -50,7 +52,7 @@
|
|
|
50
52
|
}
|
|
51
53
|
},
|
|
52
54
|
"devDependencies": {
|
|
53
|
-
"@prosopo/config": "2.
|
|
55
|
+
"@prosopo/config": "2.6.0",
|
|
54
56
|
"@vitest/coverage-v8": "3.0.9",
|
|
55
57
|
"concurrently": "9.0.1",
|
|
56
58
|
"del-cli": "6.0.0",
|
|
@@ -63,7 +65,8 @@
|
|
|
63
65
|
},
|
|
64
66
|
"repository": {
|
|
65
67
|
"type": "git",
|
|
66
|
-
"url": "git+https://github.com/prosopo/captcha.git"
|
|
68
|
+
"url": "git+https://github.com/prosopo/captcha.git",
|
|
69
|
+
"directory": "packages/procaptcha-react"
|
|
67
70
|
},
|
|
68
71
|
"bugs": {
|
|
69
72
|
"url": "https://github.com/prosopo/captcha/issues"
|