Adding keyboard accessibility to left navs
Signed-off-by: Rudra-SH <rudra099999@gmail.com>
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
Excepteur in id laborum veniam sunt cillum nulla. Cupidatat aliquip mollit enim nisi elit sunt. Ipsum sunt quis do mollit pariatur sint cupidatat minim reprehenderit eu in. Excepteur tempor ullamco labore magna labore veniam et culpa do in eiusmod cillum velit. Proident adipisicing incididunt exercitation sint. Consectetur mollit in non id ad ad. Amet consectetur dolor consectetur ea laborum ea deserunt nulla duis.
|
||||
|
||||
Ex cupidatat laboris consequat non enim aute anim. Officia nostrud exercitation eiusmod est amet sit dolor est. Culpa aliqua elit laboris enim. Minim minim ipsum amet incididunt do sint adipisicing. Culpa tempor velit ipsum et do.
|
||||
|
||||
Labore proident excepteur ut esse aliqua irure cillum mollit. Aute nisi sit nulla ipsum. Magna anim sint velit cillum incididunt mollit aliqua occaecat elit veniam consequat laboris do incididunt. Lorem laborum mollit reprehenderit sunt officia nisi ea exercitation occaecat.
|
||||
@@ -0,0 +1,9 @@
|
||||
Aliqua adipisicing incididunt ea exercitation nulla qui irure. Ad reprehenderit eu incididunt officia ea magna voluptate proident in pariatur laborum. Voluptate consectetur aliqua aute fugiat dolor duis eiusmod exercitation aliquip consectetur. Dolor exercitation voluptate minim veniam laborum eiusmod in velit et.
|
||||
|
||||
Amet et adipisicing qui ipsum. Incididunt enim sint reprehenderit ullamco ipsum dolor culpa Lorem cillum. Aliqua qui adipisicing amet magna deserunt fugiat ipsum nisi ex sint Lorem laboris. Nulla anim tempor anim nulla sit non non incididunt. Irure ad aliqua velit minim elit excepteur ad voluptate in pariatur officia nulla sunt fugiat. Est aliquip est sit nostrud occaecat. Elit ipsum veniam qui adipisicing sint duis officia ad reprehenderit quis.
|
||||
|
||||
Labore cillum dolor ea laborum. Exercitation non nostrud excepteur anim quis sint dolore. Esse aute dolor velit consequat labore amet et reprehenderit reprehenderit. Enim aute et minim nostrud sint aute Lorem. Fugiat aliqua mollit ullamco sunt.
|
||||
|
||||
Fugiat fugiat eiusmod culpa adipisicing proident non nostrud velit dolor laboris. Labore laborum ut eu labore do amet tempor labore. Eu laborum nostrud occaecat tempor amet elit elit ad anim Lorem exercitation aliquip est enim. Sit et laborum nostrud magna incididunt.
|
||||
|
||||
Duis culpa ea Lorem laborum in commodo ea officia irure labore duis consectetur anim consectetur. Exercitation minim velit minim reprehenderit ad laboris id anim. Adipisicing ad esse dolor ut sint mollit pariatur minim cupidatat.
|
||||
@@ -0,0 +1,5 @@
|
||||
Ea ad adipisicing nisi nulla. Duis voluptate aute aute ad est labore sunt deserunt officia Lorem sit mollit. Velit reprehenderit id voluptate aute Lorem voluptate sunt aliquip nostrud.
|
||||
|
||||
In nostrud esse aliqua esse nostrud qui velit pariatur occaecat et officia. Ex excepteur velit laboris consectetur. Do esse id tempor incididunt veniam minim officia Lorem est laboris. Tempor et consectetur officia exercitation irure aute amet occaecat aliqua nostrud enim laboris anim eu.
|
||||
|
||||
Pariatur voluptate veniam adipisicing nisi nulla occaecat excepteur voluptate. Tempor non duis velit Lorem laboris nulla ullamco incididunt sunt elit reprehenderit et. Ullamco nisi proident nulla minim sunt eiusmod. Commodo ut ad veniam deserunt labore duis qui officia amet mollit eu culpa voluptate. Officia veniam magna elit pariatur exercitation occaecat sint nostrud est. Proident ea ex ad ipsum nulla pariatur eiusmod velit quis ipsum mollit magna deserunt. Commodo ipsum elit velit cillum do velit dolore ex aute nulla duis voluptate reprehenderit.
|
||||
@@ -0,0 +1,11 @@
|
||||
Culpa velit ex enim velit voluptate magna cupidatat. Cupidatat dolor sunt tempor adipisicing. Exercitation cupidatat commodo aliquip duis laborum laboris. Commodo consequat irure ex culpa. Ut exercitation sit eiusmod irure consequat incididunt aliqua. Anim adipisicing aute quis dolore qui officia dolore dolor occaecat dolor. Duis fugiat qui sunt veniam ullamco labore occaecat in reprehenderit incididunt.
|
||||
|
||||
Voluptate nisi ut in proident magna excepteur veniam exercitation ad nisi reprehenderit dolore est ut. Irure id cillum elit tempor tempor cupidatat enim. Anim aute irure nulla pariatur aute minim. Excepteur sunt ipsum commodo commodo eiusmod culpa. Ea dolor ex sint laborum qui enim ex tempor nostrud incididunt ad sit consequat. Deserunt non amet cupidatat id Lorem aute.
|
||||
|
||||
Elit velit cillum Lorem labore incididunt. Consectetur ex occaecat ex id aliquip reprehenderit cupidatat. Veniam excepteur excepteur ut excepteur veniam nisi sunt ipsum ipsum. Aliquip ea elit fugiat occaecat anim deserunt aliqua fugiat reprehenderit esse.
|
||||
|
||||
Culpa ad officia nulla do cupidatat irure aliquip duis ea esse quis est. Anim non elit deserunt reprehenderit exercitation proident in aliquip nisi nisi nisi et pariatur. Dolore ad nisi laborum id commodo ullamco nisi exercitation quis. Duis exercitation sunt aliquip esse nostrud fugiat dolor nostrud dolore eiusmod laborum. Sit sit proident adipisicing aute nulla exercitation qui reprehenderit nulla consectetur ullamco cupidatat consequat. Ex commodo officia officia dolor ut. Proident culpa deserunt exercitation quis nostrud cillum exercitation.
|
||||
|
||||
Ullamco aute et dolore adipisicing. Sint exercitation eiusmod aliqua enim velit aliqua ea mollit cupidatat officia officia proident ex. Voluptate amet laborum deserunt ea in culpa exercitation culpa cillum laborum enim enim nostrud. Labore dolor ex commodo nostrud sit eiusmod. Aliquip enim dolor nostrud fugiat veniam Lorem irure ad tempor irure reprehenderit. Aute ut laboris dolore laboris do amet.
|
||||
|
||||
Officia ipsum magna veniam enim sit culpa ex laboris aliqua et minim sint id. Culpa proident do esse eu sunt laborum dolor ut dolor in mollit sit id. Aute tempor do labore anim aliquip eiusmod deserunt sit sint et. Fugiat qui et cillum do esse dolor nulla Lorem do. Incididunt magna irure magna proident qui aliqua officia duis laborum.
|
||||
@@ -5,8 +5,14 @@ edit_uri: edit/master/plugins/techdocs-backend/examples/documented-component/doc
|
||||
nav:
|
||||
- Home: index.md
|
||||
- Subpage: sub-page.md
|
||||
- 'Code Sample': code/code-sample.md
|
||||
- Extensions: extensions.md
|
||||
- Code Sample:
|
||||
- Overview: code/code-sample.md
|
||||
- Example 1: code/example1.md
|
||||
- Example 2: code/example2.md
|
||||
- Extensions:
|
||||
- Overview: extensions.md
|
||||
- Advanced: extensions/advanced.md
|
||||
- API Reference: extensions/api-reference.md
|
||||
|
||||
plugins:
|
||||
- techdocs-core
|
||||
|
||||
+46
-3
@@ -77,6 +77,7 @@ export const ExpandableNavigationAddon = () => {
|
||||
(item: HTMLInputElement) => {
|
||||
const isExpanded = item.checked;
|
||||
const shouldExpand = expanded?.expandAllNestedNavs;
|
||||
// console.log('Item:', item, 'isExpanded:', isExpanded, 'shouldExpand:', shouldExpand);
|
||||
|
||||
// Is collapsed but should expand
|
||||
if (shouldExpand && !isExpanded) {
|
||||
@@ -92,16 +93,55 @@ export const ExpandableNavigationAddon = () => {
|
||||
},
|
||||
[expanded],
|
||||
);
|
||||
|
||||
const handleKeyPass = (
|
||||
event: React.KeyboardEvent<HTMLElement>,
|
||||
toggleAction: () => void,
|
||||
) => {
|
||||
if (event.key === 'Enter' || event.key === ' ') {
|
||||
event.preventDefault();
|
||||
toggleAction();
|
||||
}
|
||||
};
|
||||
useEffect(() => {
|
||||
// console.log('Checkbox Toggles:', checkboxToggles);
|
||||
// There is no nested navs
|
||||
if (!checkboxToggles?.length) return;
|
||||
|
||||
setHasNavSubLevels(true);
|
||||
checkboxToggles.forEach(item => {
|
||||
if (shouldToggle(item)) item.click();
|
||||
item.tabIndex = 0;
|
||||
const toggleAction = () => {
|
||||
if (shouldToggle(item)) {
|
||||
// console.log('Toggling item:', item);
|
||||
item.click();
|
||||
}
|
||||
};
|
||||
// Add keyboard event listener
|
||||
const keydownHandler = (event: KeyboardEvent) => {
|
||||
handleKeyPass(
|
||||
event as unknown as React.KeyboardEvent<HTMLDivElement>,
|
||||
toggleAction,
|
||||
);
|
||||
};
|
||||
// console.log('Attaching keydown listener to:', item)
|
||||
item.addEventListener('keydown', keydownHandler);
|
||||
item.addEventListener('click', toggleAction);
|
||||
|
||||
// Clean up event listener or unmount
|
||||
return () => {
|
||||
item.removeEventListener('keydown', keydownHandler);
|
||||
item.removeEventListener('click', toggleAction);
|
||||
};
|
||||
});
|
||||
}, [expanded, shouldToggle, checkboxToggles]);
|
||||
}, [checkboxToggles, shouldToggle]);
|
||||
useEffect(() => {
|
||||
if (!checkboxToggles?.length) return;
|
||||
checkboxToggles.forEach(item => {
|
||||
if (shouldToggle(item)) {
|
||||
item.click();
|
||||
}
|
||||
});
|
||||
}, [expanded, checkboxToggles, shouldToggle]);
|
||||
|
||||
const handleState = () => {
|
||||
setExpanded(prevState => ({
|
||||
@@ -115,6 +155,9 @@ export const ExpandableNavigationAddon = () => {
|
||||
<StyledButton
|
||||
size="small"
|
||||
onClick={handleState}
|
||||
onKeyDown={event => handleKeyPass(event, handleState)}
|
||||
tabIndex={0} // Ensuring keyboard focus
|
||||
aria-expanded={expanded?.expandAllNestedNavs} // Accessibility
|
||||
aria-label={
|
||||
expanded?.expandAllNestedNavs ? 'collapse-nav' : 'expand-nav'
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import {
|
||||
useSanitizerTransformer,
|
||||
useStylesTransformer,
|
||||
handleMetaRedirects,
|
||||
addNavLinkKeyboardToggle,
|
||||
} from '../../transformers';
|
||||
import { useNavigateUrl } from './useNavigateUrl';
|
||||
import { useParams } from 'react-router-dom';
|
||||
@@ -267,6 +268,7 @@ export const useTechDocsReaderDom = (
|
||||
},
|
||||
onLoaded: () => {},
|
||||
}),
|
||||
addNavLinkKeyboardToggle(),
|
||||
]),
|
||||
[theme, navigate, analytics, entityRef.name, configApi],
|
||||
);
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { addNavLinkKeyboardToggle } from './addNavLinkKeyboardToggle';
|
||||
import { createTestShadowDom } from '../../test-utils';
|
||||
import { act } from '@testing-library/react';
|
||||
|
||||
describe('addNavLinkKeyboardToggle', () => {
|
||||
it('adds tabindex and toggles checkbox on Enter/Space', async () => {
|
||||
let shadowDom: ShadowRoot;
|
||||
await act(async () => {
|
||||
shadowDom = await createTestShadowDom(
|
||||
`
|
||||
<input type="checkbox" id="cb1" />
|
||||
<label class="md-nav__link" for="cb1">Section</label>
|
||||
`,
|
||||
{
|
||||
preTransformers: [],
|
||||
postTransformers: [addNavLinkKeyboardToggle()],
|
||||
},
|
||||
);
|
||||
});
|
||||
const label = shadowDom!.querySelector('label.md-nav__link')!;
|
||||
const checkbox = shadowDom!.querySelector('#cb1') as HTMLInputElement;
|
||||
expect(label.getAttribute('tabIndex')).toBe('0');
|
||||
|
||||
// Simulate keydown: Enter
|
||||
await act(async () => {
|
||||
label.dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }),
|
||||
);
|
||||
});
|
||||
expect(checkbox.checked).toBe(true);
|
||||
|
||||
// Simulate keydown: space
|
||||
await act(async () => {
|
||||
label.dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: ' ', bubbles: true }),
|
||||
);
|
||||
});
|
||||
expect(checkbox.checked).toBe(false);
|
||||
});
|
||||
|
||||
it('does nothing if no for attribute or checkbox', async () => {
|
||||
let shadowDom: ShadowRoot;
|
||||
await act(async () => {
|
||||
shadowDom = await createTestShadowDom(
|
||||
`<label class ="md-nav__link">No for</label>`,
|
||||
{
|
||||
preTransformers: [],
|
||||
postTransformers: [addNavLinkKeyboardToggle()],
|
||||
},
|
||||
);
|
||||
});
|
||||
const label = shadowDom!.querySelector('label.md-nav__link')!;
|
||||
await act(async () => {
|
||||
expect(() =>
|
||||
label.dispatchEvent(
|
||||
new KeyboardEvent('keydown', { key: 'Enter', bubbles: true }),
|
||||
),
|
||||
).not.toThrow();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2020 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export function addNavLinkKeyboardToggle() {
|
||||
return (element: Element) => {
|
||||
const navLabels = element.querySelectorAll('label.md-nav__link[for]');
|
||||
navLabels.forEach(label => {
|
||||
label.setAttribute('tabIndex', '0');
|
||||
label.addEventListener('keydown', event => {
|
||||
const keyboardEvent = event as KeyboardEvent;
|
||||
if (keyboardEvent.key === 'Enter' || keyboardEvent.key === ' ') {
|
||||
const forId = label.getAttribute('for');
|
||||
if (!forId) return;
|
||||
const checkbox = element.querySelector(
|
||||
`#${forId}`,
|
||||
) as HTMLInputElement | null;
|
||||
if (checkbox && checkbox.type === 'checkbox') {
|
||||
checkbox.checked = !checkbox.checked;
|
||||
checkbox.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
return element;
|
||||
};
|
||||
}
|
||||
@@ -28,3 +28,4 @@ export * from './onCssReady';
|
||||
export * from './scrollIntoNavigation';
|
||||
export * from './transformer';
|
||||
export * from './handleMetaRedirects';
|
||||
export * from './addNavLinkKeyboardToggle';
|
||||
|
||||
Reference in New Issue
Block a user