From c3a9b7b37a989623a6b7b471afeb624e200fb967 Mon Sep 17 00:00:00 2001 From: Dmitriy Mezhnin <59breeder@gmail.com> Date: Tue, 29 Oct 2024 17:23:27 +0100 Subject: [PATCH 1/3] adds focusgroup attribute basic support --- focus-group.js | 14 +++++- package.json | 2 +- test/demo/index.html | 11 +++++ test/demo/index.tsx | 54 +++++++++++++++++++++ test/focus-group.test.ts | 100 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 178 insertions(+), 3 deletions(-) diff --git a/focus-group.js b/focus-group.js index 53ecdfb..e537a72 100644 --- a/focus-group.js +++ b/focus-group.js @@ -13,6 +13,9 @@ function focus(current, next) { } function findGroupNodeByEventTarget(target) { + let fg = target.closest('[focusgroup]'); + if (fg) return fg; + let itemRole = target.role || target.type || target.tagName if (!itemRole) return null @@ -26,7 +29,7 @@ function findGroupNodeByEventTarget(target) { } function getItems(target, group) { - if (group.role === 'toolbar') return getToolbarItems(group) + if (group.role === 'toolbar' || group.hasAttribute('focusgroup')) return getToolbarItems(group) return group.querySelectorAll(`[role=${target.role}]`) } @@ -37,12 +40,19 @@ function getToolbarItems(group) { item.role === 'button' || item.type === 'button' || item.role === 'checkbox' || - item.type === 'checkbox' + item.type === 'checkbox' || + item.hasAttribute('tabindex') ) }) } function isHorizontalOrientation(group) { + let fg = group.getAttribute('focusgroup') + if (fg !== null) + { + return !fg.split(' ').includes('block'); + } + let ariaOrientation = group.getAttribute('aria-orientation') if (ariaOrientation === 'vertical') return false if (ariaOrientation === 'horizontal') return true diff --git a/package.json b/package.json index 34e8f1c..a7be2b4 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": "2194 B" + "limit": "2248 B" } ], "clean-publish": { diff --git a/test/demo/index.html b/test/demo/index.html index bef977c..b13128a 100644 --- a/test/demo/index.html +++ b/test/demo/index.html @@ -124,6 +124,17 @@ border: 1px solid #aaa; padding: 1em; } + .focusgroup { + margin-top: 1em; + gap: 16px; + align-items: center; + border: 1px solid #aaa; + padding: 0.5em 1em; + background: #eee; + } + .focusgroup-item { + padding: 0.5em 1em; + } .toolbar { margin-top: 1em; display: flex; diff --git a/test/demo/index.tsx b/test/demo/index.tsx index bfaf9a3..883a575 100644 --- a/test/demo/index.tsx +++ b/test/demo/index.tsx @@ -381,6 +381,57 @@ const Toolbar: FC = () => { ) } +const FocusGroup: FC = () => { + return ( + <> +
+ Red + Yellow + Green +
+ + ) +} + +const FocusGroupInline: FC = () => { + return ( + <> +
+ Mac + Windows + Linux +
+ + ) +} + +const FocusGroupBlock: FC = () => { + return ( + <> +
+
Dog
+
Cat
+
Turtle
+
+ + ) +} + const App: FC = () => { let [, setUpdate] = useState({}) let [router, setRouter] = useState('home') @@ -399,6 +450,9 @@ const App: FC = () => { /> + + + ) } diff --git a/test/focus-group.test.ts b/test/focus-group.test.ts index 1ebd8ed..73666c1 100644 --- a/test/focus-group.test.ts +++ b/test/focus-group.test.ts @@ -456,3 +456,103 @@ test('adds toolbar widget', () => { press(window, 'ArrowRight') equal(window.document.activeElement, buttons[0]) }) + +test('adds focusgroup widget', () => { + let window = new JSDOM().window + startKeyUX(window, [focusGroupKeyUX()]) + window.document.body.innerHTML = + '
' + + 'Mac' + + 'Windows' + + 'Linux' + + '
' + let inlineElements = window.document.querySelectorAll('span') + inlineElements[0].focus() + + equal(window.document.activeElement, inlineElements[0]) + + press(window, 'ArrowRight') + equal(window.document.activeElement, inlineElements[1]) + + press(window, 'ArrowLeft') + equal(window.document.activeElement, inlineElements[0]) + + press(window, 'End') + equal(window.document.activeElement, inlineElements[2]) + + press(window, 'Home') + equal(window.document.activeElement, inlineElements[0]) + + press(window, 'ArrowLeft') + equal(window.document.activeElement, inlineElements[2]) + + press(window, 'ArrowRight') + equal(window.document.activeElement, inlineElements[0]) +}) + +test('adds focusgroup inline widget', () => { + let window = new JSDOM().window + startKeyUX(window, [focusGroupKeyUX()]) + window.document.body.innerHTML = + '
' + + 'Mac' + + 'Windows' + + 'Linux' + + '
' + let inlineElements = window.document.querySelectorAll('span') + inlineElements[0].focus() + + equal(window.document.activeElement, inlineElements[0]) + + press(window, 'ArrowRight') + equal(window.document.activeElement, inlineElements[1]) + + press(window, 'ArrowLeft') + equal(window.document.activeElement, inlineElements[0]) + + press(window, 'End') + equal(window.document.activeElement, inlineElements[2]) + + press(window, 'Home') + equal(window.document.activeElement, inlineElements[0]) + + press(window, 'ArrowLeft') + equal(window.document.activeElement, inlineElements[2]) + + press(window, 'ArrowRight') + equal(window.document.activeElement, inlineElements[0]) +}) + +test('adds focusgroup block widget', () => { + let window = new JSDOM().window + startKeyUX(window, [focusGroupKeyUX()]) + window.document.body.innerHTML = + '
' + + '
Dog
' + + '
Cat
' + + '
Turtle
' + + '
' + let blockElements = window.document.querySelectorAll('div:not([focusgroup="block"])'); + // @ts-ignore + blockElements[0].focus() + + equal(window.document.activeElement, blockElements[0]) + + press(window, 'ArrowDown') + equal(window.document.activeElement, blockElements[1]) + + press(window, 'ArrowUp') + equal(window.document.activeElement, blockElements[0]) + + press(window, 'End') + equal(window.document.activeElement, blockElements[2]) + + press(window, 'Home') + equal(window.document.activeElement, blockElements[0]) + + press(window, 'ArrowLeft') + equal(window.document.activeElement, blockElements[0]) + + press(window, 'ArrowRight') + equal(window.document.activeElement, blockElements[0]) +}) From 110bc4c5c0ea021647a499890fe36d7f7658a4cb Mon Sep 17 00:00:00 2001 From: Dmitriy Mezhnin <59breeder@gmail.com> Date: Tue, 29 Oct 2024 17:27:42 +0100 Subject: [PATCH 2/3] fixed code style --- focus-group.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/focus-group.js b/focus-group.js index e537a72..a1bf126 100644 --- a/focus-group.js +++ b/focus-group.js @@ -48,10 +48,7 @@ function getToolbarItems(group) { function isHorizontalOrientation(group) { let fg = group.getAttribute('focusgroup') - if (fg !== null) - { - return !fg.split(' ').includes('block'); - } + if (fg !== null) return !fg.split(' ').includes('block'); let ariaOrientation = group.getAttribute('aria-orientation') if (ariaOrientation === 'vertical') return false From 7f854eb7fd233a7f1873450f428ca61da2a2ab02 Mon Sep 17 00:00:00 2001 From: Dmitriy Mezhnin <59breeder@gmail.com> Date: Tue, 29 Oct 2024 19:30:57 +0100 Subject: [PATCH 3/3] ignore tabindex for items --- focus-group.js | 3 +- package.json | 2 +- test/demo/index.html | 8 +++-- test/demo/index.tsx | 18 +++++----- test/focus-group.test.ts | 72 ++++++++++++++++++++-------------------- 5 files changed, 53 insertions(+), 50 deletions(-) diff --git a/focus-group.js b/focus-group.js index a1bf126..6e34a83 100644 --- a/focus-group.js +++ b/focus-group.js @@ -40,8 +40,7 @@ function getToolbarItems(group) { item.role === 'button' || item.type === 'button' || item.role === 'checkbox' || - item.type === 'checkbox' || - item.hasAttribute('tabindex') + item.type === 'checkbox' ) }) } diff --git a/package.json b/package.json index a7be2b4..fe56595 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": "2248 B" + "limit": "2240 B" } ], "clean-publish": { diff --git a/test/demo/index.html b/test/demo/index.html index b13128a..9c31218 100644 --- a/test/demo/index.html +++ b/test/demo/index.html @@ -132,8 +132,12 @@ padding: 0.5em 1em; background: #eee; } - .focusgroup-item { - padding: 0.5em 1em; + .focusgroup button:not(:last-child) { + margin-right: 1em; + } + .focusgroup[focusgroup='block'] button { + display: block; + margin-bottom: 1em; } .toolbar { margin-top: 1em; diff --git a/test/demo/index.tsx b/test/demo/index.tsx index 883a575..582a94f 100644 --- a/test/demo/index.tsx +++ b/test/demo/index.tsx @@ -390,9 +390,9 @@ const FocusGroup: FC = () => { focusgroup={''} tabIndex={0} > - Red - Yellow - Green + + + ) @@ -407,9 +407,9 @@ const FocusGroupInline: FC = () => { focusgroup="inline" tabIndex={0} > - Mac - Windows - Linux + + + ) @@ -424,9 +424,9 @@ const FocusGroupBlock: FC = () => { focusgroup="block" tabIndex={0} > -
Dog
-
Cat
-
Turtle
+ + + ) diff --git a/test/focus-group.test.ts b/test/focus-group.test.ts index 73666c1..773cb03 100644 --- a/test/focus-group.test.ts +++ b/test/focus-group.test.ts @@ -462,32 +462,32 @@ test('adds focusgroup widget', () => { startKeyUX(window, [focusGroupKeyUX()]) window.document.body.innerHTML = '
' + - 'Mac' + - 'Windows' + - 'Linux' + + '' + + '' + + '' + '
' - let inlineElements = window.document.querySelectorAll('span') - inlineElements[0].focus() + let buttons = window.document.querySelectorAll('button') + buttons[0].focus() - equal(window.document.activeElement, inlineElements[0]) + equal(window.document.activeElement, buttons[0]) press(window, 'ArrowRight') - equal(window.document.activeElement, inlineElements[1]) + equal(window.document.activeElement, buttons[1]) press(window, 'ArrowLeft') - equal(window.document.activeElement, inlineElements[0]) + equal(window.document.activeElement, buttons[0]) press(window, 'End') - equal(window.document.activeElement, inlineElements[2]) + equal(window.document.activeElement, buttons[2]) press(window, 'Home') - equal(window.document.activeElement, inlineElements[0]) + equal(window.document.activeElement, buttons[0]) press(window, 'ArrowLeft') - equal(window.document.activeElement, inlineElements[2]) + equal(window.document.activeElement, buttons[2]) press(window, 'ArrowRight') - equal(window.document.activeElement, inlineElements[0]) + equal(window.document.activeElement, buttons[0]) }) test('adds focusgroup inline widget', () => { @@ -495,32 +495,32 @@ test('adds focusgroup inline widget', () => { startKeyUX(window, [focusGroupKeyUX()]) window.document.body.innerHTML = '
' + - 'Mac' + - 'Windows' + - 'Linux' + + '' + + '' + + '' + '
' - let inlineElements = window.document.querySelectorAll('span') - inlineElements[0].focus() + let buttons = window.document.querySelectorAll('button') + buttons[0].focus() - equal(window.document.activeElement, inlineElements[0]) + equal(window.document.activeElement, buttons[0]) press(window, 'ArrowRight') - equal(window.document.activeElement, inlineElements[1]) + equal(window.document.activeElement, buttons[1]) press(window, 'ArrowLeft') - equal(window.document.activeElement, inlineElements[0]) + equal(window.document.activeElement, buttons[0]) press(window, 'End') - equal(window.document.activeElement, inlineElements[2]) + equal(window.document.activeElement, buttons[2]) press(window, 'Home') - equal(window.document.activeElement, inlineElements[0]) + equal(window.document.activeElement, buttons[0]) press(window, 'ArrowLeft') - equal(window.document.activeElement, inlineElements[2]) + equal(window.document.activeElement, buttons[2]) press(window, 'ArrowRight') - equal(window.document.activeElement, inlineElements[0]) + equal(window.document.activeElement, buttons[0]) }) test('adds focusgroup block widget', () => { @@ -528,31 +528,31 @@ test('adds focusgroup block widget', () => { startKeyUX(window, [focusGroupKeyUX()]) window.document.body.innerHTML = '
' + - '
Dog
' + - '
Cat
' + - '
Turtle
' + + '' + + '' + + '' + '
' - let blockElements = window.document.querySelectorAll('div:not([focusgroup="block"])'); + let buttons = window.document.querySelectorAll('button'); // @ts-ignore - blockElements[0].focus() + buttons[0].focus() - equal(window.document.activeElement, blockElements[0]) + equal(window.document.activeElement, buttons[0]) press(window, 'ArrowDown') - equal(window.document.activeElement, blockElements[1]) + equal(window.document.activeElement, buttons[1]) press(window, 'ArrowUp') - equal(window.document.activeElement, blockElements[0]) + equal(window.document.activeElement, buttons[0]) press(window, 'End') - equal(window.document.activeElement, blockElements[2]) + equal(window.document.activeElement, buttons[2]) press(window, 'Home') - equal(window.document.activeElement, blockElements[0]) + equal(window.document.activeElement, buttons[0]) press(window, 'ArrowLeft') - equal(window.document.activeElement, blockElements[0]) + equal(window.document.activeElement, buttons[0]) press(window, 'ArrowRight') - equal(window.document.activeElement, blockElements[0]) + equal(window.document.activeElement, buttons[0]) })