From f93604b4cf03faf01fd0c03eefc6c3288f57d0ad Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Fri, 23 Oct 2020 02:20:41 +0300 Subject: [PATCH 1/3] refactor(v2): remove focus outline from mouse users --- .../src/theme/Layout/index.tsx | 4 ++ .../src/theme/Tabs/index.tsx | 32 +----------- .../src/theme/hooks/styles.css | 10 ++++ .../src/theme/hooks/useKeyboardNavigation.ts | 51 +++++++++++++++++++ .../docusaurus-theme-classic/src/types.d.ts | 6 +++ 5 files changed, 73 insertions(+), 30 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/hooks/styles.css create mode 100644 packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts diff --git a/packages/docusaurus-theme-classic/src/theme/Layout/index.tsx b/packages/docusaurus-theme-classic/src/theme/Layout/index.tsx index 108f03e47d77..c21b28d9c030 100644 --- a/packages/docusaurus-theme-classic/src/theme/Layout/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Layout/index.tsx @@ -13,10 +13,14 @@ import Footer from '@theme/Footer'; import LayoutProviders from '@theme/LayoutProviders'; import LayoutHead from '@theme/LayoutHead'; import type {Props} from '@theme/Layout'; +import useKeyboardNavigation from '@theme/hooks/useKeyboardNavigation'; import './styles.css'; function Layout(props: Props): JSX.Element { const {children, noFooter, wrapperClassName} = props; + + useKeyboardNavigation(); + return ( diff --git a/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx b/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx index 29d7b1ca0573..4b84a76523fc 100644 --- a/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Tabs/index.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {useState, Children, ReactElement, useEffect} from 'react'; +import React, {useState, Children, ReactElement} from 'react'; import useUserPreferencesContext from '@theme/hooks/useUserPreferencesContext'; import type {Props} from '@theme/Tabs'; @@ -16,14 +16,12 @@ import styles from './styles.module.css'; const keys = { left: 37, right: 39, - tab: 9, }; function Tabs(props: Props): JSX.Element { const {block, children, defaultValue, values, groupId, className} = props; const {tabGroupChoices, setTabGroupChoices} = useUserPreferencesContext(); const [selectedValue, setSelectedValue] = useState(defaultValue); - const [keyboardPress, setKeyboardPress] = useState(false); if (groupId != null) { const relevantTabGroupChoice = tabGroupChoices[groupId]; @@ -78,28 +76,6 @@ function Tabs(props: Props): JSX.Element { } }; - const handleKeyboardEvent = (event) => { - if (event.metaKey || event.altKey || event.ctrlKey) { - return; - } - - setKeyboardPress(true); - }; - - const handleMouseEvent = () => { - setKeyboardPress(false); - }; - - useEffect(() => { - window.addEventListener('keydown', handleKeyboardEvent); - window.addEventListener('mousedown', handleMouseEvent); - - return () => { - window.removeEventListener('keydown', handleKeyboardEvent); - window.removeEventListener('mousedown', handleMouseEvent); - }; - }, []); - return (
    tabRefs.push(tabControl)} onKeyDown={(event) => { handleKeydown(tabRefs, event.target, event); - handleKeyboardEvent(event); }} onFocus={() => changeSelectedValue(value)} onClick={() => { changeSelectedValue(value); - setKeyboardPress(false); - }} - onPointerDown={() => setKeyboardPress(false)}> + }}> {label} ))} diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/styles.css b/packages/docusaurus-theme-classic/src/theme/hooks/styles.css new file mode 100644 index 000000000000..9ff4acda9a5f --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/hooks/styles.css @@ -0,0 +1,10 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +body:not(.navigation-with-keyboard) *:focus { + outline: none; +} diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts b/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts new file mode 100644 index 000000000000..b6eeec79d139 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts @@ -0,0 +1,51 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {useEffect} from 'react'; + +import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; + +import './styles.css'; + +// This hook detect keyboard focus indicator to not show outline for mouse users +// Inspired by https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 +function useKeyboardNavigation(): void { + useEffect(() => { + if (!ExecutionEnvironment.canUseDOM) { + return undefined; + } + + const keyboardFocusedClassName = 'navigation-with-keyboard'; + + function handleFirstTab(e: KeyboardEvent) { + if (e.key === 'Tab') { + document.body.classList.add(keyboardFocusedClassName); + + document.removeEventListener('keydown', handleFirstTab); + document.addEventListener('mousedown', handleMouseDown); + } + } + + function handleMouseDown() { + document.body.classList.remove(keyboardFocusedClassName); + + document.removeEventListener('mousedown', handleMouseDown); + document.addEventListener('keydown', handleFirstTab); + } + + document.addEventListener('keydown', handleFirstTab); + + return () => { + document.body.classList.remove(keyboardFocusedClassName); + + document.removeEventListener('keydown', handleFirstTab); + document.removeEventListener('mousedown', handleMouseDown); + }; + }, []); +} + +export default useKeyboardNavigation; diff --git a/packages/docusaurus-theme-classic/src/types.d.ts b/packages/docusaurus-theme-classic/src/types.d.ts index 59cb29b859d5..c6bf4dbc3f81 100644 --- a/packages/docusaurus-theme-classic/src/types.d.ts +++ b/packages/docusaurus-theme-classic/src/types.d.ts @@ -236,6 +236,12 @@ declare module '@theme/hooks/useWindowSize' { export default function useWindowSize(): WindowSize | undefined; } +declare module '@theme/hooks/useKeyboardNavigation' { + const useKeyboardNavigation: () => void; + + export default useKeyboardNavigation; +} + declare module '@theme/Layout' { import type {ReactNode} from 'react'; From e260104499362e400daacccae19baeb1bb4bdc4e Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 26 Oct 2020 20:46:30 +0300 Subject: [PATCH 2/3] Improvements --- .../src/theme/hooks/styles.css | 2 +- .../src/theme/hooks/useKeyboardNavigation.ts | 30 ++++--------------- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/styles.css b/packages/docusaurus-theme-classic/src/theme/hooks/styles.css index 9ff4acda9a5f..a5d601e160b3 100644 --- a/packages/docusaurus-theme-classic/src/theme/hooks/styles.css +++ b/packages/docusaurus-theme-classic/src/theme/hooks/styles.css @@ -5,6 +5,6 @@ * LICENSE file in the root directory of this source tree. */ -body:not(.navigation-with-keyboard) *:focus { +body:not(.navigation-with-keyboard) *:not(input):focus { outline: none; } diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts b/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts index b6eeec79d139..985dd93e2e30 100644 --- a/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts +++ b/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts @@ -7,43 +7,25 @@ import {useEffect} from 'react'; -import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; - import './styles.css'; // This hook detect keyboard focus indicator to not show outline for mouse users // Inspired by https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2 function useKeyboardNavigation(): void { useEffect(() => { - if (!ExecutionEnvironment.canUseDOM) { - return undefined; - } - const keyboardFocusedClassName = 'navigation-with-keyboard'; - function handleFirstTab(e: KeyboardEvent) { - if (e.key === 'Tab') { - document.body.classList.add(keyboardFocusedClassName); - - document.removeEventListener('keydown', handleFirstTab); - document.addEventListener('mousedown', handleMouseDown); - } + function handleOutlineStyles(e: MouseEvent | KeyboardEvent) { + document.body.classList.toggle(keyboardFocusedClassName, e.key === 'Tab'); } - function handleMouseDown() { - document.body.classList.remove(keyboardFocusedClassName); - - document.removeEventListener('mousedown', handleMouseDown); - document.addEventListener('keydown', handleFirstTab); - } - - document.addEventListener('keydown', handleFirstTab); + document.addEventListener('keydown', handleOutlineStyles); + document.addEventListener('mousedown', handleOutlineStyles); return () => { document.body.classList.remove(keyboardFocusedClassName); - - document.removeEventListener('keydown', handleFirstTab); - document.removeEventListener('mousedown', handleMouseDown); + document.removeEventListener('keydown', handleOutlineStyles); + document.removeEventListener('mousedown', handleOutlineStyles); }; }, []); } From 4d5b422d67b8427c3e1ce4f1ed6ec996fd836d11 Mon Sep 17 00:00:00 2001 From: Alexey Pyltsyn Date: Mon, 26 Oct 2020 21:01:47 +0300 Subject: [PATCH 3/3] Cleanup --- .../src/theme/hooks/useKeyboardNavigation.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts b/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts index 985dd93e2e30..acc5545622aa 100644 --- a/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts +++ b/packages/docusaurus-theme-classic/src/theme/hooks/useKeyboardNavigation.ts @@ -16,7 +16,13 @@ function useKeyboardNavigation(): void { const keyboardFocusedClassName = 'navigation-with-keyboard'; function handleOutlineStyles(e: MouseEvent | KeyboardEvent) { - document.body.classList.toggle(keyboardFocusedClassName, e.key === 'Tab'); + if (e.type === 'keydown' && (e as KeyboardEvent).key === 'Tab') { + document.body.classList.add(keyboardFocusedClassName); + } + + if (e.type === 'mousedown') { + document.body.classList.remove(keyboardFocusedClassName); + } } document.addEventListener('keydown', handleOutlineStyles);