@prosopo/procaptcha-common 2.13.3 → 2.14.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.
Files changed (32) hide show
  1. package/.turbo/turbo-build$colon$cjs.log +6 -6
  2. package/.turbo/turbo-build$colon$tsc.log +18 -18
  3. package/.turbo/turbo-build.log +7 -7
  4. package/CHANGELOG.md +74 -0
  5. package/dist/callbacks/defaultCallbacks.d.ts.map +1 -1
  6. package/dist/callbacks/defaultCallbacks.js +1 -4
  7. package/dist/callbacks/defaultCallbacks.js.map +1 -1
  8. package/dist/cjs/callbacks/defaultCallbacks.cjs +1 -4
  9. package/dist/cjs/elements/window.cjs +5 -2
  10. package/dist/cjs/reactComponents/ChallengeSurface.cjs +44 -1
  11. package/dist/cjs/reactComponents/Checkbox.cjs +29 -3
  12. package/dist/elements/window.d.ts +3 -1
  13. package/dist/elements/window.d.ts.map +1 -1
  14. package/dist/elements/window.js +5 -2
  15. package/dist/elements/window.js.map +1 -1
  16. package/dist/reactComponents/ChallengeSurface.d.ts +1 -0
  17. package/dist/reactComponents/ChallengeSurface.d.ts.map +1 -1
  18. package/dist/reactComponents/ChallengeSurface.js +44 -1
  19. package/dist/reactComponents/ChallengeSurface.js.map +1 -1
  20. package/dist/reactComponents/Checkbox.d.ts +1 -0
  21. package/dist/reactComponents/Checkbox.d.ts.map +1 -1
  22. package/dist/reactComponents/Checkbox.js +30 -4
  23. package/dist/reactComponents/Checkbox.js.map +1 -1
  24. package/dist/tests/challengeSurfaceRender.unit.test.js +71 -3
  25. package/dist/tests/challengeSurfaceRender.unit.test.js.map +1 -1
  26. package/package.json +9 -9
  27. package/src/callbacks/defaultCallbacks.ts +5 -7
  28. package/src/elements/window.ts +13 -4
  29. package/src/reactComponents/ChallengeSurface.tsx +74 -0
  30. package/src/reactComponents/Checkbox.tsx +51 -2
  31. package/src/tests/challengeSurfaceRender.unit.test.tsx +111 -0
  32. package/tsconfig.tsbuildinfo +1 -1
@@ -1,6 +1,6 @@
1
1
  import { isEventTrusted } from "../events/trust.js";
2
2
  import { WIDGET_CHECKBOX_SPINNER_CSS_CLASS, withAlpha } from "@prosopo/widget-skeleton";
3
- import { useMemo, useState } from "react";
3
+ import { useEffect, useMemo, useRef, useState } from "react";
4
4
  import { jsx, jsxs } from "@emotion/react/jsx-runtime";
5
5
  import { css } from "@emotion/react";
6
6
  import styled from "@emotion/styled";
@@ -35,12 +35,29 @@ var baseStyle = {
35
35
  borderWidth: "2px"
36
36
  };
37
37
  var ID_LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
38
+ /**
39
+ * Whether nothing on the page holds focus, which is where the browser leaves it
40
+ * when the focused element is removed.
41
+ */
42
+ var focusIsStranded = (element) => {
43
+ const { activeElement, body } = element.ownerDocument;
44
+ return activeElement === null || activeElement === body;
45
+ };
38
46
  var FAQ_LINK = process.env.PROSOPO_DOCS_URL ? `${new URL(`${process.env.PROSOPO_DOCS_URL}/en/basics/faq/`).href}/` : "https://docs.prosopo.io/en/basics/faq/";
39
47
  var generateRandomId = () => {
40
48
  return Array.from({ length: 8 }, () => ID_LETTERS[Math.floor(Math.random() * ID_LETTERS.length)]).join("");
41
49
  };
42
- var Checkbox = ({ theme, onChange, checked, labelText, error, loading }) => {
50
+ var Checkbox = ({ theme, onChange, checked, labelText, error, loading, loadingText = "Checking that you are human" }) => {
43
51
  const [hover, setHover] = useState(false);
52
+ const inputRef = useRef(null);
53
+ const spinnerRef = useRef(null);
54
+ const hadFocus = useRef(false);
55
+ useEffect(() => {
56
+ if (!hadFocus.current) return;
57
+ const target = loading ? spinnerRef.current : inputRef.current;
58
+ if (!target || !focusIsStranded(target)) return;
59
+ target.focus();
60
+ }, [loading]);
44
61
  const checkboxFocus = useMemo(() => css`
45
62
  &:focus-visible {
46
63
  outline: 3px solid ${theme.palette.primary.main};
@@ -102,20 +119,29 @@ var Checkbox = ({ theme, onChange, checked, labelText, error, loading }) => {
102
119
  minHeight: "58px"
103
120
  },
104
121
  children: [loading ? /* @__PURE__ */ jsx("div", {
122
+ ref: spinnerRef,
105
123
  className: WIDGET_CHECKBOX_SPINNER_CSS_CLASS,
106
- "aria-label": "Loading spinner"
124
+ role: "status",
125
+ tabIndex: -1,
126
+ "aria-label": loadingText
107
127
  }) : /* @__PURE__ */ jsx("input", {
128
+ ref: inputRef,
108
129
  name: id,
109
130
  id,
110
131
  onMouseEnter: () => setHover(true),
111
132
  onMouseLeave: () => setHover(false),
133
+ onFocus: () => {
134
+ hadFocus.current = true;
135
+ },
136
+ onBlur: () => {
137
+ hadFocus.current = false;
138
+ },
112
139
  css: [
113
140
  checkboxBefore,
114
141
  checkboxForcedColors,
115
142
  checkboxFocus
116
143
  ],
117
144
  type: "checkbox",
118
- "aria-live": "assertive",
119
145
  "aria-label": labelText,
120
146
  onKeyDown: (e) => {
121
147
  if (!isEventTrusted(e)) return;
@@ -1 +1 @@
1
- {"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../src/reactComponents/Checkbox.tsx"],"names":[],"mappings":";AAcA,OAAO,EAAE,GAAG,EAAE,MAAM,gBAAgB,CAAC;AACrC,OAAO,MAAM,MAAM,iBAAiB,CAAC;AACrC,OAAO,EAEN,iCAAiC,EACjC,SAAS,GACT,MAAM,0BAA0B,CAAC;AAClC,OAAO,EAIN,OAAO,EACP,QAAQ,GACR,MAAM,OAAO,CAAC;AACf,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAYpD,MAAM,cAAc,GAAG,GAAG,CAAA;;;;;;;EAOxB,CAAC;AAKH,MAAM,oBAAoB,GAAG,GAAG,CAAA;;;;;CAK/B,CAAC;AAKF,MAAM,aAAa,GAAG,MAAM,CAAC;AAE7B,MAAM,SAAS,GAAkB;IAChC,KAAK,EAAE,aAAa;IACpB,MAAM,EAAE,aAAa;IACrB,QAAQ,EAAE,aAAa;IACvB,SAAS,EAAE,aAAa;IACxB,GAAG,EAAE,MAAM;IACX,IAAI,EAAE,MAAM;IACZ,OAAO,EAAE,GAAG;IACZ,UAAU,EAAE,MAAM;IAClB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,GAAG;IACX,WAAW,EAAE,OAAO;IACpB,WAAW,EAAE,KAAK;CAClB,CAAC;AAEF,MAAM,UAAU,GAAG,sDAAsD,CAAC;AAE1E,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB;IAC5C,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,iBAAiB,CAAC,CAAC,IAAI,GAAG;IACtE,CAAC,CAAC,wCAAwC,CAAC;AAE5C,MAAM,gBAAgB,GAAG,GAAG,EAAE;IAC7B,OAAO,KAAK,CAAC,IAAI,CAChB,EAAE,MAAM,EAAE,CAAC,EAAE,EACb,GAAG,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAC/D,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACZ,CAAC,CAAC;AAMF,MAAM,CAAC,MAAM,QAAQ,GAAsB,CAAC,EAC3C,KAAK,EACL,QAAQ,EACR,OAAO,EACP,SAAS,EACT,KAAK,EACL,OAAO,GACQ,EAAE,EAAE;IACnB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAI1C,MAAM,aAAa,GAAG,OAAO,CAC5B,GAAG,EAAE,CAAC,GAAG,CAAA;;yBAEc,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI;;;GAGhD,EACD,CAAC,KAAK,CAAC,CACP,CAAC;IAEF,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAsB;;;WAGhD,KAAK,CAAC,OAAO,CAAC,SAAS;;;;;;iBAMjB,KAAK,CAAC,IAAI,CAAC,UAAU;;;;;;;;;;;;;;;;EAgBpC,CAAC;IAEF,MAAM,aAAa,GAAkB,OAAO,CAAC,GAAG,EAAE;QAGjD,MAAM,SAAS,GAAG,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;QAClE,MAAM,UAAU,GAAG,yGAAyG,SAAS,yEAAyE,CAAC;QAG/M,MAAM,eAAe,GAAG,OAAO;YAC9B,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI;YAC7B,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC;QAC3B,OAAO;YACN,GAAG,SAAS;YAEZ,MAAM,EAAE,MAAM;YACd,YAAY,EAAE,KAAK,CAAC,KAAK,CAAC,QAAQ;YAClC,WAAW,EAAE,OAAO;gBACnB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAC7B,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM;YAChC,eAAe,EAAE,OAAO;gBACvB,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAC7B,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO;YACxB,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM;YAC9C,gBAAgB,EAAE,WAAW;YAC7B,kBAAkB,EAAE,QAAQ;YAE5B,cAAc,EAAE,WAAW;YAC3B,SAAS,EAAE,KAAK;gBACf,CAAC,CAAC,cAAc,SAAS,CAAC,eAAe,EAAE,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE;gBACpE,CAAC,CAAC,MAAM;YACT,UAAU,EACT,0EAA0E;SAC3E,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IAC5B,MAAM,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAE9B,OAAO,CACN,gBACC,KAAK,EAAE;YACN,OAAO,EAAE,aAAa;YACtB,UAAU,EAAE,QAAQ;YACpB,SAAS,EAAE,MAAM;SACjB,aAEA,OAAO,CAAC,CAAC,CAAC,CACV,cACC,SAAS,EAAE,iCAAiC,gBACjC,iBAAiB,GAC3B,CACF,CAAC,CAAC,CAAC,CACH,gBACC,IAAI,EAAE,EAAE,EACR,EAAE,EAAE,EAAE,EACN,YAAY,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,EAClC,YAAY,EAAE,GAAG,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,EACnC,GAAG,EAAE,CAAC,cAAc,EAAE,oBAAoB,EAAE,aAAa,CAAC,EAC1D,IAAI,EAAE,UAAU,eACL,WAAW,gBACV,SAAS,EACrB,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE;oBAChB,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;wBACxB,OAAO;oBACR,CAAC;oBACD,IAAI,CAAC,CAAC,GAAG,KAAK,OAAO,EAAE,CAAC;wBACvB,CAAC,CAAC,cAAc,EAAE,CAAC;wBACnB,CAAC,CAAC,eAAe,EAAE,CAAC;wBACpB,QAAQ,CAAC,KAAK,CAAC,CAAC;wBAChB,QAAQ,CAAC,CAAC,CAAC,CAAC;oBACb,CAAC;gBACF,CAAC,EACD,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE;oBACf,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC;wBACxB,OAAO;oBACR,CAAC;oBACD,CAAC,CAAC,cAAc,EAAE,CAAC;oBACnB,CAAC,CAAC,eAAe,EAAE,CAAC;oBACpB,QAAQ,CAAC,KAAK,CAAC,CAAC;oBAChB,QAAQ,CAAC,CAAC,CAAC,CAAC;gBACb,CAAC,EACD,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,aAAa,EACpB,QAAQ,EAAE,KAAK,KAAK,SAAS,EAC7B,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC,mCAAmC,CAAC,CAAC,CAAC,EAAE,aACpD,kBAAkB,GAC1B,CACF,EACA,KAAK,CAAC,CAAC,CAAC,CACR,KAAC,eAAe,IACf,MAAM,EAAE,EAAE,EACV,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAE7C,YACC,GAAG,EAAE;wBACJ,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI;wBAC/B,UAAU,EAAE,MAAM;qBAClB,EACD,IAAI,EAAE,QAAQ,YAEb,KAAK,GACH,GACa,CAClB,CAAC,CAAC,CAAC,CACH,KAAC,eAAe,IAAC,MAAM,EAAE,EAAE,YAAG,SAAS,GAAmB,CAC1D,IACK,CACP,CAAC;AACH,CAAC,CAAC;AACF,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"Checkbox.js","sourceRoot":"","sources":["../../src/reactComponents/Checkbox.tsx"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx } from "@emotion/react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
2
  import { PlacementEnum } from "@prosopo/types";
3
3
  import { createRoot } from "react-dom/client";
4
4
  import { act } from "react-dom/test-utils";
@@ -9,9 +9,15 @@ let root;
9
9
  let anchor;
10
10
  const layer = () => document.querySelector(".prosopo-challenge-surface");
11
11
  const content = () => document.querySelector(".prosopo-challenge-content");
12
- const render = ({ placement, withAnchor = true, onDismiss, show = true, }) => {
12
+ const render = ({ placement, withAnchor = true, onDismiss, show = true, dialogLabel, focusableChildren = 0, }) => {
13
13
  act(() => {
14
- root.render(_jsx(ChallengeSurface, { show: show, placement: placement, anchor: withAnchor ? anchor : null, onDismiss: onDismiss, children: _jsx("div", { "data-testid": "challenge", children: "challenge" }) }));
14
+ root.render(_jsxs(ChallengeSurface, { show: show, placement: placement, anchor: withAnchor ? anchor : null, onDismiss: onDismiss, dialogLabel: dialogLabel, children: [_jsx("div", { "data-testid": "challenge", children: "challenge" }), Array.from({ length: focusableChildren }, (_, index) => `button-${index}`).map((id) => (_jsx("button", { type: "button", children: id }, id)))] }));
15
+ });
16
+ };
17
+ const buttons = () => Array.from(content()?.querySelectorAll("button") ?? []);
18
+ const pressTab = (shiftKey = false) => {
19
+ act(() => {
20
+ document.dispatchEvent(new KeyboardEvent("keydown", { key: "Tab", bubbles: true, shiftKey }));
15
21
  });
16
22
  };
17
23
  beforeEach(() => {
@@ -132,4 +138,66 @@ describe("dismissing with the keyboard", () => {
132
138
  expect(onDismiss).not.toHaveBeenCalled();
133
139
  });
134
140
  });
141
+ describe("as a dialog", () => {
142
+ it("stays inert for a challenge that does not name itself", () => {
143
+ render({});
144
+ expect(content()?.getAttribute("role")).toBeNull();
145
+ expect(content()?.getAttribute("aria-modal")).toBeNull();
146
+ });
147
+ it("names itself to assistive tech once a label is given", () => {
148
+ render({ dialogLabel: "Puzzle challenge" });
149
+ expect(content()?.getAttribute("role")).toBe("dialog");
150
+ expect(content()?.getAttribute("aria-modal")).toBe("true");
151
+ expect(content()?.getAttribute("aria-label")).toBe("Puzzle challenge");
152
+ });
153
+ it("takes focus so a screen reader lands on the challenge", () => {
154
+ render({ dialogLabel: "Puzzle challenge", focusableChildren: 2 });
155
+ expect(document.activeElement).toBe(buttons()[0]);
156
+ });
157
+ it("falls back to the panel when it holds nothing focusable", () => {
158
+ render({ dialogLabel: "Puzzle challenge" });
159
+ expect(document.activeElement).toBe(content());
160
+ });
161
+ it("gives focus back to whatever opened it", () => {
162
+ const opener = document.createElement("button");
163
+ document.body.appendChild(opener);
164
+ opener.focus();
165
+ render({ dialogLabel: "Puzzle challenge", focusableChildren: 1 });
166
+ expect(document.activeElement).not.toBe(opener);
167
+ act(() => root.unmount());
168
+ expect(document.activeElement).toBe(opener);
169
+ opener.remove();
170
+ root = createRoot(container);
171
+ });
172
+ it("wraps tab from the last control back to the first", () => {
173
+ render({ dialogLabel: "Puzzle challenge", focusableChildren: 2 });
174
+ const [first, last] = buttons();
175
+ last?.focus();
176
+ pressTab();
177
+ expect(document.activeElement).toBe(first);
178
+ });
179
+ it("wraps shift-tab from the first control back to the last", () => {
180
+ render({ dialogLabel: "Puzzle challenge", focusableChildren: 2 });
181
+ const [first, last] = buttons();
182
+ first?.focus();
183
+ pressTab(true);
184
+ expect(document.activeElement).toBe(last);
185
+ });
186
+ it("pulls focus back in if it has escaped to the page", () => {
187
+ const outside = document.createElement("button");
188
+ document.body.appendChild(outside);
189
+ render({ dialogLabel: "Puzzle challenge", focusableChildren: 2 });
190
+ outside.focus();
191
+ pressTab();
192
+ expect(document.activeElement).toBe(buttons()[0]);
193
+ outside.remove();
194
+ });
195
+ it("leaves tab alone for a challenge that is not a dialog", () => {
196
+ render({ focusableChildren: 2 });
197
+ const [, last] = buttons();
198
+ last?.focus();
199
+ pressTab();
200
+ expect(document.activeElement).toBe(last);
201
+ });
202
+ });
135
203
  //# sourceMappingURL=challengeSurfaceRender.unit.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"challengeSurfaceRender.unit.test.js","sourceRoot":"","sources":["../../src/tests/challengeSurfaceRender.unit.test.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"challengeSurfaceRender.unit.test.js","sourceRoot":"","sources":["../../src/tests/challengeSurfaceRender.unit.test.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prosopo/procaptcha-common",
3
- "version": "2.13.3",
3
+ "version": "2.14.1",
4
4
  "author": "PROSOPO LIMITED <info@prosopo.io>",
5
5
  "license": "Apache-2.0",
6
6
  "main": "dist/index.js",
@@ -34,19 +34,19 @@
34
34
  "dependencies": {
35
35
  "@emotion/react": "11.14.0",
36
36
  "@emotion/styled": "11.14.1",
37
- "@prosopo/account": "2.8.91",
38
- "@prosopo/load-balancer": "2.10.43",
39
- "@prosopo/types": "5.8.2",
37
+ "@prosopo/account": "2.8.93",
38
+ "@prosopo/load-balancer": "2.10.45",
39
+ "@prosopo/types": "5.8.4",
40
40
  "@prosopo/widget-skeleton": "2.8.7",
41
- "react": "19.2.8",
42
- "react-dom": "19.2.8"
41
+ "react": "19.3.0",
42
+ "react-dom": "19.3.0"
43
43
  },
44
44
  "devDependencies": {
45
- "@prosopo/config": "3.3.16",
45
+ "@prosopo/config": "3.3.17",
46
46
  "@types/jsdom": "30.0.0",
47
47
  "@types/node": "22.10.2",
48
- "@types/react": "19.2.18",
49
- "@types/react-dom": "19.2.5",
48
+ "@types/react": "19.3.0",
49
+ "@types/react-dom": "19.3.0",
50
50
  "@vitest/coverage-v8": "4.1.11",
51
51
  "concurrently": "9.0.1",
52
52
  "del-cli": "6.0.0",
@@ -58,17 +58,14 @@ export const getDefaultCallbacks = (element?: Element): Callbacks => ({
58
58
  /**
59
59
  * Set the a user callback function for an element. Data tags take precedence over renderOptions.
60
60
  */
61
- const getUserCallback = (
61
+ const getUserCallback = <Args extends unknown[]>(
62
62
  callback: string,
63
63
  element: Element,
64
- callbackFnOrName: string | ((token: string) => void) | undefined,
65
- ) => {
64
+ callbackFnOrName: string | ((...args: Args) => void) | undefined,
65
+ ): ((...args: Args) => unknown) | undefined => {
66
66
  const callbackFnName = element.getAttribute(`data-${callback}`);
67
67
  if (callbackFnName) {
68
- const callbackFn = getWindowCallback(callbackFnName);
69
- if (callbackFn) {
70
- return callbackFn;
71
- }
68
+ return getWindowCallback(callbackFnName);
72
69
  }
73
70
  if (typeof callbackFnOrName === "function") {
74
71
  return callbackFnOrName;
@@ -76,6 +73,7 @@ const getUserCallback = (
76
73
  if (typeof callbackFnOrName === "string") {
77
74
  return getWindowCallback(callbackFnOrName);
78
75
  }
76
+ return undefined;
79
77
  };
80
78
 
81
79
  export function setUserCallbacks(
@@ -12,10 +12,19 @@
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
 
15
- export const getWindowCallback = (callbackName: string) => {
16
- // biome-ignore lint/suspicious/noExplicitAny: TODO fix any
17
- const fn = (window as any)[callbackName.replace("window.", "")];
18
- if (typeof fn !== "function") {
15
+ type WindowCallback = (...args: unknown[]) => unknown;
16
+
17
+ const WINDOW_PREFIX = "window.";
18
+
19
+ const isWindowCallback = (value: unknown): value is WindowCallback =>
20
+ typeof value === "function";
21
+
22
+ export const getWindowCallback = (callbackName: string): WindowCallback => {
23
+ const name = callbackName.startsWith(WINDOW_PREFIX)
24
+ ? callbackName.slice(WINDOW_PREFIX.length)
25
+ : callbackName;
26
+ const fn: unknown = Reflect.get(window, name);
27
+ if (!isWindowCallback(fn)) {
19
28
  throw new Error(
20
29
  `Callback ${callbackName} is not defined on the window object`,
21
30
  );
@@ -43,8 +43,27 @@ interface ChallengeSurfaceProps {
43
43
  /** Called on Escape, and on an outside click when floating. */
44
44
  onDismiss?: () => void;
45
45
  className?: string;
46
+ /**
47
+ * Accessible name for the panel. Supplying one turns the panel into a modal
48
+ * dialog: it takes focus when it opens, keeps Tab inside itself while it is
49
+ * open, and hands focus back to whatever opened it on close. Challenges
50
+ * that have nothing focusable to offer leave it unset and stay inert.
51
+ */
52
+ dialogLabel?: string;
46
53
  }
47
54
 
55
+ const FOCUSABLE_SELECTOR = [
56
+ "a[href]",
57
+ "button:not([disabled])",
58
+ "input:not([disabled])",
59
+ "select:not([disabled])",
60
+ "textarea:not([disabled])",
61
+ '[tabindex]:not([tabindex="-1"])',
62
+ ].join(",");
63
+
64
+ const focusableWithin = (root: HTMLElement): HTMLElement[] =>
65
+ Array.from(root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR));
66
+
48
67
  const SURFACE_Z_INDEX = 2147483646;
49
68
  const CONTENT_Z_INDEX = 2147483647;
50
69
 
@@ -90,6 +109,7 @@ const ChallengeSurface = React.memo((props: ChallengeSurfaceProps) => {
90
109
  scrim = "none",
91
110
  onDismiss,
92
111
  className,
112
+ dialogLabel,
93
113
  } = props;
94
114
 
95
115
  const contentRef = useRef<HTMLDivElement>(null);
@@ -158,6 +178,53 @@ const ChallengeSurface = React.memo((props: ChallengeSurfaceProps) => {
158
178
  return () => document.removeEventListener("keydown", onKeyDown);
159
179
  }, [show, onDismiss]);
160
180
 
181
+ useEffect(() => {
182
+ if (!show || !dialogLabel) return;
183
+
184
+ const content = contentRef.current;
185
+ if (!content) return;
186
+
187
+ const opener =
188
+ document.activeElement instanceof HTMLElement
189
+ ? document.activeElement
190
+ : null;
191
+ // The panel itself is the fallback so the dialog's name is still
192
+ // announced when it holds nothing focusable.
193
+ (focusableWithin(content)[0] ?? content).focus();
194
+
195
+ return () => opener?.focus();
196
+ }, [show, dialogLabel]);
197
+
198
+ useEffect(() => {
199
+ if (!show || !dialogLabel) return;
200
+
201
+ // Tabbing off either end wraps back inside. A modal hides the rest of
202
+ // the page from assistive tech, so focus landing out there leaves the
203
+ // user somewhere they have no way to perceive or get back from.
204
+ const onKeyDown = (event: KeyboardEvent) => {
205
+ if (event.key !== "Tab") return;
206
+ const content = contentRef.current;
207
+ if (!content) return;
208
+
209
+ const focusable = focusableWithin(content);
210
+ const first = focusable[0] ?? content;
211
+ const last = focusable[focusable.length - 1] ?? content;
212
+ const active = document.activeElement;
213
+ const outside = !content.contains(active);
214
+
215
+ if (event.shiftKey && (outside || active === first)) {
216
+ event.preventDefault();
217
+ last.focus();
218
+ } else if (!event.shiftKey && (outside || active === last)) {
219
+ event.preventDefault();
220
+ first.focus();
221
+ }
222
+ };
223
+
224
+ document.addEventListener("keydown", onKeyDown);
225
+ return () => document.removeEventListener("keydown", onKeyDown);
226
+ }, [show, dialogLabel]);
227
+
161
228
  useEffect(() => {
162
229
  if (!show || !isFloating || !onDismiss) return;
163
230
 
@@ -244,10 +311,17 @@ const ChallengeSurface = React.memo((props: ChallengeSurfaceProps) => {
244
311
  .join(" ")}
245
312
  style={layerStyle}
246
313
  >
314
+ {/* biome-ignore lint/a11y/useSemanticElements: <dialog> brings its own
315
+ top-layer and backdrop, which would fight the portal's own
316
+ stacking and the float placement computed above. */}
247
317
  <div
248
318
  ref={contentRef}
249
319
  className="prosopo-challenge-content"
250
320
  style={contentStyle}
321
+ role={dialogLabel ? "dialog" : undefined}
322
+ aria-modal={dialogLabel ? true : undefined}
323
+ aria-label={dialogLabel}
324
+ tabIndex={dialogLabel ? -1 : undefined}
251
325
  >
252
326
  {children}
253
327
  </div>
@@ -23,7 +23,9 @@ import {
23
23
  type ButtonHTMLAttributes,
24
24
  type CSSProperties,
25
25
  type FC,
26
+ useEffect,
26
27
  useMemo,
28
+ useRef,
27
29
  useState,
28
30
  } from "react";
29
31
  import { isEventTrusted } from "../events/trust.js";
@@ -36,6 +38,8 @@ interface CheckboxProps extends ButtonHTMLAttributes<HTMLButtonElement> {
36
38
  labelText: string;
37
39
  error?: string;
38
40
  loading: boolean;
41
+ /** Name for the spinner that stands in for the box while it is working. */
42
+ loadingText?: string;
39
43
  }
40
44
 
41
45
  const checkboxBefore = css`{
@@ -79,6 +83,15 @@ const baseStyle: CSSProperties = {
79
83
 
80
84
  const ID_LETTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
81
85
 
86
+ /**
87
+ * Whether nothing on the page holds focus, which is where the browser leaves it
88
+ * when the focused element is removed.
89
+ */
90
+ const focusIsStranded = (element: HTMLElement): boolean => {
91
+ const { activeElement, body } = element.ownerDocument;
92
+ return activeElement === null || activeElement === body;
93
+ };
94
+
82
95
  const FAQ_LINK = process.env.PROSOPO_DOCS_URL
83
96
  ? `${new URL(`${process.env.PROSOPO_DOCS_URL}/en/basics/faq/`).href}/`
84
97
  : "https://docs.prosopo.io/en/basics/faq/";
@@ -101,8 +114,32 @@ export const Checkbox: FC<CheckboxProps> = ({
101
114
  labelText,
102
115
  error,
103
116
  loading,
117
+ loadingText = "Checking that you are human",
104
118
  }: CheckboxProps) => {
105
119
  const [hover, setHover] = useState(false);
120
+ const inputRef = useRef<HTMLInputElement>(null);
121
+ const spinnerRef = useRef<HTMLDivElement>(null);
122
+ // Removing a focused element drops focus to the body without firing blur,
123
+ // so this survives the swap and says whether the swap cost the user their
124
+ // place on the page.
125
+ const hadFocus = useRef(false);
126
+
127
+ // The spinner replaces the box in the DOM rather than covering it, which
128
+ // strands a keyboard user at the top of the page for as long as the check
129
+ // runs, with nothing said about why the box vanished. Handing focus across
130
+ // the swap and back keeps them where they were and gets each side's name
131
+ // read out as it arrives.
132
+ //
133
+ // Only focus the swap itself stranded is claimed back. The check lasts as
134
+ // long as the network does, and a user who spent that time moving on to the
135
+ // host page's own fields would otherwise be dragged out of them, mid
136
+ // keystroke, by a widget they had finished with.
137
+ useEffect(() => {
138
+ if (!hadFocus.current) return;
139
+ const target = loading ? spinnerRef.current : inputRef.current;
140
+ if (!target || !focusIsStranded(target)) return;
141
+ target.focus();
142
+ }, [loading]);
106
143
 
107
144
  // M3 focus indicator: a 3dp outline offset by 2dp, drawn only for keyboard
108
145
  // focus. The control previously had no focus affordance at all.
@@ -188,18 +225,30 @@ export const Checkbox: FC<CheckboxProps> = ({
188
225
  >
189
226
  {loading ? (
190
227
  <div
228
+ ref={spinnerRef}
191
229
  className={WIDGET_CHECKBOX_SPINNER_CSS_CLASS}
192
- aria-label="Loading spinner"
230
+ role="status"
231
+ // Focusable only programmatically: it stands in for the input it
232
+ // replaced, so the name below is what a screen reader reads when
233
+ // focus is handed over.
234
+ tabIndex={-1}
235
+ aria-label={loadingText}
193
236
  />
194
237
  ) : (
195
238
  <input
239
+ ref={inputRef}
196
240
  name={id}
197
241
  id={id}
198
242
  onMouseEnter={() => setHover(true)}
199
243
  onMouseLeave={() => setHover(false)}
244
+ onFocus={() => {
245
+ hadFocus.current = true;
246
+ }}
247
+ onBlur={() => {
248
+ hadFocus.current = false;
249
+ }}
200
250
  css={[checkboxBefore, checkboxForcedColors, checkboxFocus]}
201
251
  type={"checkbox"}
202
- aria-live={"assertive"}
203
252
  aria-label={labelText}
204
253
  onKeyDown={(e) => {
205
254
  if (!isEventTrusted(e)) {
@@ -35,6 +35,8 @@ interface RenderArgs {
35
35
  withAnchor?: boolean;
36
36
  onDismiss?: () => void;
37
37
  show?: boolean;
38
+ dialogLabel?: string;
39
+ focusableChildren?: number;
38
40
  }
39
41
 
40
42
  const render = ({
@@ -42,6 +44,8 @@ const render = ({
42
44
  withAnchor = true,
43
45
  onDismiss,
44
46
  show = true,
47
+ dialogLabel,
48
+ focusableChildren = 0,
45
49
  }: RenderArgs): void => {
46
50
  act(() => {
47
51
  root.render(
@@ -50,13 +54,34 @@ const render = ({
50
54
  placement={placement}
51
55
  anchor={withAnchor ? anchor : null}
52
56
  onDismiss={onDismiss}
57
+ dialogLabel={dialogLabel}
53
58
  >
54
59
  <div data-testid="challenge">challenge</div>
60
+ {Array.from(
61
+ { length: focusableChildren },
62
+ (_, index) => `button-${index}`,
63
+ ).map((id) => (
64
+ <button key={id} type="button">
65
+ {id}
66
+ </button>
67
+ ))}
55
68
  </ChallengeSurface>,
56
69
  );
57
70
  });
58
71
  };
59
72
 
73
+ /** Scoped to the panel: tests put buttons on the page around it too. */
74
+ const buttons = (): HTMLButtonElement[] =>
75
+ Array.from(content()?.querySelectorAll("button") ?? []);
76
+
77
+ const pressTab = (shiftKey = false): void => {
78
+ act(() => {
79
+ document.dispatchEvent(
80
+ new KeyboardEvent("keydown", { key: "Tab", bubbles: true, shiftKey }),
81
+ );
82
+ });
83
+ };
84
+
60
85
  beforeEach(() => {
61
86
  container = document.createElement("div");
62
87
  anchor = document.createElement("div");
@@ -228,3 +253,89 @@ describe("dismissing with the keyboard", () => {
228
253
  expect(onDismiss).not.toHaveBeenCalled();
229
254
  });
230
255
  });
256
+
257
+ describe("as a dialog", () => {
258
+ it("stays inert for a challenge that does not name itself", () => {
259
+ render({});
260
+
261
+ expect(content()?.getAttribute("role")).toBeNull();
262
+ expect(content()?.getAttribute("aria-modal")).toBeNull();
263
+ });
264
+
265
+ it("names itself to assistive tech once a label is given", () => {
266
+ render({ dialogLabel: "Puzzle challenge" });
267
+
268
+ expect(content()?.getAttribute("role")).toBe("dialog");
269
+ expect(content()?.getAttribute("aria-modal")).toBe("true");
270
+ expect(content()?.getAttribute("aria-label")).toBe("Puzzle challenge");
271
+ });
272
+
273
+ it("takes focus so a screen reader lands on the challenge", () => {
274
+ render({ dialogLabel: "Puzzle challenge", focusableChildren: 2 });
275
+
276
+ expect(document.activeElement).toBe(buttons()[0]);
277
+ });
278
+
279
+ it("falls back to the panel when it holds nothing focusable", () => {
280
+ render({ dialogLabel: "Puzzle challenge" });
281
+
282
+ expect(document.activeElement).toBe(content());
283
+ });
284
+
285
+ it("gives focus back to whatever opened it", () => {
286
+ const opener = document.createElement("button");
287
+ document.body.appendChild(opener);
288
+ opener.focus();
289
+
290
+ render({ dialogLabel: "Puzzle challenge", focusableChildren: 1 });
291
+ expect(document.activeElement).not.toBe(opener);
292
+
293
+ act(() => root.unmount());
294
+ expect(document.activeElement).toBe(opener);
295
+
296
+ opener.remove();
297
+ root = createRoot(container);
298
+ });
299
+
300
+ it("wraps tab from the last control back to the first", () => {
301
+ render({ dialogLabel: "Puzzle challenge", focusableChildren: 2 });
302
+ const [first, last] = buttons();
303
+ last?.focus();
304
+
305
+ pressTab();
306
+
307
+ expect(document.activeElement).toBe(first);
308
+ });
309
+
310
+ it("wraps shift-tab from the first control back to the last", () => {
311
+ render({ dialogLabel: "Puzzle challenge", focusableChildren: 2 });
312
+ const [first, last] = buttons();
313
+ first?.focus();
314
+
315
+ pressTab(true);
316
+
317
+ expect(document.activeElement).toBe(last);
318
+ });
319
+
320
+ it("pulls focus back in if it has escaped to the page", () => {
321
+ const outside = document.createElement("button");
322
+ document.body.appendChild(outside);
323
+ render({ dialogLabel: "Puzzle challenge", focusableChildren: 2 });
324
+ outside.focus();
325
+
326
+ pressTab();
327
+
328
+ expect(document.activeElement).toBe(buttons()[0]);
329
+ outside.remove();
330
+ });
331
+
332
+ it("leaves tab alone for a challenge that is not a dialog", () => {
333
+ render({ focusableChildren: 2 });
334
+ const [, last] = buttons();
335
+ last?.focus();
336
+
337
+ pressTab();
338
+
339
+ expect(document.activeElement).toBe(last);
340
+ });
341
+ });