@prosopo/procaptcha-puzzle 2.13.3 → 2.14.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.
Files changed (72) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +6 -6
  2. package/.turbo/turbo-build$colon$tsc.log +19 -19
  3. package/.turbo/turbo-build.log +7 -7
  4. package/CHANGELOG.md +41 -0
  5. package/dist/cjs/components/procaptchaPuzzle.cjs +22 -0
  6. package/dist/cjs/components/procaptchaWidget.cjs +225 -0
  7. package/dist/cjs/components/puzzleCanvas.cjs +450 -0
  8. package/dist/cjs/index.cjs +7 -2
  9. package/dist/components/procaptchaPuzzle.d.ts +7 -0
  10. package/dist/components/procaptchaPuzzle.d.ts.map +1 -0
  11. package/dist/components/procaptchaPuzzle.js +21 -0
  12. package/dist/components/procaptchaPuzzle.js.map +1 -0
  13. package/dist/components/procaptchaWidget.d.ts +7 -0
  14. package/dist/components/procaptchaWidget.d.ts.map +1 -0
  15. package/dist/components/procaptchaWidget.js +225 -0
  16. package/dist/components/procaptchaWidget.js.map +1 -0
  17. package/dist/components/{PuzzleCanvas.d.ts → puzzleCanvas.d.ts} +6 -4
  18. package/dist/components/puzzleCanvas.d.ts.map +1 -0
  19. package/dist/components/puzzleCanvas.js +450 -0
  20. package/dist/components/puzzleCanvas.js.map +1 -0
  21. package/dist/index.d.ts +3 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +4 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/tests/domHarness.d.ts +20 -0
  26. package/dist/tests/domHarness.d.ts.map +1 -0
  27. package/dist/tests/domHarness.js +56 -0
  28. package/dist/tests/domHarness.js.map +1 -0
  29. package/dist/tests/procaptchaPuzzle.test-d.js +13 -10
  30. package/dist/tests/procaptchaPuzzle.test-d.js.map +1 -1
  31. package/dist/tests/procaptchaPuzzle.unit.test.js +44 -33
  32. package/dist/tests/procaptchaPuzzle.unit.test.js.map +1 -1
  33. package/dist/tests/procaptchaWidget.unit.test.js +108 -175
  34. package/dist/tests/procaptchaWidget.unit.test.js.map +1 -1
  35. package/dist/tests/puzzleCanvas.unit.test.js +47 -80
  36. package/dist/tests/puzzleCanvas.unit.test.js.map +1 -1
  37. package/package.json +8 -12
  38. package/src/components/procaptchaPuzzle.ts +54 -0
  39. package/src/components/procaptchaWidget.ts +392 -0
  40. package/src/components/puzzleCanvas.ts +653 -0
  41. package/src/index.ts +3 -2
  42. package/src/tests/domHarness.ts +122 -0
  43. package/src/tests/procaptchaPuzzle.test-d.ts +33 -17
  44. package/src/tests/procaptchaPuzzle.unit.test.ts +59 -44
  45. package/src/tests/procaptchaWidget.unit.test.ts +145 -258
  46. package/src/tests/puzzleCanvas.unit.test.ts +76 -120
  47. package/tsconfig.cjs.json +1 -2
  48. package/tsconfig.json +1 -2
  49. package/tsconfig.tsbuildinfo +1 -1
  50. package/vite.test.config.ts +3 -4
  51. package/dist/cjs/components/ProcaptchaPuzzle.cjs +0 -7
  52. package/dist/cjs/components/ProcaptchaWidget.cjs +0 -206
  53. package/dist/cjs/components/PuzzleCanvas.cjs +0 -476
  54. package/dist/components/ProcaptchaPuzzle.d.ts +0 -3
  55. package/dist/components/ProcaptchaPuzzle.d.ts.map +0 -1
  56. package/dist/components/ProcaptchaPuzzle.js +0 -7
  57. package/dist/components/ProcaptchaPuzzle.js.map +0 -1
  58. package/dist/components/ProcaptchaWidget.d.ts +0 -4
  59. package/dist/components/ProcaptchaWidget.d.ts.map +0 -1
  60. package/dist/components/ProcaptchaWidget.js +0 -207
  61. package/dist/components/ProcaptchaWidget.js.map +0 -1
  62. package/dist/components/PuzzleCanvas.d.ts.map +0 -1
  63. package/dist/components/PuzzleCanvas.js +0 -476
  64. package/dist/components/PuzzleCanvas.js.map +0 -1
  65. package/dist/tests/setup.d.ts +0 -5
  66. package/dist/tests/setup.d.ts.map +0 -1
  67. package/dist/tests/setup.js +0 -3
  68. package/dist/tests/setup.js.map +0 -1
  69. package/src/components/ProcaptchaPuzzle.tsx +0 -36
  70. package/src/components/ProcaptchaWidget.tsx +0 -320
  71. package/src/components/PuzzleCanvas.tsx +0 -638
  72. package/src/tests/setup.ts +0 -26
@@ -0,0 +1,450 @@
1
+ let _prosopo_procaptcha_common = require("@prosopo/procaptcha-common");
2
+ //#region src/components/puzzleCanvas.ts
3
+ var CONTAINER_WIDTH = 300;
4
+ var CONTAINER_HEIGHT = 200;
5
+ var PIECE_CSS_CLASS = "prosopo-puzzle-piece";
6
+ var STEP_PX = 10;
7
+ var FINE_STEP_PX = 2;
8
+ var ANNOUNCE_DEBOUNCE_MS = 400;
9
+ var VISUALLY_HIDDEN = {
10
+ position: "absolute",
11
+ width: "1px",
12
+ height: "1px",
13
+ padding: 0,
14
+ margin: "-1px",
15
+ overflow: "hidden",
16
+ clip: "rect(0, 0, 0, 0)",
17
+ clipPath: "inset(50%)",
18
+ whiteSpace: "nowrap",
19
+ border: 0
20
+ };
21
+ var stylesheet = (focusRingColor) => `
22
+ @keyframes prosopo-puzzle-shake {
23
+ 0%, 100% { transform: translateX(0); }
24
+ 10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }
25
+ 20%, 40%, 60%, 80% { transform: translateX(4px); }
26
+ }
27
+ .${PIECE_CSS_CLASS}:focus-visible {
28
+ outline: 3px solid ${focusRingColor};
29
+ outline-offset: 2px;
30
+ }
31
+ `;
32
+ var KALEIDOSCOPE_TILES = [
33
+ [
34
+ 0,
35
+ 0,
36
+ -1,
37
+ -1
38
+ ],
39
+ [
40
+ 1,
41
+ 0,
42
+ 1,
43
+ -1
44
+ ],
45
+ [
46
+ 2,
47
+ 0,
48
+ -1,
49
+ -1
50
+ ],
51
+ [
52
+ 0,
53
+ 1,
54
+ -1,
55
+ 1
56
+ ],
57
+ [
58
+ 1,
59
+ 1,
60
+ 1,
61
+ 1
62
+ ],
63
+ [
64
+ 2,
65
+ 1,
66
+ -1,
67
+ 1
68
+ ],
69
+ [
70
+ 0,
71
+ 2,
72
+ -1,
73
+ -1
74
+ ],
75
+ [
76
+ 1,
77
+ 2,
78
+ 1,
79
+ -1
80
+ ],
81
+ [
82
+ 2,
83
+ 2,
84
+ -1,
85
+ -1
86
+ ]
87
+ ];
88
+ var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
89
+ var instanceCount = 0;
90
+ var mountPuzzleCanvas = (initialProps) => {
91
+ const teardown = new _prosopo_procaptcha_common.Teardown();
92
+ let props = initialProps;
93
+ let posX = props.originX;
94
+ let posY = props.originY;
95
+ let dragging = false;
96
+ let puzzleEvents = [];
97
+ let dragOffset = {
98
+ x: 0,
99
+ y: 0
100
+ };
101
+ let visible = false;
102
+ let shaking = false;
103
+ let shakeTimer;
104
+ let announceTimer;
105
+ let keyboardDragging = false;
106
+ const baseId = `prosopo-puzzle-${instanceCount++}`;
107
+ const instructionId = `${baseId}-instruction`;
108
+ const keyboardHintId = `${baseId}-keyboard-hint`;
109
+ const t = (key, options) => props.translator.t(key, options);
110
+ const style = (0, _prosopo_procaptcha_common.createElement)("style", { text: stylesheet(props.theme.palette.primary.main) });
111
+ const announcer = (0, _prosopo_procaptcha_common.createElement)("output", {
112
+ style: VISUALLY_HIDDEN,
113
+ attributes: {
114
+ "aria-live": "polite",
115
+ "aria-atomic": "true"
116
+ }
117
+ });
118
+ const keyboardHint = (0, _prosopo_procaptcha_common.createElement)("div", {
119
+ style: VISUALLY_HIDDEN,
120
+ attributes: { id: keyboardHintId }
121
+ });
122
+ const backgroundTiles = KALEIDOSCOPE_TILES.map(([column, row, sx, sy]) => (0, _prosopo_procaptcha_common.createElement)("img", {
123
+ style: {
124
+ position: "absolute",
125
+ left: `${column * CONTAINER_WIDTH}px`,
126
+ top: `${row * CONTAINER_HEIGHT}px`,
127
+ width: `${CONTAINER_WIDTH}px`,
128
+ height: `${CONTAINER_HEIGHT}px`,
129
+ transform: `scale(${sx}, ${sy})`,
130
+ pointerEvents: "none",
131
+ userSelect: "none"
132
+ },
133
+ attributes: {
134
+ alt: "",
135
+ draggable: false
136
+ }
137
+ }));
138
+ const backgroundLayer = (0, _prosopo_procaptcha_common.createElement)("div", {
139
+ style: {
140
+ left: `-${CONTAINER_WIDTH}px`,
141
+ top: `-${CONTAINER_HEIGHT}px`,
142
+ position: "absolute",
143
+ width: `${CONTAINER_WIDTH * 3}px`,
144
+ height: `${CONTAINER_HEIGHT * 3}px`,
145
+ pointerEvents: "none",
146
+ userSelect: "none",
147
+ transformOrigin: "center center",
148
+ willChange: "transform, filter"
149
+ },
150
+ children: backgroundTiles
151
+ });
152
+ const piece = (0, _prosopo_procaptcha_common.createElement)("div", {
153
+ className: PIECE_CSS_CLASS,
154
+ style: {
155
+ position: "absolute",
156
+ backgroundSize: "100% 100%",
157
+ touchAction: "none"
158
+ },
159
+ attributes: {
160
+ role: "application",
161
+ "aria-describedby": `${instructionId} ${keyboardHintId}`
162
+ }
163
+ });
164
+ if ("production" !== process.env.NODE_ENV) (0, _prosopo_procaptcha_common.applyAttributes)(piece, { "data-cy": "prosopo-puzzle-piece" });
165
+ const area = (0, _prosopo_procaptcha_common.createElement)("div", {
166
+ style: {
167
+ position: "relative",
168
+ width: `${CONTAINER_WIDTH}px`,
169
+ height: `${CONTAINER_HEIGHT}px`,
170
+ borderRadius: "0 0 20px 20px",
171
+ overflow: "hidden",
172
+ userSelect: "none",
173
+ transition: "opacity 0.2s ease"
174
+ },
175
+ children: [backgroundLayer, piece]
176
+ });
177
+ const instruction = (0, _prosopo_procaptcha_common.createElement)("div", {
178
+ attributes: { id: instructionId },
179
+ style: {
180
+ borderRadius: "20px 20px 0 0",
181
+ padding: "12px 20px",
182
+ width: `${CONTAINER_WIDTH}px`,
183
+ boxSizing: "border-box",
184
+ textAlign: "center",
185
+ fontSize: "14px",
186
+ fontWeight: 500,
187
+ transition: "color 0.3s ease, border-color 0.3s ease"
188
+ }
189
+ });
190
+ const panel = (0, _prosopo_procaptcha_common.createElement)("div", {
191
+ style: {
192
+ display: "flex",
193
+ flexDirection: "column",
194
+ alignItems: "center",
195
+ gap: "0",
196
+ transition: "opacity 0.3s ease, transform 0.3s ease"
197
+ },
198
+ children: [instruction, area]
199
+ });
200
+ const surfaceProps = () => ({
201
+ show: true,
202
+ placement: props.placement,
203
+ anchor: props.anchor,
204
+ onDismiss: props.onDismiss,
205
+ scrim: visible ? "dim" : "none",
206
+ dialogLabel: t("WIDGET.PUZZLE.DIALOG_LABEL", { defaultValue: "Puzzle challenge" })
207
+ });
208
+ const surface = (0, _prosopo_procaptcha_common.mountChallengeSurface)(surfaceProps());
209
+ surface.content.append(style, announcer, keyboardHint, panel);
210
+ const announce = (message, delayMs = 0) => {
211
+ if (void 0 !== announceTimer) {
212
+ clearTimeout(announceTimer);
213
+ announceTimer = void 0;
214
+ }
215
+ if (0 === delayMs) {
216
+ announcer.textContent = message;
217
+ return;
218
+ }
219
+ announceTimer = setTimeout(() => {
220
+ announcer.textContent = message;
221
+ }, delayMs);
222
+ };
223
+ const describePosition = (x, y) => t("WIDGET.PUZZLE.POSITION", {
224
+ defaultValue: "{{x}} percent across, {{y}} percent down",
225
+ x: Math.round(x / CONTAINER_WIDTH * 100),
226
+ y: Math.round(y / CONTAINER_HEIGHT * 100)
227
+ });
228
+ const applyPiecePosition = () => {
229
+ (0, _prosopo_procaptcha_common.applyStyles)(piece, {
230
+ left: `${posX - props.pieceSize / 2}px`,
231
+ top: `${posY - props.pieceSize / 2}px`
232
+ });
233
+ };
234
+ const applyPieceChrome = () => {
235
+ (0, _prosopo_procaptcha_common.applyStyles)(piece, {
236
+ width: `${props.pieceSize}px`,
237
+ height: `${props.pieceSize}px`,
238
+ backgroundImage: `url(${props.piece})`,
239
+ cursor: props.submitting ? "default" : dragging ? "grabbing" : "grab",
240
+ filter: dragging ? "drop-shadow(0 4px 10px rgba(0, 0, 0, 0.45))" : "drop-shadow(0 2px 5px rgba(0, 0, 0, 0.35))",
241
+ transition: dragging ? "none" : "filter 0.2s ease, left 0.3s ease, top 0.3s ease"
242
+ });
243
+ };
244
+ const PARALLAX_FACTOR = .08;
245
+ const applyBackgroundMotion = () => {
246
+ const deltaX = posX - props.originX;
247
+ const deltaY = posY - props.originY;
248
+ const dragDistance = Math.hypot(deltaX, deltaY);
249
+ const translateX = dragging ? -deltaX * PARALLAX_FACTOR : 0;
250
+ const translateY = dragging ? -deltaY * PARALLAX_FACTOR : 0;
251
+ const scale = dragging ? 1.03 : 1;
252
+ const hueShift = dragging ? clamp(deltaX * .12, -18, 18) : 0;
253
+ const satBoost = dragging ? 1 + Math.min(.25, dragDistance * .0035) : 1;
254
+ const brightness = dragging ? 1 - Math.min(.06, dragDistance * 8e-4) : 1;
255
+ (0, _prosopo_procaptcha_common.applyStyles)(backgroundLayer, {
256
+ transform: `translate(${translateX.toFixed(2)}px, ${translateY.toFixed(2)}px) scale(${scale.toFixed(3)})`,
257
+ filter: `hue-rotate(${hueShift.toFixed(2)}deg) saturate(${satBoost.toFixed(3)}) brightness(${brightness.toFixed(3)})`,
258
+ transition: dragging ? "none" : "transform 0.35s cubic-bezier(0.22, 1, 0.36, 1), filter 0.35s ease"
259
+ });
260
+ };
261
+ const render = () => {
262
+ const { theme } = props;
263
+ (0, _prosopo_procaptcha_common.applyStyles)(panel, {
264
+ opacity: visible ? 1 : 0,
265
+ transform: visible ? "scale(1)" : "scale(0.9)",
266
+ animation: shaking ? "prosopo-puzzle-shake 0.5s ease" : "none"
267
+ });
268
+ instruction.textContent = props.showRetry ? t("WIDGET.PUZZLE.RETRY", { defaultValue: "Not quite — try again" }) : t("WIDGET.PUZZLE.DRAG", { defaultValue: "Drag the piece to the target" });
269
+ keyboardHint.textContent = t("WIDGET.PUZZLE.KEYBOARD_HINT", { defaultValue: "Use the arrow keys to move the piece, holding shift for smaller steps. Press Enter to submit it, Home to put it back at the start, or Escape to cancel." });
270
+ (0, _prosopo_procaptcha_common.applyStyles)(instruction, {
271
+ backgroundColor: theme.palette.surface,
272
+ fontFamily: theme.font.fontFamily,
273
+ color: props.showRetry ? theme.palette.error.main : theme.palette.onSurface,
274
+ borderBottom: `2px solid ${props.showRetry ? theme.palette.error.main : "transparent"}`
275
+ });
276
+ (0, _prosopo_procaptcha_common.applyStyles)(area, {
277
+ background: `linear-gradient(135deg, ${theme.palette.surface} 0%, ${theme.palette.primaryContainer.main} 50%, ${theme.palette.surface} 100%)`,
278
+ opacity: props.submitting ? .6 : 1,
279
+ pointerEvents: props.submitting ? "none" : "auto"
280
+ });
281
+ for (const tile of backgroundTiles) tile.src = props.background;
282
+ (0, _prosopo_procaptcha_common.applyAttributes)(piece, {
283
+ tabindex: props.submitting ? -1 : 0,
284
+ "aria-roledescription": t("WIDGET.PUZZLE.PIECE_ROLE", { defaultValue: "draggable puzzle piece" }),
285
+ "aria-label": t("WIDGET.PUZZLE.PIECE_LABEL", { defaultValue: "Puzzle piece" })
286
+ });
287
+ applyPiecePosition();
288
+ applyPieceChrome();
289
+ applyBackgroundMotion();
290
+ surface.update(surfaceProps());
291
+ };
292
+ const containerOffset = () => {
293
+ const rect = area.getBoundingClientRect();
294
+ return {
295
+ x: rect.left,
296
+ y: rect.top
297
+ };
298
+ };
299
+ const complete = (finalX, finalY) => {
300
+ props.onComplete(finalX, finalY, [...puzzleEvents]);
301
+ };
302
+ const handleMove = (clientX, clientY) => {
303
+ if (!dragging) return;
304
+ const offset = containerOffset();
305
+ posX = clamp(clientX - offset.x - dragOffset.x, 0, CONTAINER_WIDTH);
306
+ posY = clamp(clientY - offset.y - dragOffset.y, 0, CONTAINER_HEIGHT);
307
+ applyPiecePosition();
308
+ applyBackgroundMotion();
309
+ puzzleEvents.push({
310
+ x: posX,
311
+ y: posY,
312
+ t: Date.now()
313
+ });
314
+ };
315
+ const handleEnd = () => {
316
+ if (!dragging) return;
317
+ dragging = false;
318
+ applyPieceChrome();
319
+ applyBackgroundMotion();
320
+ const lastEvent = puzzleEvents[puzzleEvents.length - 1];
321
+ complete(lastEvent ? lastEvent.x : props.originX, lastEvent ? lastEvent.y : props.originY);
322
+ };
323
+ const beginDrag = (clientX, clientY) => {
324
+ if (props.submitting) return;
325
+ dragging = true;
326
+ keyboardDragging = false;
327
+ puzzleEvents = [];
328
+ const offset = containerOffset();
329
+ dragOffset = {
330
+ x: clientX - offset.x - posX,
331
+ y: clientY - offset.y - posY
332
+ };
333
+ applyPieceChrome();
334
+ applyBackgroundMotion();
335
+ };
336
+ const moveByKeyboard = (deltaX, deltaY) => {
337
+ if (!keyboardDragging) {
338
+ keyboardDragging = true;
339
+ puzzleEvents = [];
340
+ }
341
+ posX = clamp(posX + deltaX, 0, CONTAINER_WIDTH);
342
+ posY = clamp(posY + deltaY, 0, CONTAINER_HEIGHT);
343
+ applyPiecePosition();
344
+ puzzleEvents.push({
345
+ x: posX,
346
+ y: posY,
347
+ t: Date.now()
348
+ });
349
+ announce(describePosition(posX, posY), ANNOUNCE_DEBOUNCE_MS);
350
+ };
351
+ const keyboardMove = (key, step) => {
352
+ switch (key) {
353
+ case "ArrowLeft": return [-step, 0];
354
+ case "ArrowRight": return [step, 0];
355
+ case "ArrowUp": return [0, -step];
356
+ case "ArrowDown": return [0, step];
357
+ case "Home": return [props.originX - posX, props.originY - posY];
358
+ default: return;
359
+ }
360
+ };
361
+ teardown.addEventListener(piece, "keydown", (event) => {
362
+ if (props.submitting || !(0, _prosopo_procaptcha_common.isEventTrusted)(event)) return;
363
+ const keyboardEvent = event;
364
+ const step = keyboardEvent.shiftKey ? FINE_STEP_PX : STEP_PX;
365
+ const move = keyboardMove(keyboardEvent.key, step);
366
+ if (move) {
367
+ keyboardEvent.preventDefault();
368
+ moveByKeyboard(move[0], move[1]);
369
+ return;
370
+ }
371
+ if ("Enter" === keyboardEvent.key || " " === keyboardEvent.key) {
372
+ keyboardEvent.preventDefault();
373
+ keyboardDragging = false;
374
+ complete(posX, posY);
375
+ }
376
+ });
377
+ teardown.addEventListener(piece, "focus", () => {
378
+ announce(describePosition(posX, posY));
379
+ });
380
+ teardown.addEventListener(piece, "mousedown", (event) => {
381
+ const mouseEvent = event;
382
+ beginDrag(mouseEvent.clientX, mouseEvent.clientY);
383
+ });
384
+ teardown.addEventListener(piece, "touchstart", (event) => {
385
+ const touch = event.touches[0];
386
+ if (touch) beginDrag(touch.clientX, touch.clientY);
387
+ });
388
+ teardown.addEventListener(document, "mousemove", (event) => {
389
+ const mouseEvent = event;
390
+ handleMove(mouseEvent.clientX, mouseEvent.clientY);
391
+ });
392
+ teardown.addEventListener(document, "mouseup", handleEnd);
393
+ teardown.addEventListener(document, "touchmove", (event) => {
394
+ const touch = event.touches[0];
395
+ if (touch) handleMove(touch.clientX, touch.clientY);
396
+ });
397
+ teardown.addEventListener(document, "touchend", handleEnd);
398
+ render();
399
+ const frame = requestAnimationFrame(() => {
400
+ visible = true;
401
+ render();
402
+ });
403
+ teardown.add(() => cancelAnimationFrame(frame));
404
+ const startShake = () => {
405
+ shaking = true;
406
+ render();
407
+ if (void 0 !== shakeTimer) clearTimeout(shakeTimer);
408
+ shakeTimer = setTimeout(() => {
409
+ shaking = false;
410
+ render();
411
+ }, 500);
412
+ };
413
+ teardown.add(() => {
414
+ if (void 0 !== shakeTimer) clearTimeout(shakeTimer);
415
+ if (void 0 !== announceTimer) clearTimeout(announceTimer);
416
+ });
417
+ const announceSubmitting = () => {
418
+ announce(t("WIDGET.PUZZLE.CHECKING", { defaultValue: "Checking your answer" }));
419
+ };
420
+ const announceRetry = () => {
421
+ announce(t("WIDGET.PUZZLE.RETRY_ANNOUNCEMENT", { defaultValue: "Not quite. A new puzzle has loaded and the piece is back at the start." }));
422
+ };
423
+ if (props.submitting) announceSubmitting();
424
+ else if (props.showRetry) announceRetry();
425
+ if (props.showRetry) startShake();
426
+ return {
427
+ update: (nextProps) => {
428
+ const previous = props;
429
+ props = nextProps;
430
+ if (nextProps.originX !== previous.originX || nextProps.originY !== previous.originY) {
431
+ posX = nextProps.originX;
432
+ posY = nextProps.originY;
433
+ keyboardDragging = false;
434
+ }
435
+ if (nextProps.submitting && !previous.submitting) announceSubmitting();
436
+ if (nextProps.showRetry && !previous.showRetry) announceRetry();
437
+ if (nextProps.showRetry && !previous.showRetry) {
438
+ startShake();
439
+ return;
440
+ }
441
+ render();
442
+ },
443
+ destroy: () => {
444
+ teardown.run();
445
+ surface.destroy();
446
+ }
447
+ };
448
+ };
449
+ //#endregion
450
+ exports.mountPuzzleCanvas = mountPuzzleCanvas;
@@ -1,3 +1,8 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_ProcaptchaPuzzle = require("./components/ProcaptchaPuzzle.cjs");
3
- exports.ProcaptchaPuzzle = require_ProcaptchaPuzzle.ProcaptchaPuzzle;
2
+ const require_puzzleCanvas = require("./components/puzzleCanvas.cjs");
3
+ const require_procaptchaWidget = require("./components/procaptchaWidget.cjs");
4
+ const require_procaptchaPuzzle = require("./components/procaptchaPuzzle.cjs");
5
+ exports.loadProcaptchaPuzzle = require_procaptchaPuzzle.loadProcaptchaPuzzle;
6
+ exports.mountProcaptchaPuzzle = require_procaptchaPuzzle.mountProcaptchaPuzzle;
7
+ exports.mountProcaptchaPuzzleWidget = require_procaptchaWidget.default;
8
+ exports.mountPuzzleCanvas = require_puzzleCanvas.mountPuzzleCanvas;
@@ -0,0 +1,7 @@
1
+ import type { ProcaptchaProps } from "@prosopo/types";
2
+ import type { ProcaptchaPuzzleHandle } from "./procaptchaWidget.js";
3
+ export type { ProcaptchaPuzzleHandle };
4
+ export type ProcaptchaPuzzleMountFn = (container: HTMLElement, props: ProcaptchaProps) => ProcaptchaPuzzleHandle;
5
+ export declare const loadProcaptchaPuzzle: () => Promise<ProcaptchaPuzzleMountFn>;
6
+ export declare const mountProcaptchaPuzzle: (container: HTMLElement, props: ProcaptchaProps) => ProcaptchaPuzzleHandle;
7
+ //# sourceMappingURL=procaptchaPuzzle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"procaptchaPuzzle.d.ts","sourceRoot":"","sources":["../../src/components/procaptchaPuzzle.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAEpE,YAAY,EAAE,sBAAsB,EAAE,CAAC;AAEvC,MAAM,MAAM,uBAAuB,GAAG,CACrC,SAAS,EAAE,WAAW,EACtB,KAAK,EAAE,eAAe,KAClB,sBAAsB,CAAC;AAM5B,eAAO,MAAM,oBAAoB,QACtB,OAAO,CAAC,uBAAuB,CAC2B,CAAC;AAEtE,eAAO,MAAM,qBAAqB,cACtB,WAAW,SACf,eAAe,KACpB,sBAkBF,CAAC"}
@@ -0,0 +1,21 @@
1
+ //#region src/components/procaptchaPuzzle.ts
2
+ /**
3
+ * Dynamic import so the puzzle widget lands in its own chunk, replacing the
4
+ * `lazy()` + `<Suspense>` pair that used to provide the split.
5
+ */
6
+ var loadProcaptchaPuzzle = async () => (await import("./procaptchaWidget.js")).mountProcaptchaPuzzleWidget;
7
+ var mountProcaptchaPuzzle = (container, props) => {
8
+ let destroyed = false;
9
+ let inner;
10
+ loadProcaptchaPuzzle().then((mount) => {
11
+ if (destroyed) return;
12
+ inner = mount(container, props);
13
+ });
14
+ return { destroy: () => {
15
+ destroyed = true;
16
+ inner?.destroy();
17
+ inner = void 0;
18
+ } };
19
+ };
20
+ //#endregion
21
+ export { loadProcaptchaPuzzle, mountProcaptchaPuzzle };
@@ -0,0 +1 @@
1
+ {"version":3,"file":"procaptchaPuzzle.js","sourceRoot":"","sources":["../../src/components/procaptchaPuzzle.ts"],"names":[],"mappings":"AA4BA,MAAM,CAAC,MAAM,oBAAoB,GAChC,KAAK,IAAsC,EAAE,CAC5C,CAAC,MAAM,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC,2BAA2B,CAAC;AAEtE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CACpC,SAAsB,EACtB,KAAsB,EACG,EAAE;IAC3B,IAAI,SAAS,GAAG,KAAK,CAAC;IACtB,IAAI,KAAyC,CAAC;IAE9C,KAAK,oBAAoB,EAAE,CAAC,IAAI,CAAC,CAAC,KAA8B,EAAE,EAAE;QACnE,IAAI,SAAS,EAAE,CAAC;YACf,OAAO;QACR,CAAC;QACD,KAAK,GAAG,KAAK,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,OAAO;QACN,OAAO,EAAE,GAAG,EAAE;YACb,SAAS,GAAG,IAAI,CAAC;YACjB,KAAK,EAAE,OAAO,EAAE,CAAC;YACjB,KAAK,GAAG,SAAS,CAAC;QACnB,CAAC;KACD,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { type ProcaptchaProps } from "@prosopo/types";
2
+ export interface ProcaptchaPuzzleHandle {
3
+ destroy(): void;
4
+ }
5
+ export declare const mountProcaptchaPuzzleWidget: (container: HTMLElement, props: ProcaptchaProps) => ProcaptchaPuzzleHandle;
6
+ export default mountProcaptchaPuzzleWidget;
7
+ //# sourceMappingURL=procaptchaWidget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"procaptchaWidget.d.ts","sourceRoot":"","sources":["../../src/components/procaptchaWidget.ts"],"names":[],"mappings":"AA6BA,OAAO,EAGN,KAAK,eAAe,EAGpB,MAAM,gBAAgB,CAAC;AAUxB,MAAM,WAAW,sBAAsB;IACtC,OAAO,IAAI,IAAI,CAAC;CAChB;AAED,eAAO,MAAM,2BAA2B,cAC5B,WAAW,SACf,eAAe,KACpB,sBAiVF,CAAC;AAEF,eAAe,2BAA2B,CAAC"}