From a3c1cf2c630d69ea7c0e6269286c288b86f347cc Mon Sep 17 00:00:00 2001 From: Mike Perrotti Date: Thu, 28 Apr 2022 14:57:23 -0400 Subject: [PATCH 01/12] updates focus styles that do not match the Primer CSS implementation --- docs/content/SubNav.md | 2 +- src/Pagination/Pagination.tsx | 6 ++++++ src/TabNav.tsx | 6 ++++++ src/_TextInputWrapper.tsx | 39 ++++++++--------------------------- src/_globalFocusStyles.ts | 10 +++++++++ 5 files changed, 32 insertions(+), 31 deletions(-) create mode 100644 src/_globalFocusStyles.ts diff --git a/docs/content/SubNav.md b/docs/content/SubNav.md index 701dc47e262..d674f543b17 100644 --- a/docs/content/SubNav.md +++ b/docs/content/SubNav.md @@ -39,7 +39,7 @@ This ensures that the NavLink gets `activeClassName='selected'` Support - + ``` diff --git a/src/Pagination/Pagination.tsx b/src/Pagination/Pagination.tsx index 8a13794f3f7..666a9123fd3 100644 --- a/src/Pagination/Pagination.tsx +++ b/src/Pagination/Pagination.tsx @@ -3,6 +3,7 @@ import styled from 'styled-components' import Box from '../Box' import {get} from '../constants' import sx, {SxProp} from '../sx' +import globalFocusStyles from '../_globalFocusStyles' import {buildComponentData, buildPaginationModel} from './model' const Page = styled.a` @@ -37,6 +38,11 @@ const Page = styled.a` transition-duration: 0.1s; } + &:focus-visible { + ${globalFocusStyles}; + outline-offset: 0; + } + &:active { border-color: ${get('colors.border.muted')}; } diff --git a/src/TabNav.tsx b/src/TabNav.tsx index c4204d406f9..f32048f25eb 100644 --- a/src/TabNav.tsx +++ b/src/TabNav.tsx @@ -5,6 +5,7 @@ import styled from 'styled-components' import {get} from './constants' import sx, {SxProp} from './sx' import {ComponentProps} from './utils/types' +import globalFocusStyles from './_globalFocusStyles' const ITEM_CLASS = 'TabNav-item' const SELECTED_CLASS = 'selected' @@ -49,6 +50,11 @@ const TabNavLink = styled.a.attrs(props => ({ border: 1px solid transparent; border-bottom: 0; + &:focus-visible { + ${globalFocusStyles}; + outline-offset: -6px; + } + &:hover, &:focus { color: ${get('colors.fg.default')}; diff --git a/src/_TextInputWrapper.tsx b/src/_TextInputWrapper.tsx index 29962499ee6..ed0cb97f050 100644 --- a/src/_TextInputWrapper.tsx +++ b/src/_TextInputWrapper.tsx @@ -65,20 +65,22 @@ export type StyledWrapperProps = { const textInputBasePadding = '12px' export const textInputHorizPadding = textInputBasePadding -// TODO: figure out how to type a themed CSS function (e.g.: css`color: blue;`) -// eslint-disable-next-line @typescript-eslint/no-explicit-any -const renderFocusStyles = (hasTrailingAction: boolean, isInputFocused: boolean, focusStyles: any) => { +const renderFocusStyles = (hasTrailingAction: boolean, isInputFocused: boolean) => { if (hasTrailingAction) { return ( isInputFocused && css` - ${focusStyles} + border-color: ${get('colors.accent.fg')}; + outline: none; + box-shadow: inset 0 0 0 1px ${get('colors.accent.fg')}; ` ) } return css` &:focus-within { - ${focusStyles} + border-color: ${get('colors.accent.fg')}; + outline: none; + box-shadow: inset 0 0 0 1px ${get('colors.accent.fg')}; } ` } @@ -102,15 +104,7 @@ export const TextInputBaseWrapper = styled.span` color: ${get('colors.fg.subtle')}; } - ${props => - renderFocusStyles( - Boolean(props.hasTrailingAction), - Boolean(props.isInputFocused), - css` - border-color: ${get('colors.accent.emphasis')}; - box-shadow: ${get('shadows.primer.shadow.focus')}; - ` - )} + ${props => renderFocusStyles(Boolean(props.hasTrailingAction), Boolean(props.isInputFocused))} > textarea { padding: ${textInputBasePadding}; @@ -141,14 +135,7 @@ export const TextInputBaseWrapper = styled.span` props.validationStatus === 'error' && css` border-color: ${get('colors.danger.emphasis')}; - ${renderFocusStyles( - Boolean(props.hasTrailingAction), - Boolean(props.isInputFocused), - css` - border-color: ${get('colors.danger.emphasis')}; - box-shadow: ${get('shadows.btn.danger.focusShadow')}; - ` - )} + ${renderFocusStyles(Boolean(props.hasTrailingAction), Boolean(props.isInputFocused))} `} @@ -156,14 +143,6 @@ export const TextInputBaseWrapper = styled.span` props.validationStatus === 'success' && css` border-color: ${get('colors.success.emphasis')}; - ${renderFocusStyles( - Boolean(props.hasTrailingAction), - Boolean(props.isInputFocused), - css` - border-color: ${get('colors.success.emphasis')}; - box-shadow: 0 0 0 3px ${get('colors.success.muted')}; - ` - )} `} ${props => diff --git a/src/_globalFocusStyles.ts b/src/_globalFocusStyles.ts new file mode 100644 index 00000000000..72b329c8c1f --- /dev/null +++ b/src/_globalFocusStyles.ts @@ -0,0 +1,10 @@ +import {css} from 'styled-components' +import {get} from './constants' + +const globalFocusStyles = css` + box-shadow: none; + outline: 2px solid ${get('colors.accent.fg')}; + outline-offset: 2px; +` + +export default globalFocusStyles From b2c66d048b763d7c3c0e505ce0903a6af53e8aeb Mon Sep 17 00:00:00 2001 From: Mike Perrotti Date: Thu, 28 Apr 2022 14:58:05 -0400 Subject: [PATCH 02/12] updates ThemeSwitcher to render ActionMenu instead of DropdownMenu --- .../components/live-preview-wrapper.js | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/docs/src/@primer/gatsby-theme-doctocat/components/live-preview-wrapper.js b/docs/src/@primer/gatsby-theme-doctocat/components/live-preview-wrapper.js index 80e851b9ca9..a2871551839 100644 --- a/docs/src/@primer/gatsby-theme-doctocat/components/live-preview-wrapper.js +++ b/docs/src/@primer/gatsby-theme-doctocat/components/live-preview-wrapper.js @@ -1,24 +1,33 @@ -import {BaseStyles, Box, ThemeProvider, useTheme} from '@primer/react' -import {DropdownMenu, DropdownButton} from '@primer/react/deprecated' import React from 'react' +import {ActionMenu, ActionList, BaseStyles, Box, ThemeProvider, useTheme} from '@primer/react' function ThemeSwitcher() { const {theme, dayScheme, setDayScheme} = useTheme() - const items = Object.keys(theme.colorSchemes).map(scheme => ({text: scheme.replace(/_/g, ' '), key: scheme})) + const items = Object.keys(theme.colorSchemes).map(scheme => ({name: scheme.replace(/_/g, ' '), key: scheme})) const selectedItem = React.useMemo(() => items.find(item => item.key === dayScheme), [items, dayScheme]) + const itemsKeys = items.map(item => item.key) + const [selectedIndex, setSelectedIndex] = React.useState(itemsKeys.indexOf(dayScheme)) + return ( - ( - - {children} - - )} - items={items} - selectedItem={selectedItem} - onChange={item => { - setDayScheme(item.key) - }} - /> + + {selectedItem?.name} + + + {items.map((type, index) => ( + { + setSelectedIndex(index) + setDayScheme(items[index].key) + }} + > + {type.name} + + ))} + + + ) } From b31c108d02e25ac8ba9dc102eeef69eec2f76ad7 Mon Sep 17 00:00:00 2001 From: Mike Perrotti Date: Thu, 28 Apr 2022 15:06:22 -0400 Subject: [PATCH 03/12] explicitly sets outline-offset in global focus styles instead of adding a new style that 'beats' the default 2px --- src/Pagination/Pagination.tsx | 5 ++--- src/TabNav.tsx | 5 ++--- src/_getGlobalFocusStyles.ts | 11 +++++++++++ src/_globalFocusStyles.ts | 10 ---------- 4 files changed, 15 insertions(+), 16 deletions(-) create mode 100644 src/_getGlobalFocusStyles.ts delete mode 100644 src/_globalFocusStyles.ts diff --git a/src/Pagination/Pagination.tsx b/src/Pagination/Pagination.tsx index 666a9123fd3..7e521517150 100644 --- a/src/Pagination/Pagination.tsx +++ b/src/Pagination/Pagination.tsx @@ -3,7 +3,7 @@ import styled from 'styled-components' import Box from '../Box' import {get} from '../constants' import sx, {SxProp} from '../sx' -import globalFocusStyles from '../_globalFocusStyles' +import getGlobalFocusStyles from '../_getGlobalFocusStyles' import {buildComponentData, buildPaginationModel} from './model' const Page = styled.a` @@ -39,8 +39,7 @@ const Page = styled.a` } &:focus-visible { - ${globalFocusStyles}; - outline-offset: 0; + ${getGlobalFocusStyles(0)}; } &:active { diff --git a/src/TabNav.tsx b/src/TabNav.tsx index f32048f25eb..9ba5940bbb5 100644 --- a/src/TabNav.tsx +++ b/src/TabNav.tsx @@ -5,7 +5,7 @@ import styled from 'styled-components' import {get} from './constants' import sx, {SxProp} from './sx' import {ComponentProps} from './utils/types' -import globalFocusStyles from './_globalFocusStyles' +import getGlobalFocusStyles from './_getGlobalFocusStyles' const ITEM_CLASS = 'TabNav-item' const SELECTED_CLASS = 'selected' @@ -51,8 +51,7 @@ const TabNavLink = styled.a.attrs(props => ({ border-bottom: 0; &:focus-visible { - ${globalFocusStyles}; - outline-offset: -6px; + ${getGlobalFocusStyles('-6px')}; } &:hover, diff --git a/src/_getGlobalFocusStyles.ts b/src/_getGlobalFocusStyles.ts new file mode 100644 index 00000000000..ef12d43f3d7 --- /dev/null +++ b/src/_getGlobalFocusStyles.ts @@ -0,0 +1,11 @@ +import {CSSProperties} from 'react' +import {css} from 'styled-components' +import {get} from './constants' + +const getGlobalFocusStyles = (outlineOffset?: CSSProperties['outlineOffset']) => css` + box-shadow: none; + outline: 2px solid ${get('colors.accent.fg')}; + outline-offset: ${outlineOffset || '2px'}; +` + +export default getGlobalFocusStyles diff --git a/src/_globalFocusStyles.ts b/src/_globalFocusStyles.ts deleted file mode 100644 index 72b329c8c1f..00000000000 --- a/src/_globalFocusStyles.ts +++ /dev/null @@ -1,10 +0,0 @@ -import {css} from 'styled-components' -import {get} from './constants' - -const globalFocusStyles = css` - box-shadow: none; - outline: 2px solid ${get('colors.accent.fg')}; - outline-offset: 2px; -` - -export default globalFocusStyles From ad65025d514523e64a9336589f54066689bd0f2e Mon Sep 17 00:00:00 2001 From: Mike Perrotti Date: Thu, 28 Apr 2022 15:08:18 -0400 Subject: [PATCH 04/12] update snapshots --- .../__snapshots__/Pagination.test.tsx.snap | 6 ++ .../__snapshots__/Autocomplete.test.tsx.snap | 21 +++-- .../__snapshots__/TabNav.test.tsx.snap | 6 ++ .../__snapshots__/TextInput.test.tsx.snap | 85 ++++++++++++------- .../TextInputWithTokens.test.tsx.snap | 78 +++++++++++------ .../__snapshots__/Textarea.test.tsx.snap | 3 +- 6 files changed, 136 insertions(+), 63 deletions(-) diff --git a/src/__tests__/Pagination/__snapshots__/Pagination.test.tsx.snap b/src/__tests__/Pagination/__snapshots__/Pagination.test.tsx.snap index f0f13c18b48..6e173bca839 100644 --- a/src/__tests__/Pagination/__snapshots__/Pagination.test.tsx.snap +++ b/src/__tests__/Pagination/__snapshots__/Pagination.test.tsx.snap @@ -43,6 +43,12 @@ exports[`Pagination renders consistently 1`] = ` transition-duration: 0.1s; } +.c2:focus-visible { + box-shadow: none; + outline: 2px solid #0969da; + outline-offset: 2px; +} + .c2:active { border-color: hsla(210,18%,87%,1); } diff --git a/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap b/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap index 56c84fb8419..63a64e2f9e7 100644 --- a/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap +++ b/src/__tests__/__snapshots__/Autocomplete.test.tsx.snap @@ -46,7 +46,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -197,7 +198,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -383,7 +385,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -1332,7 +1335,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -2191,7 +2195,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -3061,7 +3066,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -4061,7 +4067,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { diff --git a/src/__tests__/__snapshots__/TabNav.test.tsx.snap b/src/__tests__/__snapshots__/TabNav.test.tsx.snap index 58d38dd3de4..2136f64909c 100644 --- a/src/__tests__/__snapshots__/TabNav.test.tsx.snap +++ b/src/__tests__/__snapshots__/TabNav.test.tsx.snap @@ -13,6 +13,12 @@ exports[`TabNav TabNav.Link renders consistently 1`] = ` border-bottom: 0; } +.c0:focus-visible { + box-shadow: none; + outline: 2px solid #0969da; + outline-offset: -6px; +} + .c0:hover, .c0:focus { color: #24292f; diff --git a/src/__tests__/__snapshots__/TextInput.test.tsx.snap b/src/__tests__/__snapshots__/TextInput.test.tsx.snap index 587faa121f4..b59b25330dc 100644 --- a/src/__tests__/__snapshots__/TextInput.test.tsx.snap +++ b/src/__tests__/__snapshots__/TextInput.test.tsx.snap @@ -45,7 +45,8 @@ exports[`TextInput renders 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -160,7 +161,8 @@ exports[`TextInput renders block 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -270,7 +272,8 @@ exports[`TextInput renders consistently 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -380,7 +383,8 @@ exports[`TextInput renders contrast 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -491,7 +495,8 @@ exports[`TextInput renders error 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -499,8 +504,9 @@ exports[`TextInput renders error 1`] = ` } .c0:focus-within { - border-color: #cf222e; - box-shadow: 0 0 0 3px rgba(164,14,38,0.4); + border-color: #0969da; + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 >:not(:last-child) { @@ -611,7 +617,8 @@ exports[`TextInput renders large 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -722,7 +729,8 @@ exports[`TextInput renders leadingVisual 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -860,7 +868,8 @@ exports[`TextInput renders monospace 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -970,7 +979,8 @@ exports[`TextInput renders placeholder 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -1088,7 +1098,8 @@ exports[`TextInput renders small 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -2377,7 +2388,8 @@ exports[`TextInput renders trailingVisual 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -2515,7 +2527,8 @@ exports[`TextInput renders warning 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -2544,8 +2557,9 @@ exports[`TextInput renders warning 1`] = ` } .c0:focus-within { - border-color: #bf8700; - box-shadow: 0 0 0 3px rgba(212,167,44,0.4); + border-color: #0969da; + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c1 { @@ -2639,7 +2653,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -2797,7 +2812,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -2999,7 +3015,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -3161,7 +3178,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -3403,7 +3421,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -3645,7 +3664,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -3887,7 +3907,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -4085,7 +4106,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -4327,7 +4349,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -4536,7 +4559,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -4819,7 +4843,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -5106,7 +5131,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -5377,7 +5403,8 @@ exports[`TextInput should render a password input 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { diff --git a/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap b/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap index 03f1c8ed1fb..1725ebaeeaa 100644 --- a/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap +++ b/src/__tests__/__snapshots__/TextInputWithTokens.test.tsx.snap @@ -89,7 +89,8 @@ exports[`TextInputWithTokens renders a leadingVisual and trailingVisual 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -816,7 +817,8 @@ exports[`TextInputWithTokens renders a truncated set of tokens 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -1231,7 +1233,8 @@ exports[`TextInputWithTokens renders as block layout 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -1398,7 +1401,8 @@ exports[`TextInputWithTokens renders at a maximum height when specified 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -2080,7 +2084,8 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -2762,7 +2767,8 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 2`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -3437,7 +3443,8 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 3`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -4112,7 +4119,8 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 4`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -4787,7 +4795,8 @@ exports[`TextInputWithTokens renders tokens at the specified sizes 5`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -5464,7 +5473,8 @@ exports[`TextInputWithTokens renders tokens on a single line when specified 1`] .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -6139,7 +6149,8 @@ exports[`TextInputWithTokens renders tokens without a remove button when specifi .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -6531,7 +6542,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -7255,7 +7267,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -8023,7 +8036,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -8751,7 +8765,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -9559,7 +9574,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -10367,7 +10383,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -11175,7 +11192,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -11939,7 +11957,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -12747,7 +12766,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -13522,7 +13542,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -14370,7 +14391,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -15218,7 +15240,8 @@ Array [ .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -16054,7 +16077,8 @@ exports[`TextInputWithTokens renders with tokens 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -16729,7 +16753,8 @@ exports[`TextInputWithTokens renders with tokens using a custom token component .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { @@ -17409,7 +17434,8 @@ exports[`TextInputWithTokens renders without tokens 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { diff --git a/src/__tests__/__snapshots__/Textarea.test.tsx.snap b/src/__tests__/__snapshots__/Textarea.test.tsx.snap index 137d04ffcad..9581ddbc8c1 100644 --- a/src/__tests__/__snapshots__/Textarea.test.tsx.snap +++ b/src/__tests__/__snapshots__/Textarea.test.tsx.snap @@ -41,7 +41,8 @@ exports[`Textarea renders consistently 1`] = ` .c0:focus-within { border-color: #0969da; - box-shadow: 0 0 0 3px rgba(9,105,218,0.3); + outline: none; + box-shadow: inset 0 0 0 1px #0969da; } .c0 > textarea { From 8c7d0207d125f0e46ebbff4e5e718744f3528636 Mon Sep 17 00:00:00 2001 From: Mike Perrotti Date: Thu, 28 Apr 2022 15:50:34 -0400 Subject: [PATCH 05/12] fixes cross-browser issues for global focus styles --- src/Checkbox.tsx | 2 + src/Pagination/Pagination.tsx | 4 +- src/Radio.tsx | 2 + src/TabNav.tsx | 4 +- .../__snapshots__/Pagination.test.tsx.snap | 12 ++- .../__snapshots__/Checkbox.test.tsx.snap | 16 ++++ .../__snapshots__/CheckboxGroup.test.tsx.snap | 16 ++++ .../CheckboxOrRadioGroup.test.tsx.snap | 16 ++++ .../__snapshots__/Radio.test.tsx.snap | 16 ++++ .../__snapshots__/RadioGroup.test.tsx.snap | 16 ++++ .../__snapshots__/TabNav.test.tsx.snap | 10 ++ .../__snapshots__/themePreval.test.ts.snap | 2 +- .../ChoiceFieldset.test.tsx.snap | 96 +++++++++++++++++++ src/_getGlobalFocusStyles.ts | 22 ++++- 14 files changed, 224 insertions(+), 10 deletions(-) diff --git a/src/Checkbox.tsx b/src/Checkbox.tsx index bbad54491ca..058aa1b2e63 100644 --- a/src/Checkbox.tsx +++ b/src/Checkbox.tsx @@ -4,6 +4,7 @@ import React, {ChangeEventHandler, InputHTMLAttributes, ReactElement, useContext import sx, {SxProp} from './sx' import {FormValidationStatus} from './utils/types/FormValidationStatus' import {CheckboxGroupContext} from './CheckboxGroup' +import getGlobalFocusStyles from './_getGlobalFocusStyles' export type CheckboxProps = { /** @@ -38,6 +39,7 @@ const StyledCheckbox = styled.input` cursor: pointer; ${props => props.disabled && `cursor: not-allowed;`} + ${getGlobalFocusStyles(0)}; ${sx} ` diff --git a/src/Pagination/Pagination.tsx b/src/Pagination/Pagination.tsx index 7e521517150..cb16f146d46 100644 --- a/src/Pagination/Pagination.tsx +++ b/src/Pagination/Pagination.tsx @@ -38,9 +38,7 @@ const Page = styled.a` transition-duration: 0.1s; } - &:focus-visible { - ${getGlobalFocusStyles(0)}; - } + ${getGlobalFocusStyles(0)}; &:active { border-color: ${get('colors.border.muted')}; diff --git a/src/Radio.tsx b/src/Radio.tsx index 64616927adc..ee660497768 100644 --- a/src/Radio.tsx +++ b/src/Radio.tsx @@ -3,6 +3,7 @@ import React, {ChangeEventHandler, InputHTMLAttributes, ReactElement, useContext import sx, {SxProp} from './sx' import {FormValidationStatus} from './utils/types/FormValidationStatus' import {RadioGroupContext} from './RadioGroup' +import getGlobalFocusStyles from './_getGlobalFocusStyles' export type RadioProps = { /** @@ -41,6 +42,7 @@ const StyledRadio = styled.input` cursor: pointer; ${props => props.disabled && `cursor: not-allowed;`} + ${getGlobalFocusStyles(0)}; ${sx} ` diff --git a/src/TabNav.tsx b/src/TabNav.tsx index 9ba5940bbb5..dc7ff810571 100644 --- a/src/TabNav.tsx +++ b/src/TabNav.tsx @@ -50,9 +50,7 @@ const TabNavLink = styled.a.attrs(props => ({ border: 1px solid transparent; border-bottom: 0; - &:focus-visible { - ${getGlobalFocusStyles('-6px')}; - } + ${getGlobalFocusStyles('-6px')}; &:hover, &:focus { diff --git a/src/__tests__/Pagination/__snapshots__/Pagination.test.tsx.snap b/src/__tests__/Pagination/__snapshots__/Pagination.test.tsx.snap index 6e173bca839..089fa8da7f3 100644 --- a/src/__tests__/Pagination/__snapshots__/Pagination.test.tsx.snap +++ b/src/__tests__/Pagination/__snapshots__/Pagination.test.tsx.snap @@ -43,10 +43,20 @@ exports[`Pagination renders consistently 1`] = ` transition-duration: 0.1s; } +.c2:focus { + box-shadow: none; + outline: 2px solid #0969da; + outline-offset: 0; +} + +.c2:focus:not(:focus-visible) { + outline: solid 1px transparent; +} + .c2:focus-visible { box-shadow: none; outline: 2px solid #0969da; - outline-offset: 2px; + outline-offset: 0; } .c2:active { diff --git a/src/__tests__/__snapshots__/Checkbox.test.tsx.snap b/src/__tests__/__snapshots__/Checkbox.test.tsx.snap index 1f1f73e7285..87321f2c6b6 100644 --- a/src/__tests__/__snapshots__/Checkbox.test.tsx.snap +++ b/src/__tests__/__snapshots__/Checkbox.test.tsx.snap @@ -5,6 +5,22 @@ exports[`Checkbox renders consistently 1`] = ` cursor: pointer; } +.c0:focus { + box-shadow: none; + outline: 2px solid #0969da; + outline-offset: 0; +} + +.c0:focus:not(:focus-visible) { + outline: solid 1px transparent; +} + +.c0:focus-visible { + box-shadow: none; + outline: 2px solid #0969da; + outline-offset: 0; +} +