Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Typescript support added #11

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ jobs:

- name: Build
run: npm run build

8,561 changes: 4,274 additions & 4,287 deletions demo/package-lock.json

Large diffs are not rendered by default.

1,918 changes: 1,380 additions & 538 deletions package-lock.json

Large diffs are not rendered by default.

15 changes: 10 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "react-use-focus-trap",
"version": "1.0.1",
"version": "1.0.3",
"description": "A react hook to trap the focus within a reference",
"keywords": [
"react",
Expand All @@ -14,8 +14,8 @@
"main": "dist/useFocusTrap.js",
"type": "module",
"scripts": {
"test": "mocha -r jsdom-global/register",
"build": "esbuild src/*.js --minify --sourcemap --target=es2016 --outdir=dist",
"test": "ts-mocha -p test/tsconfig.json test/**/*.test.ts",
"build": "tsc --project tsconfig.json",
"run:demo": "npm install && npm run build && npm link && cd demo && npm install && npm start"
},
"repository": {
Expand All @@ -32,10 +32,15 @@
"react": "^17.0.0"
},
"devDependencies": {
"esbuild": "^0.14.5",
"@types/expect": "^24.3.0",
"@types/mocha": "^9.1.0",
"@types/react": "^17.0.39",
"jsdom": "^19.0.0",
"jsdom-global": "^3.0.2",
"mocha": "^9.1.3",
"react": "^17.0.2"
"react": "^17.0.2",
"ts-mocha": "^9.0.2",
"ts-node": "^10.7.0",
"typescript": "^4.6.2"
}
}
23 changes: 13 additions & 10 deletions src/useFocusTrap.js → src/useFocusTrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,28 @@ const focusableElementsSelector =
const TAB_KEY = 9;

export function useFocusTrap() {
const trapRef = useRef(null);
const trapRef = useRef<HTMLElement>(null);

const selectNextFocusableElem = useCallback(
(
sortedFocusableElems,
currentIndex,
sortedFocusableElems: HTMLElement[],
currentIndex?: number,
shiftKeyPressed = false,
skipCount = 0
) => {
): void => {
if (skipCount > sortedFocusableElems.length) {
// this means that it ran through all of elements but non was properly focusable
// hence we stop it to avoid running in an infinite loop
return false;
return;
}

const backwards = !!shiftKeyPressed;
const maxIndex = sortedFocusableElems.length - 1;

if (!currentIndex) {
const activeElement: HTMLElement = document.activeElement as HTMLElement; // can be null, which is okay
currentIndex =
sortedFocusableElems.indexOf(document.activeElement) ?? 0;
sortedFocusableElems.indexOf(activeElement) ?? 0;
}

let nextIndex = backwards ? currentIndex - 1 : currentIndex + 1;
Expand All @@ -51,19 +52,21 @@ export function useFocusTrap() {
skipCount + 1
);
}
}
}, []
);

// defining the trap function first
const trapper = useCallback((evt) => {
const trapper = useCallback((evt: KeyboardEvent) => {
const trapRefElem = trapRef.current;

if (trapRefElem !== null) {
if (evt.which === TAB_KEY || evt.key === "Tab") {
evt.preventDefault();

const shiftKeyPressed = !!evt.shiftKey;
let focusableElems = Array.from(
let focusableElems = (Array.from(
trapRefElem.querySelectorAll(focusableElementsSelector)
).filter(
) as Array<HTMLElement>).filter(
(focusableElement) => getTabIndexOfNode(focusableElement) >= 0
); // caching this is NOT a good idea in dynamic applications - so don't!
// now we need to sort it by tabIndex, highest first
Expand Down
10 changes: 5 additions & 5 deletions src/util.js → src/util.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
export function convertToIntOrFallback(stringToConvert) {
export function convertToIntOrFallback(stringToConvert: string) {
const parsed = parseInt(stringToConvert);
return parsed ? parsed : 0;
}

export function sortByTabIndex(firstNode, secondNode) {
export function sortByTabIndex(firstNode: HTMLElement, secondNode: HTMLElement) {
const tabIndexes = [firstNode, secondNode].map((node) =>
getTabIndexOfNode(node)
);
Expand All @@ -25,7 +25,7 @@ export function sortByTabIndex(firstNode, secondNode) {
* @returns Tha sanitized tab index
* @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/tabindex} for further information on the tabindex and its order
*/
function sanitizeTabIndexInput(tabIndex, highestPositiveTabIndex) {
function sanitizeTabIndexInput(tabIndex: number, highestPositiveTabIndex: number) {
if (tabIndex < 0) {
throw new Error(
`Unable to sort given input. A negative value is not part of the tab order: ${tabIndex}`
Expand All @@ -35,6 +35,6 @@ function sanitizeTabIndexInput(tabIndex, highestPositiveTabIndex) {
return tabIndex === 0 ? highestPositiveTabIndex + 1 : tabIndex;
}

export function getTabIndexOfNode(targetNode) {
return convertToIntOrFallback(targetNode.getAttribute("tabindex"));
export function getTabIndexOfNode(targetNode: HTMLElement) {
return convertToIntOrFallback(targetNode.getAttribute("tabindex") || '');
}
6 changes: 6 additions & 0 deletions test/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"module": "commonjs"
}
}
2 changes: 1 addition & 1 deletion test/util.test.js → test/util.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
convertToIntOrFallback,
getTabIndexOfNode,
sortByTabIndex,
} from "../src/util.js";
} from "../src/util";
import assert from "assert";
import { JSDOM } from "jsdom";

Expand Down
20 changes: 20 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"compilerOptions": {
"sourceMap": true,
"module": "es2020",
"target": "es2017",
"moduleResolution": "node",
"outDir": "./dist",
"jsx": "react",
"skipLibCheck": true,
"declaration": true,
"declarationMap": true,
"esModuleInterop": true,
"lib": ["dom", "dom.iterable", "esnext"],
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/"]
}