From e622ac5e5b0a0651d65d7fde346774f4c62cf3fa Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 7 Aug 2024 20:16:55 +0300 Subject: [PATCH 01/16] jump to first element on esc -> implement --- escape.js | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++ index.js | 1 + package.json | 2 +- 3 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 escape.js diff --git a/escape.js b/escape.js new file mode 100644 index 0000000..4a320cd --- /dev/null +++ b/escape.js @@ -0,0 +1,63 @@ +export function escapeKeyUX() { + return window => { + function isVisible(element) { + return element.offsetWidth > 0 && + element.offsetHeight > 0 && + getComputedStyle(element).visibility !== 'hidden'; + } + + function isDirectlyVisible(element) { + let selectors = ':not([style*="display: none"], [style*="visibility: hidden"])' + return isVisible(element) && + isVisible(element.closest(selectors)); + } + + function updateFocusableElements() { + let selectors = 'button, a, input, select, textarea, [tabindex]:not([tabindex="-1"])' + return Array.from(document.querySelectorAll(selectors)) + .filter(isDirectlyVisible); + } + + let focusableElements = updateFocusableElements(); + let lastFocusedIndex = -1; + + const observer = new MutationObserver(_mutations => { + focusableElements = updateFocusableElements(); + }); + + observer.observe(document.body, { + childList: true, + subtree: true, + attributes: true, + attributeFilter: ['style', 'class'] + }); + + document.body.addEventListener('focus', event => { + const index = focusableElements.indexOf(event.target); + if (index !== -1) { + lastFocusedIndex = index; + } + }, true); + + function keyDown(event) { + if (event.key === 'Escape') { + document.activeElement.blur(); + lastFocusedIndex = -1; + } else if (event.key === 'Tab') { + event.preventDefault(); + if (!event.shiftKey) { + lastFocusedIndex = (lastFocusedIndex + 1) % focusableElements.length; + } else { + lastFocusedIndex = (lastFocusedIndex - 1 + focusableElements.length) % focusableElements.length; + } + focusableElements[lastFocusedIndex] && focusableElements[lastFocusedIndex].focus(); + } + } + + window.addEventListener('keydown', keyDown); + return () => { + window.removeEventListener('keydown', keyDown); + observer.disconnect(); + } + } +} diff --git a/index.js b/index.js index 0c980a2..3b26520 100644 --- a/index.js +++ b/index.js @@ -5,6 +5,7 @@ export * from './hotkey.js' export * from './jump.js' export * from './overrides.js' export * from './press.js' +export * from './escape.js' export function startKeyUX(window, plugins) { let unbinds = plugins.map(plugin => plugin(window)) diff --git a/package.json b/package.json index 3425af7..ca2ac83 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ { "name": "All modules", "import": { - "./index.js": "{ startKeyUX, hotkeyKeyUX, pressKeyUX, focusGroupKeyUX, jumpKeyUX, hiddenKeyUX, likelyWithKeyboard, getHotKeyHint, hotkeyOverrides, hotkeyMacCompat }" + "./index.js": "{ startKeyUX, hotkeyKeyUX, pressKeyUX, focusGroupKeyUX, escapeKeyUX, jumpKeyUX, hiddenKeyUX, likelyWithKeyboard, getHotKeyHint, hotkeyOverrides, hotkeyMacCompat }" }, "limit": "2120 B" } From d83116f7622dff4beb7f54992a0f70decd68797a Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 7 Aug 2024 20:26:52 +0300 Subject: [PATCH 02/16] escape module -> add to demo --- test/demo/index.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/demo/index.tsx b/test/demo/index.tsx index bfaf9a3..e3468aa 100644 --- a/test/demo/index.tsx +++ b/test/demo/index.tsx @@ -12,7 +12,8 @@ import { jumpKeyUX, likelyWithKeyboard, pressKeyUX, - startKeyUX + startKeyUX, + escapeKeyUX } from '../../index.js' let overrides: HotkeyOverride = {} @@ -21,6 +22,7 @@ let macCompatTransformer = hotkeyMacCompat() startKeyUX(window, [ hotkeyKeyUX([macCompatTransformer, overridesTransformer]), + escapeKeyUX(), focusGroupKeyUX(), pressKeyUX('is-pressed'), jumpKeyUX(), From e4f775e38b046b2b1a0649a8a106c11f9889f621 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 23 Aug 2024 19:54:40 +0300 Subject: [PATCH 03/16] restore focus state -> implement --- jump.js | 59 +++++++++++++++++++++++++++++++++++++--------------- package.json | 8 +++---- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/jump.js b/jump.js index c878cc0..75778fc 100644 --- a/jump.js +++ b/jump.js @@ -1,6 +1,7 @@ export function jumpKeyUX() { return window => { let jumps = [] + let lastFocusedElement = null function focus(next) { let current = window.document.activeElement @@ -8,27 +9,44 @@ export function jumpKeyUX() { jumps.push(new WeakRef(current)) } next.focus({ focusVisible: true }) + lastFocusedElement = null } - function back() { - let ref = jumps.pop() - if (!ref) { - window.document.activeElement.blur() - return + function jumpBack() { + let ref = jumps.pop(); + if (ref) { + let el = ref.deref(); + + if (el && el.isConnected) { + el.focus(); + return true; + } + return jumpBack(); } - let el = ref.deref() - if (el && el.isConnected) { - el.focus() - } else { - back() + return false; + } + + function blur() { + let activeElement = document.activeElement; + if (activeElement && activeElement !== document.body) { + lastFocusedElement = activeElement; } + activeElement.blur(); } - + + function jumpBackOrBlur() { + let successfullyJumped = jumpBack(); + if (!successfullyJumped) { + blur(); + } + } + let tries = 0 let finding function jump(from) { clearInterval(finding) + tries = 0 let ariaControls = from.getAttribute('aria-controls') finding = setInterval(() => { if (tries++ > 50) { @@ -53,14 +71,21 @@ export function jumpKeyUX() { }, 50) } + function restoreFocus(event) { + event.preventDefault() + lastFocusedElement.focus({ focusVisible: true }) + lastFocusedElement = null + } + function keyDown(event) { - if (event.target.getAttribute('aria-controls')) { - if (event.key === 'Enter') { - jump(event.target) - } + if (event.target.getAttribute('aria-controls') && event.key === 'Enter') { + jump(event.target) } - if (event.key === 'Escape') { - back() + + if (event.key === 'Tab' && lastFocusedElement) { + restoreFocus(event) + } else if (event.key === 'Escape') { + jumpBackOrBlur() } } diff --git a/package.json b/package.json index 3425af7..91b9df8 100644 --- a/package.json +++ b/package.json @@ -38,20 +38,20 @@ } ], "devDependencies": { - "@logux/eslint-config": "^53.2.1", - "@size-limit/preset-small-lib": "^11.1.4", + "@logux/eslint-config": "^50.0.0", + "@size-limit/preset-small-lib": "^3.0.1", "@types/jsdom": "^21.1.7", "@types/node": "^22.1.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "better-node-test": "^0.5.1", "c8": "^10.1.2", - "clean-publish": "^5.0.0", + "clean-publish": "^3.4.5", "eslint": "^9.8.0", "jsdom": "^24.1.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "size-limit": "^11.1.4", + "size-limit": "^0.14.1", "tsx": "^4.16.5", "typescript": "^5.5.4", "vite": "^5.3.5" From dd91a21dabf1c8f768fbeba7aa2ae073c5bf6fed Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 26 Aug 2024 15:02:49 +0300 Subject: [PATCH 04/16] revert dependencies back --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 91b9df8..3425af7 100644 --- a/package.json +++ b/package.json @@ -38,20 +38,20 @@ } ], "devDependencies": { - "@logux/eslint-config": "^50.0.0", - "@size-limit/preset-small-lib": "^3.0.1", + "@logux/eslint-config": "^53.2.1", + "@size-limit/preset-small-lib": "^11.1.4", "@types/jsdom": "^21.1.7", "@types/node": "^22.1.0", "@types/react": "^18.3.3", "@types/react-dom": "^18.3.0", "better-node-test": "^0.5.1", "c8": "^10.1.2", - "clean-publish": "^3.4.5", + "clean-publish": "^5.0.0", "eslint": "^9.8.0", "jsdom": "^24.1.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "size-limit": "^0.14.1", + "size-limit": "^11.1.4", "tsx": "^4.16.5", "typescript": "^5.5.4", "vite": "^5.3.5" From e8e8c74b9723b868724735779a0fa9f1a6485e46 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 23 Aug 2024 19:54:40 +0300 Subject: [PATCH 05/16] restore focus state -> implement --- jump.js | 59 +++++++++++++++++++++++++++++++++++++--------------- package.json | 18 ++++++++-------- 2 files changed, 51 insertions(+), 26 deletions(-) diff --git a/jump.js b/jump.js index c878cc0..75778fc 100644 --- a/jump.js +++ b/jump.js @@ -1,6 +1,7 @@ export function jumpKeyUX() { return window => { let jumps = [] + let lastFocusedElement = null function focus(next) { let current = window.document.activeElement @@ -8,27 +9,44 @@ export function jumpKeyUX() { jumps.push(new WeakRef(current)) } next.focus({ focusVisible: true }) + lastFocusedElement = null } - function back() { - let ref = jumps.pop() - if (!ref) { - window.document.activeElement.blur() - return + function jumpBack() { + let ref = jumps.pop(); + if (ref) { + let el = ref.deref(); + + if (el && el.isConnected) { + el.focus(); + return true; + } + return jumpBack(); } - let el = ref.deref() - if (el && el.isConnected) { - el.focus() - } else { - back() + return false; + } + + function blur() { + let activeElement = document.activeElement; + if (activeElement && activeElement !== document.body) { + lastFocusedElement = activeElement; } + activeElement.blur(); } - + + function jumpBackOrBlur() { + let successfullyJumped = jumpBack(); + if (!successfullyJumped) { + blur(); + } + } + let tries = 0 let finding function jump(from) { clearInterval(finding) + tries = 0 let ariaControls = from.getAttribute('aria-controls') finding = setInterval(() => { if (tries++ > 50) { @@ -53,14 +71,21 @@ export function jumpKeyUX() { }, 50) } + function restoreFocus(event) { + event.preventDefault() + lastFocusedElement.focus({ focusVisible: true }) + lastFocusedElement = null + } + function keyDown(event) { - if (event.target.getAttribute('aria-controls')) { - if (event.key === 'Enter') { - jump(event.target) - } + if (event.target.getAttribute('aria-controls') && event.key === 'Enter') { + jump(event.target) } - if (event.key === 'Escape') { - back() + + if (event.key === 'Tab' && lastFocusedElement) { + restoreFocus(event) + } else if (event.key === 'Escape') { + jumpBackOrBlur() } } diff --git a/package.json b/package.json index fe23749..576173f 100644 --- a/package.json +++ b/package.json @@ -38,23 +38,23 @@ } ], "devDependencies": { - "@logux/eslint-config": "^53.4.0", - "@size-limit/preset-small-lib": "^11.1.5", + "@logux/eslint-config": "^50.0.0", + "@size-limit/preset-small-lib": "^3.0.1", "@types/jsdom": "^21.1.7", "@types/node": "^22.5.5", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", "better-node-test": "^0.7.1", "c8": "^10.1.2", - "clean-publish": "^5.0.0", - "eslint": "^9.11.0", - "jsdom": "^25.0.1", + "clean-publish": "^3.4.5", + "eslint": "^9.8.0", + "jsdom": "^24.1.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "size-limit": "^11.1.5", - "tsx": "^4.19.1", - "typescript": "^5.6.2", - "vite": "^5.4.7" + "size-limit": "^0.14.1", + "tsx": "^4.16.5", + "typescript": "^5.5.4", + "vite": "^5.3.5" }, "prettier": { "arrowParens": "avoid", From 17ae44107e443424cbf35dc8500c385abb98deca Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 26 Aug 2024 15:02:49 +0300 Subject: [PATCH 06/16] revert dependencies back --- package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 576173f..0da1b0f 100644 --- a/package.json +++ b/package.json @@ -38,20 +38,20 @@ } ], "devDependencies": { - "@logux/eslint-config": "^50.0.0", - "@size-limit/preset-small-lib": "^3.0.1", + "@logux/eslint-config": "^53.2.1", + "@size-limit/preset-small-lib": "^11.1.4", "@types/jsdom": "^21.1.7", "@types/node": "^22.5.5", "@types/react": "^18.3.8", "@types/react-dom": "^18.3.0", "better-node-test": "^0.7.1", "c8": "^10.1.2", - "clean-publish": "^3.4.5", + "clean-publish": "^5.0.0", "eslint": "^9.8.0", "jsdom": "^24.1.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "size-limit": "^0.14.1", + "size-limit": "^11.1.4", "tsx": "^4.16.5", "typescript": "^5.5.4", "vite": "^5.3.5" From 5ed5888ee896bd39d8c376574ddc15949b522af9 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 30 Aug 2024 12:23:40 +0300 Subject: [PATCH 07/16] size-limit -> increase limit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0da1b0f..ebb903e 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "import": { "./index.js": "{ startKeyUX, hotkeyKeyUX, pressKeyUX, focusGroupKeyUX, escapeKeyUX, jumpKeyUX, hiddenKeyUX, likelyWithKeyboard, getHotKeyHint, hotkeyOverrides, hotkeyMacCompat }" }, - "limit": "2162 B" + "limit": "2174 B" } ], "clean-publish": { From ebf80066c44ec467f4d7217ab0849df99f61e29c Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 23 Sep 2024 14:58:38 +0300 Subject: [PATCH 08/16] [draft] trying to understand the problem --- test/jump.test.ts | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/test/jump.test.ts b/test/jump.test.ts index fa2f595..3149dc9 100644 --- a/test/jump.test.ts +++ b/test/jump.test.ts @@ -6,11 +6,15 @@ import { setTimeout } from 'node:timers/promises' import { jumpKeyUX, startKeyUX } from '../index.js' import { keyboardClick, mouseClick, press } from './utils.js' +const dom = new JSDOM(`

Hello world

`); +global.window = dom.window; +global.document = dom.window.document; + test('jumps to next area by click and back by escape', async () => { let window = new JSDOM().window startKeyUX(window, [jumpKeyUX()]) window.document.body.innerHTML = - '' + + 'Step1' + '
' + '
' + @@ -18,13 +22,22 @@ test('jumps to next area by click and back by escape', async () => { '
' + '
' - let step1 = window.document.querySelector('#step1')! + let step1 = window.document.querySelector('#step1')! let step2button = window.document.querySelector('#step2 button')! let step3label = window.document.querySelector('#step3 label')! let step4input = window.document.querySelector('#step4 input')! let step5checked = window.document.querySelector('#step5 input:last-child')! + console.log("step1:") + console.log(step1.innerHTML) + console.log("window.document.body.innerHTML:") + console.log(window.document.body.innerHTML) + step1.focus() + + console.log("step1:") + console.log(step1.innerHTML) + keyboardClick(window, step1) equal(window.document.activeElement, step1) await setTimeout(50) From d9a88278b85c53a9f1a58222d18fce9088c6b9c8 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 16 Oct 2024 17:59:25 +0300 Subject: [PATCH 09/16] tests: jump and escape -> fix --- test/jump.test.ts | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/test/jump.test.ts b/test/jump.test.ts index 3149dc9..a09d23f 100644 --- a/test/jump.test.ts +++ b/test/jump.test.ts @@ -6,15 +6,11 @@ import { setTimeout } from 'node:timers/promises' import { jumpKeyUX, startKeyUX } from '../index.js' import { keyboardClick, mouseClick, press } from './utils.js' -const dom = new JSDOM(`

Hello world

`); -global.window = dom.window; -global.document = dom.window.document; - test('jumps to next area by click and back by escape', async () => { let window = new JSDOM().window startKeyUX(window, [jumpKeyUX()]) window.document.body.innerHTML = - 'Step1' + + '' + '
' + '
' + @@ -22,23 +18,15 @@ test('jumps to next area by click and back by escape', async () => { '
' + '
' - let step1 = window.document.querySelector('#step1')! + let step1 = window.document.querySelector('#step1')! let step2button = window.document.querySelector('#step2 button')! let step3label = window.document.querySelector('#step3 label')! let step4input = window.document.querySelector('#step4 input')! let step5checked = window.document.querySelector('#step5 input:last-child')! - console.log("step1:") - console.log(step1.innerHTML) - console.log("window.document.body.innerHTML:") - console.log(window.document.body.innerHTML) - step1.focus() - - console.log("step1:") - console.log(step1.innerHTML) - keyboardClick(window, step1) + equal(window.document.activeElement, step1) await setTimeout(50) equal(window.document.activeElement, step2button) @@ -68,7 +56,8 @@ test('jumps to next area by click and back by escape', async () => { equal(window.document.activeElement, step1) press(window, 'Escape') - equal(window.document.activeElement, window.document.body) + + equal(window.document.activeElement, step1) }) test('stops event tracking', async () => { From d295b3d1bca224833613a9fdaa7a0b0b900f1553 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 16 Oct 2024 18:00:03 +0300 Subject: [PATCH 10/16] fix jump tests --- test/hotkey.test.ts | 2 ++ test/jump.test.ts | 11 ++++------- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/test/hotkey.test.ts b/test/hotkey.test.ts index 506c0f6..605da5d 100644 --- a/test/hotkey.test.ts +++ b/test/hotkey.test.ts @@ -53,7 +53,9 @@ test('adds hot keys to buttons and links', () => { }) equal(result, 1112) + console.log(result) press(window, { key: ' ', shiftKey: true }) + console.log(result) equal(result, 11112) }) diff --git a/test/jump.test.ts b/test/jump.test.ts index a09d23f..69496b0 100644 --- a/test/jump.test.ts +++ b/test/jump.test.ts @@ -7,7 +7,9 @@ import { jumpKeyUX, startKeyUX } from '../index.js' import { keyboardClick, mouseClick, press } from './utils.js' test('jumps to next area by click and back by escape', async () => { - let window = new JSDOM().window + const { window } = new JSDOM() + global.document = window.document + startKeyUX(window, [jumpKeyUX()]) window.document.body.innerHTML = '' + @@ -56,8 +58,7 @@ test('jumps to next area by click and back by escape', async () => { equal(window.document.activeElement, step1) press(window, 'Escape') - - equal(window.document.activeElement, step1) + equal(window.document.activeElement, window.document.body) }) test('stops event tracking', async () => { @@ -69,10 +70,6 @@ test('stops event tracking', async () => { let step1 = window.document.querySelector('#step1')! stop() - - keyboardClick(window, step1) - await setTimeout(50) - equal(window.document.activeElement, window.document.body) }) test('ignores mouse click', async () => { From 7d9475146544aefcd937492383b7af5940e29beb Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 21 Oct 2024 15:26:20 +0300 Subject: [PATCH 11/16] remove declined implementation --- escape.js | 63 --------------------------------------------- index.js | 1 - package.json | 2 +- test/demo/index.tsx | 4 +-- 4 files changed, 2 insertions(+), 68 deletions(-) delete mode 100644 escape.js diff --git a/escape.js b/escape.js deleted file mode 100644 index 4a320cd..0000000 --- a/escape.js +++ /dev/null @@ -1,63 +0,0 @@ -export function escapeKeyUX() { - return window => { - function isVisible(element) { - return element.offsetWidth > 0 && - element.offsetHeight > 0 && - getComputedStyle(element).visibility !== 'hidden'; - } - - function isDirectlyVisible(element) { - let selectors = ':not([style*="display: none"], [style*="visibility: hidden"])' - return isVisible(element) && - isVisible(element.closest(selectors)); - } - - function updateFocusableElements() { - let selectors = 'button, a, input, select, textarea, [tabindex]:not([tabindex="-1"])' - return Array.from(document.querySelectorAll(selectors)) - .filter(isDirectlyVisible); - } - - let focusableElements = updateFocusableElements(); - let lastFocusedIndex = -1; - - const observer = new MutationObserver(_mutations => { - focusableElements = updateFocusableElements(); - }); - - observer.observe(document.body, { - childList: true, - subtree: true, - attributes: true, - attributeFilter: ['style', 'class'] - }); - - document.body.addEventListener('focus', event => { - const index = focusableElements.indexOf(event.target); - if (index !== -1) { - lastFocusedIndex = index; - } - }, true); - - function keyDown(event) { - if (event.key === 'Escape') { - document.activeElement.blur(); - lastFocusedIndex = -1; - } else if (event.key === 'Tab') { - event.preventDefault(); - if (!event.shiftKey) { - lastFocusedIndex = (lastFocusedIndex + 1) % focusableElements.length; - } else { - lastFocusedIndex = (lastFocusedIndex - 1 + focusableElements.length) % focusableElements.length; - } - focusableElements[lastFocusedIndex] && focusableElements[lastFocusedIndex].focus(); - } - } - - window.addEventListener('keydown', keyDown); - return () => { - window.removeEventListener('keydown', keyDown); - observer.disconnect(); - } - } -} diff --git a/index.js b/index.js index 3b26520..0c980a2 100644 --- a/index.js +++ b/index.js @@ -5,7 +5,6 @@ export * from './hotkey.js' export * from './jump.js' export * from './overrides.js' export * from './press.js' -export * from './escape.js' export function startKeyUX(window, plugins) { let unbinds = plugins.map(plugin => plugin(window)) diff --git a/package.json b/package.json index ebb903e..39cae98 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ { "name": "All modules", "import": { - "./index.js": "{ startKeyUX, hotkeyKeyUX, pressKeyUX, focusGroupKeyUX, escapeKeyUX, jumpKeyUX, hiddenKeyUX, likelyWithKeyboard, getHotKeyHint, hotkeyOverrides, hotkeyMacCompat }" + "./index.js": "{ startKeyUX, hotkeyKeyUX, pressKeyUX, focusGroupKeyUX, jumpKeyUX, hiddenKeyUX, likelyWithKeyboard, getHotKeyHint, hotkeyOverrides, hotkeyMacCompat }" }, "limit": "2174 B" } diff --git a/test/demo/index.tsx b/test/demo/index.tsx index e3468aa..bfaf9a3 100644 --- a/test/demo/index.tsx +++ b/test/demo/index.tsx @@ -12,8 +12,7 @@ import { jumpKeyUX, likelyWithKeyboard, pressKeyUX, - startKeyUX, - escapeKeyUX + startKeyUX } from '../../index.js' let overrides: HotkeyOverride = {} @@ -22,7 +21,6 @@ let macCompatTransformer = hotkeyMacCompat() startKeyUX(window, [ hotkeyKeyUX([macCompatTransformer, overridesTransformer]), - escapeKeyUX(), focusGroupKeyUX(), pressKeyUX('is-pressed'), jumpKeyUX(), From a3e30e1aa875a629be97343a172ea6746dc7bf59 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 21 Oct 2024 15:28:48 +0300 Subject: [PATCH 12/16] update size-limit --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 39cae98..13e7d2a 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "import": { "./index.js": "{ startKeyUX, hotkeyKeyUX, pressKeyUX, focusGroupKeyUX, jumpKeyUX, hiddenKeyUX, likelyWithKeyboard, getHotKeyHint, hotkeyOverrides, hotkeyMacCompat }" }, - "limit": "2174 B" + "limit": "2208 B" } ], "clean-publish": { From 79967a86850fa50e91884344aad9e2ecda1e987d Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 21 Oct 2024 15:30:45 +0300 Subject: [PATCH 13/16] remove debugging lines --- test/hotkey.test.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/hotkey.test.ts b/test/hotkey.test.ts index 605da5d..506c0f6 100644 --- a/test/hotkey.test.ts +++ b/test/hotkey.test.ts @@ -53,9 +53,7 @@ test('adds hot keys to buttons and links', () => { }) equal(result, 1112) - console.log(result) press(window, { key: ' ', shiftKey: true }) - console.log(result) equal(result, 11112) }) From afe46e4ca52c3c8c189db41c3b832b8498dd43a5 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 21 Oct 2024 15:33:03 +0300 Subject: [PATCH 14/16] recover a broken test --- test/jump.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/jump.test.ts b/test/jump.test.ts index 69496b0..3e37597 100644 --- a/test/jump.test.ts +++ b/test/jump.test.ts @@ -70,6 +70,11 @@ test('stops event tracking', async () => { let step1 = window.document.querySelector('#step1')! stop() + + keyboardClick(window, step1) + await setTimeout(50) + equal(window.document.activeElement, window.document.body) + }) test('ignores mouse click', async () => { From 957b64f8814bd1cd94024d6cb3b7be7ad52fe4c7 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 21 Oct 2024 15:49:48 +0300 Subject: [PATCH 15/16] refocusing on the last focused element -> cover with tests --- test/jump.test.ts | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/test/jump.test.ts b/test/jump.test.ts index 3e37597..f82703e 100644 --- a/test/jump.test.ts +++ b/test/jump.test.ts @@ -6,8 +6,33 @@ import { setTimeout } from 'node:timers/promises' import { jumpKeyUX, startKeyUX } from '../index.js' import { keyboardClick, mouseClick, press } from './utils.js' +test('jumps to next next elemnt, blur and restore focus on the last element', async () => { + let { window } = new JSDOM() + global.document = window.document + + startKeyUX(window, [jumpKeyUX()]) + window.document.body.innerHTML = + '' + + '' + let step1 = window.document.querySelector('#step1')! + let step2 = window.document.querySelector('#step1')! + + step1.focus() + + press(window, 'Tab') + equal(window.document.activeElement, step1) + await setTimeout(50) + equal(window.document.activeElement, step2) + + press(window, 'Escape') + equal(window.document.activeElement, window.document.body) + + press(window, 'Tab') + equal(window.document.activeElement, step2) +}) + test('jumps to next area by click and back by escape', async () => { - const { window } = new JSDOM() + let { window } = new JSDOM() global.document = window.document startKeyUX(window, [jumpKeyUX()]) From e85f23b82741e422bb40d777a180b74eabba0123 Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 21 Oct 2024 16:19:39 +0300 Subject: [PATCH 16/16] update the package.json --- package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 13e7d2a..a7c2f22 100644 --- a/package.json +++ b/package.json @@ -38,8 +38,8 @@ } ], "devDependencies": { - "@logux/eslint-config": "^53.2.1", - "@size-limit/preset-small-lib": "^11.1.4", + "@logux/eslint-config": "^53.4.0", + "@size-limit/preset-small-lib": "^11.1.5", "@types/jsdom": "^21.1.7", "@types/node": "^22.5.5", "@types/react": "^18.3.8", @@ -47,14 +47,14 @@ "better-node-test": "^0.7.1", "c8": "^10.1.2", "clean-publish": "^5.0.0", - "eslint": "^9.8.0", - "jsdom": "^24.1.1", + "eslint": "^9.11.0", + "jsdom": "^25.0.1", "react": "^18.3.1", "react-dom": "^18.3.1", - "size-limit": "^11.1.4", - "tsx": "^4.16.5", - "typescript": "^5.5.4", - "vite": "^5.3.5" + "size-limit": "^11.1.5", + "tsx": "^4.19.1", + "typescript": "^5.6.2", + "vite": "^5.4.7" }, "prettier": { "arrowParens": "avoid",