@jobber/hooks 1.12.5 → 1.13.1-pre.19

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 CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [1.13.0](https://github.com/GetJobber/atlantis/compare/@jobber/hooks@1.12.5...@jobber/hooks@1.13.0) (2023-03-02)
7
+
8
+
9
+ ### Features
10
+
11
+ * **hooks:** Add useFocusTrap hook ([#1100](https://github.com/GetJobber/atlantis/issues/1100)) ([2fed042](https://github.com/GetJobber/atlantis/commit/2fed042db990704e1723e1ebe87bff7b04acc44f))
12
+
13
+
14
+
15
+
16
+
6
17
  ## [1.12.5](https://github.com/GetJobber/atlantis/compare/@jobber/hooks@1.12.4...@jobber/hooks@1.12.5) (2023-02-28)
7
18
 
8
19
  **Note:** Version bump only for package @jobber/hooks
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from "./useAssert";
2
2
  export * from "./useCollectionQuery";
3
+ export * from "./useFocusTrap";
3
4
  export * from "./useFormState";
4
5
  export * from "./useIsMounted";
5
6
  export * from "./useLiveAnnounce";
package/dist/index.js CHANGED
@@ -5,6 +5,7 @@ function __export(m) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  __export(require("./useAssert"));
7
7
  __export(require("./useCollectionQuery"));
8
+ __export(require("./useFocusTrap"));
8
9
  __export(require("./useFormState"));
9
10
  __export(require("./useIsMounted"));
10
11
  __export(require("./useLiveAnnounce"));
@@ -0,0 +1 @@
1
+ export { useFocusTrap } from "./useFocusTrap";
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ var useFocusTrap_1 = require("./useFocusTrap");
4
+ exports.useFocusTrap = useFocusTrap_1.useFocusTrap;
@@ -0,0 +1,10 @@
1
+ /// <reference types="react" />
2
+ /**
3
+ * Traps the focus within the children of the ref element.
4
+ *
5
+ * @param active - Turns the focus trapping on or off. Also adds aria-hidden on the
6
+ * body but not the dialog.
7
+ *
8
+ * @returns ref
9
+ */
10
+ export declare function useFocusTrap<T extends HTMLElement>(active: boolean): import("react").RefObject<T>;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ var react_1 = require("react");
4
+ /**
5
+ * Traps the focus within the children of the ref element.
6
+ *
7
+ * @param active - Turns the focus trapping on or off. Also adds aria-hidden on the
8
+ * body but not the dialog.
9
+ *
10
+ * @returns ref
11
+ */
12
+ function useFocusTrap(active) {
13
+ // There's an ongoing issue with useRef return type clashing with an element's
14
+ // ref prop type. TLDR: Use null because useRef doesn't expect undefined.
15
+ // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/35572
16
+ var ref = react_1.useRef(null);
17
+ function handleKeyDown(event) {
18
+ if (!(active && ref.current) || event.key !== "Tab") {
19
+ return;
20
+ }
21
+ var _a = getElements(ref.current), firstElement = _a.firstElement, lastElement = _a.lastElement;
22
+ if (event.shiftKey) {
23
+ if (document.activeElement === firstElement) {
24
+ lastElement.focus();
25
+ event.preventDefault();
26
+ }
27
+ }
28
+ else {
29
+ if (document.activeElement === lastElement) {
30
+ firstElement.focus();
31
+ event.preventDefault();
32
+ }
33
+ }
34
+ }
35
+ react_1.useEffect(function () {
36
+ var _a, _b;
37
+ if (active) {
38
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.focus();
39
+ (_b = ref.current) === null || _b === void 0 ? void 0 : _b.addEventListener("keydown", handleKeyDown);
40
+ }
41
+ return function () {
42
+ var _a;
43
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.removeEventListener("keydown", handleKeyDown);
44
+ };
45
+ }, [active]);
46
+ return ref;
47
+ }
48
+ exports.useFocusTrap = useFocusTrap;
49
+ function getElements(ref) {
50
+ var focusables = [
51
+ "button",
52
+ "[href]",
53
+ "input",
54
+ "select",
55
+ "textarea",
56
+ '[tabindex]:not([tabindex="-1"])',
57
+ ];
58
+ var elements = ref.querySelectorAll(focusables.join(", "));
59
+ var firstElement = ref;
60
+ var lastElement = elements[elements.length - 1];
61
+ return { firstElement: firstElement, lastElement: lastElement };
62
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ var react_1 = __importDefault(require("react"));
7
+ var react_2 = require("@testing-library/react");
8
+ var user_event_1 = __importDefault(require("@testing-library/user-event"));
9
+ var useFocusTrap_1 = require("./useFocusTrap");
10
+ var targetId = "target";
11
+ var firstFocusableChild = "first-element";
12
+ var lastFocusableChild = "last-element";
13
+ it("should focus on the ref target on mount", function () {
14
+ var getByTestId = react_2.render(react_1.default.createElement(TestComponent, null)).getByTestId;
15
+ expect(getByTestId(targetId)).toHaveFocus();
16
+ });
17
+ it("should focus on the ref target when tabbing out of the last focusable element and ignore the tabindex'=-1'", function () {
18
+ var getByTestId = react_2.render(react_1.default.createElement(TestComponent, null)).getByTestId;
19
+ getByTestId(lastFocusableChild).focus();
20
+ user_event_1.default.tab();
21
+ expect(getByTestId(targetId)).toHaveFocus();
22
+ });
23
+ it("should focus on the first focusable element", function () {
24
+ var getByTestId = react_2.render(react_1.default.createElement(TestComponent, null)).getByTestId;
25
+ user_event_1.default.tab();
26
+ expect(getByTestId(firstFocusableChild)).toHaveFocus();
27
+ });
28
+ it("should focus on the last focusable element", function () {
29
+ var getByTestId = react_2.render(react_1.default.createElement(TestComponent, null)).getByTestId;
30
+ user_event_1.default.tab({ shift: true });
31
+ expect(getByTestId(lastFocusableChild)).toHaveFocus();
32
+ });
33
+ it("should not trap the tabbing and focus on the first child node", function () {
34
+ var getByTestId = react_2.render(react_1.default.createElement(TestComponent, { trap: false })).getByTestId;
35
+ user_event_1.default.tab();
36
+ expect(getByTestId(targetId).previousElementSibling).toHaveFocus();
37
+ });
38
+ function TestComponent(_a) {
39
+ var _b = _a.trap, trap = _b === void 0 ? true : _b;
40
+ var testRef = useFocusTrap_1.useFocusTrap(trap);
41
+ return (react_1.default.createElement(react_1.default.Fragment, null,
42
+ react_1.default.createElement("input", { type: "number" }),
43
+ react_1.default.createElement("div", { ref: testRef, "data-testid": targetId, tabIndex: 0 },
44
+ react_1.default.createElement("button", { "data-testid": firstFocusableChild }, "Click me"),
45
+ react_1.default.createElement("a", { href: "#" }),
46
+ react_1.default.createElement("input", { type: "text" }),
47
+ react_1.default.createElement("select", null,
48
+ react_1.default.createElement("option", { value: "A" })),
49
+ react_1.default.createElement("textarea", null),
50
+ react_1.default.createElement("span", { tabIndex: 0, "data-testId": lastFocusableChild }),
51
+ react_1.default.createElement("span", { tabIndex: -1 })),
52
+ react_1.default.createElement("input", { type: "calendar" })));
53
+ }
@@ -1,6 +1,4 @@
1
1
  /// <reference types="react" />
2
- /// <reference types="@emotion/core" />
3
- /// <reference types="theme-ui" />
4
2
  export declare function useFormState(): readonly [{
5
3
  isDirty: boolean;
6
4
  isValid: boolean;
@@ -1,6 +1,4 @@
1
1
  /// <reference types="react" />
2
- /// <reference types="@emotion/core" />
3
- /// <reference types="theme-ui" />
4
2
  export declare const Breakpoints: {
5
3
  base: number;
6
4
  small: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jobber/hooks",
3
- "version": "1.12.5",
3
+ "version": "1.13.1-pre.19+932bbb8b",
4
4
  "license": "MIT",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.js",
@@ -16,12 +16,13 @@
16
16
  "devDependencies": {
17
17
  "@apollo/client": "^3.3.16",
18
18
  "@apollo/react-testing": "^4.0.0",
19
- "@jobber/formatters": "^0.2.1",
20
- "@testing-library/react": "^10.2.1",
19
+ "@jobber/formatters": "^0.2.2-pre.34+932bbb8b",
20
+ "@testing-library/react": "^14.0.0",
21
21
  "@testing-library/react-hooks": "^7.0.0",
22
+ "@testing-library/user-event": "^12.0.2",
22
23
  "@types/lodash": "4.14.136",
23
- "@types/react": "16.14.2",
24
- "@types/react-dom": "16.9.10",
24
+ "@types/react": "^18.0.28",
25
+ "@types/react-dom": "^18.0.11",
25
26
  "@types/uuid": "^8.3.3",
26
27
  "@types/zxcvbn": "^4.4.1",
27
28
  "graphql": "^14.6.0",
@@ -38,7 +39,7 @@
38
39
  },
39
40
  "peerDependencies": {
40
41
  "@apollo/client": "^3.3.16",
41
- "react": "^16.8.6"
42
+ "react": ">=16.8"
42
43
  },
43
- "gitHead": "bb90f77e6a841ec59113b3a7931ff13039e7d9f5"
44
+ "gitHead": "932bbb8b9dd1cdacc858efb1f7feed546a710d11"
44
45
  }