Skip to content

Commit 0f9edca

Browse files
authored
Finish updating global focus styles (#2050)
* updates focus styles that do not match the Primer CSS implementation * updates ThemeSwitcher to render ActionMenu instead of DropdownMenu * explicitly sets outline-offset in global focus styles instead of adding a new style that 'beats' the default 2px * update snapshots * fixes cross-browser issues for global focus styles * fixes unintentional laggy focus style update on SubNav * updates focus styles for UnderlineNav * DRY button focus styles * updates snapshots * adds changeset * fixes type error * revert themePreval snapshot update
1 parent 1c2eeb9 commit 0f9edca

29 files changed

+643
-322
lines changed

.changeset/silent-falcons-exist.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/react': patch
3+
---
4+
5+
Finishes updating components with the global focus styles defined in Primer CSS ([this PR](https://github.com/primer/css/pull/1744))

docs/content/SubNav.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ This ensures that the NavLink gets `activeClassName='selected'`
3939
<SubNav.Link href="#support">Support</SubNav.Link>
4040
</SubNav.Links>
4141

42-
<TextInput type="search" icon={SearchIcon} sx={{width: 320}} />
42+
<TextInput type="search" leadingVisual={SearchIcon} sx={{width: 320}} />
4343
</SubNav>
4444
```
4545

@@ -64,7 +64,7 @@ This ensures that the NavLink gets `activeClassName='selected'`
6464
</ActionList>
6565
</ActionMenu.Overlay>
6666
</ActionMenu>
67-
<TextInput type="search" icon={SearchIcon} width={320} />
67+
<TextInput type="search" leadingVisual={SearchIcon} width={320} />
6868
</FilteredSearch>
6969
<SubNav.Links>
7070
<SubNav.Link href="#home" selected>

docs/src/@primer/gatsby-theme-doctocat/components/live-preview-wrapper.js

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,33 @@
1-
import {BaseStyles, Box, ThemeProvider, useTheme} from '@primer/react'
2-
import {DropdownMenu, DropdownButton} from '@primer/react/deprecated'
31
import React from 'react'
2+
import {ActionMenu, ActionList, BaseStyles, Box, ThemeProvider, useTheme} from '@primer/react'
43

54
function ThemeSwitcher() {
65
const {theme, dayScheme, setDayScheme} = useTheme()
7-
const items = Object.keys(theme.colorSchemes).map(scheme => ({text: scheme.replace(/_/g, ' '), key: scheme}))
6+
const items = Object.keys(theme.colorSchemes).map(scheme => ({name: scheme.replace(/_/g, ' '), key: scheme}))
87
const selectedItem = React.useMemo(() => items.find(item => item.key === dayScheme), [items, dayScheme])
8+
const itemsKeys = items.map(item => item.key)
9+
const [selectedIndex, setSelectedIndex] = React.useState(itemsKeys.indexOf(dayScheme))
10+
911
return (
10-
<DropdownMenu
11-
renderAnchor={({children, ...anchorProps}) => (
12-
<DropdownButton {...anchorProps} sx={{variant: 'small'}}>
13-
{children}
14-
</DropdownButton>
15-
)}
16-
items={items}
17-
selectedItem={selectedItem}
18-
onChange={item => {
19-
setDayScheme(item.key)
20-
}}
21-
/>
12+
<ActionMenu>
13+
<ActionMenu.Button aria-label="Select field type">{selectedItem?.name}</ActionMenu.Button>
14+
<ActionMenu.Overlay width="medium">
15+
<ActionList selectionVariant="single">
16+
{items.map((type, index) => (
17+
<ActionList.Item
18+
key={index}
19+
selected={index === selectedIndex}
20+
onSelect={() => {
21+
setSelectedIndex(index)
22+
setDayScheme(items[index].key)
23+
}}
24+
>
25+
{type.name}
26+
</ActionList.Item>
27+
))}
28+
</ActionList>
29+
</ActionMenu.Overlay>
30+
</ActionMenu>
2231
)
2332
}
2433

src/Button/styles.ts

Lines changed: 1 addition & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,6 @@ import {VariantType} from './types'
22
import {Theme} from '../ThemeProvider'
33

44
export const TEXT_ROW_HEIGHT = '20px' // custom value off the scale
5-
const focusOutlineStyles = {
6-
outline: '2px solid',
7-
outlineColor: 'accent.fg',
8-
outlineOffset: '-2px'
9-
}
10-
const fallbackFocus = {
11-
...focusOutlineStyles,
12-
':not(:focus-visible)': {
13-
outline: 'solid 1px transparent'
14-
}
15-
}
165

176
export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme) => {
187
const style = {
@@ -23,11 +12,6 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
2312
'&:hover:not([disabled])': {
2413
backgroundColor: 'btn.hoverBg'
2514
},
26-
// focus must come before :active so that the active box shadow overrides
27-
'&:focus:not([disabled])': {
28-
...fallbackFocus
29-
},
30-
'&:focus-visible:not([disabled])': focusOutlineStyles,
3115
'&:active:not([disabled])': {
3216
backgroundColor: 'btn.activeBg',
3317
borderColor: 'btn.activeBorder'
@@ -52,13 +36,10 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
5236
color: 'btn.primary.hoverText',
5337
backgroundColor: 'btn.primary.hoverBg'
5438
},
55-
// focus must come before :active so that the active box shadow overrides
5639
'&:focus:not([disabled])': {
57-
boxShadow: 'inset 0 0 0 3px',
58-
...fallbackFocus
40+
boxShadow: 'inset 0 0 0 3px'
5941
},
6042
'&:focus-visible:not([disabled])': {
61-
...focusOutlineStyles,
6243
boxShadow: 'inset 0 0 0 3px'
6344
},
6445
'&:active:not([disabled])': {
@@ -95,11 +76,6 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
9576
color: 'btn.danger.hoverText'
9677
}
9778
},
98-
// focus must come before :active so that the active box shadow overrides
99-
'&:focus:not([disabled])': {
100-
...fallbackFocus
101-
},
102-
'&:focus-visible:not([disabled])': focusOutlineStyles,
10379
'&:active:not([disabled])': {
10480
color: 'btn.danger.selectedText',
10581
backgroundColor: 'btn.danger.selectedBg',
@@ -134,11 +110,6 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
134110
'&:hover:not([disabled])': {
135111
backgroundColor: 'btn.hoverBg'
136112
},
137-
// focus must come before :active so that the active box shadow overrides
138-
'&:focus:not([disabled])': {
139-
...fallbackFocus
140-
},
141-
'&:focus-visible:not([disabled])': focusOutlineStyles,
142113
'&:active:not([disabled])': {
143114
backgroundColor: 'btn.selectedBg'
144115
},
@@ -168,11 +139,6 @@ export const getVariantStyles = (variant: VariantType = 'default', theme?: Theme
168139
color: 'inherit'
169140
}
170141
},
171-
// focus must come before :active so that the active box shadow overrides
172-
'&:focus:not([disabled])': {
173-
...fallbackFocus
174-
},
175-
'&:focus-visible:not([disabled])': focusOutlineStyles,
176142
'&:active:not([disabled])': {
177143
color: 'btn.outline.selectedText',
178144
backgroundColor: 'btn.outline.selectedBg',

src/Button/types.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,12 @@ import React, {HTMLAttributes, ComponentPropsWithRef} from 'react'
22
import styled from 'styled-components'
33
import {IconProps} from '@primer/octicons-react'
44
import sx, {SxProp} from '../sx'
5+
import getGlobalFocusStyles from '../_getGlobalFocusStyles'
56

6-
export const StyledButton = styled.button<SxProp>(sx)
7+
export const StyledButton = styled.button<SxProp>`
8+
${getGlobalFocusStyles('-2px')};
9+
${sx};
10+
`
711

812
export type VariantType = 'default' | 'primary' | 'invisible' | 'danger' | 'outline'
913

src/Checkbox.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import React, {ChangeEventHandler, InputHTMLAttributes, ReactElement, useContext
44
import sx, {SxProp} from './sx'
55
import {FormValidationStatus} from './utils/types/FormValidationStatus'
66
import {CheckboxGroupContext} from './CheckboxGroup'
7+
import getGlobalFocusStyles from './_getGlobalFocusStyles'
78

89
export type CheckboxProps = {
910
/**
@@ -38,6 +39,7 @@ const StyledCheckbox = styled.input`
3839
cursor: pointer;
3940
4041
${props => props.disabled && `cursor: not-allowed;`}
42+
${getGlobalFocusStyles(0)};
4143
4244
${sx}
4345
`

src/Pagination/Pagination.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import styled from 'styled-components'
33
import Box from '../Box'
44
import {get} from '../constants'
55
import sx, {SxProp} from '../sx'
6+
import getGlobalFocusStyles from '../_getGlobalFocusStyles'
67
import {buildComponentData, buildPaginationModel} from './model'
78

89
const Page = styled.a`
@@ -37,6 +38,8 @@ const Page = styled.a`
3738
transition-duration: 0.1s;
3839
}
3940
41+
${getGlobalFocusStyles(0)};
42+
4043
&:active {
4144
border-color: ${get('colors.border.muted')};
4245
}

src/Radio.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import React, {ChangeEventHandler, InputHTMLAttributes, ReactElement, useContext
33
import sx, {SxProp} from './sx'
44
import {FormValidationStatus} from './utils/types/FormValidationStatus'
55
import {RadioGroupContext} from './RadioGroup'
6+
import getGlobalFocusStyles from './_getGlobalFocusStyles'
67

78
export type RadioProps = {
89
/**
@@ -41,6 +42,7 @@ const StyledRadio = styled.input`
4142
cursor: pointer;
4243
4344
${props => props.disabled && `cursor: not-allowed;`}
45+
${getGlobalFocusStyles(0)};
4446
4547
${sx}
4648
`

src/SubNav.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ const SubNavLink = styled.a.attrs<StyledSubNavLinkProps>(props => ({
9696
&:focus {
9797
text-decoration: none;
9898
background-color: ${get('colors.canvas.subtle')};
99-
transition: 0.2s ease;
99+
transition: background-color 0.2s ease;
100100
101101
.SubNav-octicon {
102102
color: ${get('colors.fg.muted')};

src/TabNav.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import styled from 'styled-components'
55
import {get} from './constants'
66
import sx, {SxProp} from './sx'
77
import {ComponentProps} from './utils/types'
8+
import getGlobalFocusStyles from './_getGlobalFocusStyles'
89

910
const ITEM_CLASS = 'TabNav-item'
1011
const SELECTED_CLASS = 'selected'
@@ -49,6 +50,8 @@ const TabNavLink = styled.a.attrs<StyledTabNavLinkProps>(props => ({
4950
border: 1px solid transparent;
5051
border-bottom: 0;
5152
53+
${getGlobalFocusStyles('-6px')};
54+
5255
&:hover,
5356
&:focus {
5457
color: ${get('colors.fg.default')};

0 commit comments

Comments
 (0)