Skip to content

Commit

Permalink
feat: implement :focus-visible for the Button component with target…
Browse files Browse the repository at this point in the history
…ed focus style for non-pointer devices
  • Loading branch information
cheton committed Oct 8, 2023
1 parent 4a9d833 commit b68de49
Show file tree
Hide file tree
Showing 4 changed files with 62 additions and 70 deletions.
80 changes: 42 additions & 38 deletions packages/react/src/button/styles.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,20 @@ const defaultVariantStyle = ({
light: 'gray:30',
}[colorMode];
// Focus
const focusBorderColor = {
const focusVisibleBorderColor = {
dark: 'blue:60',
light: 'blue:60',
}[colorMode];
const focusBoxShadowOuterColor = {
dark: theme?.colors?.['blue:60'],
light: theme?.colors?.['blue:60'],
const focusVisibleBoxShadowOuterColor = {
dark: 'blue:60',
light: 'blue:60',
}[colorMode];
const focusBoxShadowOuterSpreadRadius = theme?.sizes?.['1q'];
const focusBoxShadowInnerColor = {
dark: theme?.colors?.['black:emphasis'],
light: theme?.colors?.['white:emphasis'],
const focusVisibleBoxShadowOuterSpreadRadius = '1q';
const focusVisibleBoxShadowInnerColor = {
dark: 'black:emphasis',
light: 'white:emphasis',
}[colorMode];
const focusBoxShadowInnerSpreadRadius = theme?.sizes?.['2q'];
const focusVisibleBoxShadowInnerSpreadRadius = '2q';
// Disabled
const disabledBackgroundColor = {
dark: 'gray:60',
Expand Down Expand Up @@ -69,11 +69,12 @@ const defaultVariantStyle = ({
backgroundColor,
borderColor: 'transparent',
color,
_focus: {
':not(:active)': {
borderColor: focusBorderColor,
boxShadow: `inset 0 0 0 ${focusBoxShadowOuterSpreadRadius} ${focusBoxShadowOuterColor}, inset 0 0 0 ${focusBoxShadowInnerSpreadRadius} ${focusBoxShadowInnerColor}`,
},
_focusVisible: {
borderColor: focusVisibleBorderColor,
boxShadow: [
`inset 0 0 0 ${theme?.sizes?.[focusVisibleBoxShadowOuterSpreadRadius]} ${theme?.colors?.[focusVisibleBoxShadowOuterColor]}`,
`inset 0 0 0 ${theme?.sizes?.[focusVisibleBoxShadowInnerSpreadRadius]} ${theme?.colors?.[focusVisibleBoxShadowInnerColor]}`,
].join(', '),
// Bring overlapping border to front when focused
zIndex: 1,
},
Expand Down Expand Up @@ -130,16 +131,15 @@ const secondaryVariantStyle = ({
const activeBorderColor = hoverBorderColor;
const activeColor = hoverColor;
// Focus
const focusBorderColor = {
const focusVisibleBorderColor = {
dark: 'blue:60',
light: 'blue:60',
}[colorMode];
const focusBoxShadowColor = {
dark: theme?.colors?.['blue:60'],
light: theme?.colors?.['blue:60'],
const focusVisibleBoxShadowColor = {
dark: 'blue:60',
light: 'blue:60',
}[colorMode];
const focusBoxShadowSpreadRadius = theme?.sizes?.['1q'];
const focusColor = color;
const focusVisibleBoxShadowSpreadRadius = '1q';
// Disabled
const disabledBorderColor = borderColor;
const disabledColor = {
Expand All @@ -163,16 +163,15 @@ const secondaryVariantStyle = ({
return {
borderColor,
color,
_focus: {
borderColor: focusBorderColor,
boxShadow: `inset 0 0 0 ${focusBoxShadowSpreadRadius} ${focusBoxShadowColor}`,
color: focusColor,
_focusVisible: {
borderColor: focusVisibleBorderColor,
boxShadow: `inset 0 0 0 ${theme?.sizes?.[focusVisibleBoxShadowSpreadRadius]} ${theme?.colors?.[focusVisibleBoxShadowColor]}`,
// Bring overlapping border to front when focused
zIndex: 1,
},
_hover: {
color: hoverColor,
'&:not(:focus)': {
'&:not(:focus-visible)': {
borderColor: hoverBorderColor,
},
// Use a higher z-index value to bring overlapping border to front when hovered
Expand Down Expand Up @@ -263,16 +262,20 @@ const fillColorVariantStyle = ({
light: `${colorProp}:70`,
}[colorMode];
// Focus
const focusBorderColor = {
dark: theme?.colors?.['blue:60'],
light: theme?.colors?.['blue:60'],
const focusVisibleBorderColor = {
dark: 'blue:60',
light: 'blue:60',
}[colorMode];
const focusVisibleBoxShadowOuterColor = {
dark: 'blue:60',
light: 'blue:60',
}[colorMode];
const focusBoxShadowSpreadRadius = theme?.sizes?.['1q'];
const boxShadowColor = {
dark: theme?.colors?.['black:emphasis'],
light: theme?.colors?.['white:emphasis'],
const focusVisibleBoxShadowOuterSpreadRadius = '1q';
const focusVisibleBoxShadowInnerColor = {
dark: 'black:emphasis',
light: 'white:emphasis',
}[colorMode];
const boxShadowSpreadRadius = theme?.sizes?.['2q'];
const focusVisibleBoxShadowInnerSpreadRadius = '2q';
// Disabled
const disabledBackgroundColor = {
dark: 'gray:60',
Expand Down Expand Up @@ -300,11 +303,12 @@ const fillColorVariantStyle = ({
backgroundColor,
borderColor: 'transparent',
color,
_focus: {
':not(:active)': {
borderColor: focusBorderColor,
boxShadow: `inset 0 0 0 ${focusBoxShadowSpreadRadius} ${focusBorderColor}, inset 0 0 0 ${boxShadowSpreadRadius} ${boxShadowColor}`,
},
_focusVisible: {
borderColor: focusVisibleBorderColor,
boxShadow: [
`inset 0 0 0 ${theme?.sizes?.[focusVisibleBoxShadowOuterSpreadRadius]} ${theme?.colors?.[focusVisibleBoxShadowOuterColor]}`,
`inset 0 0 0 ${theme?.sizes?.[focusVisibleBoxShadowInnerSpreadRadius]} ${theme?.colors?.[focusVisibleBoxShadowInnerColor]}`,
].join(', '),
// Bring overlapping border to front when focused
zIndex: 1,
},
Expand Down
18 changes: 8 additions & 10 deletions packages/react/src/menu/__tests__/__snapshots__/Menu.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -49,29 +49,27 @@ exports[`Menu should render correctly 1`] = `
column-gap: var(--tonic-sizes-1x);
}
.emotion-2:focus-visible {
border-color: var(--tonic-colors-blue-60);
box-shadow: inset 0 0 0 .0625rem #1e5ede;
z-index: 1;
}
.emotion-2[aria-selected=true],
.emotion-2[data-selected] {
background-color: var(--tonic-colors-gray-70);
color: var(--tonic-colors-white-emphasis);
pointer-events: none;
}
.emotion-2:focus,
.emotion-2[data-focus] {
border-color: var(--tonic-colors-blue-60);
box-shadow: inset 0 0 0 .0625rem #1e5ede;
color: var(--tonic-colors-white-primary);
z-index: 1;
}
.emotion-2:hover,
.emotion-2[data-hover] {
color: var(--tonic-colors-blue-40);
z-index: 2;
}
.emotion-2:hover:not(:focus),
.emotion-2[data-hover]:not(:focus) {
.emotion-2:hover:not(:focus-visible),
.emotion-2[data-hover]:not(:focus-visible) {
border-color: var(--tonic-colors-blue-50);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,19 @@ exports[`Popover should render correctly 1`] = `
border-color: var(--tonic-colors-transparent);
}
.emotion-0:focus-visible {
border-color: var(--tonic-colors-blue-60);
box-shadow: inset 0 0 0 .0625rem #1e5ede,inset 0 0 0 .125rem rgba(0, 0, 0, 1.0);
z-index: 1;
}
.emotion-0[aria-selected=true],
.emotion-0[data-selected] {
background-color: var(--tonic-colors-gray-70);
color: var(--tonic-colors-white-emphasis);
pointer-events: none;
}
.emotion-0:focus,
.emotion-0[data-focus] {
z-index: 1;
}
.emotion-0:focus:not(:active),
.emotion-0[data-focus]:not(:active) {
border-color: var(--tonic-colors-blue-60);
box-shadow: inset 0 0 0 .0625rem #1e5ede,inset 0 0 0 .125rem rgba(0, 0, 0, 1.0);
}
.emotion-0:hover,
.emotion-0[data-hover] {
background-color: var(--tonic-colors-gray-50);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,24 +40,19 @@ exports[`Tooltip should render correctly 1`] = `
border-color: var(--tonic-colors-transparent);
}
.emotion-0:focus-visible {
border-color: var(--tonic-colors-blue-60);
box-shadow: inset 0 0 0 .0625rem #1e5ede,inset 0 0 0 .125rem rgba(0, 0, 0, 1.0);
z-index: 1;
}
.emotion-0[aria-selected=true],
.emotion-0[data-selected] {
background-color: var(--tonic-colors-gray-70);
color: var(--tonic-colors-white-emphasis);
pointer-events: none;
}
.emotion-0:focus,
.emotion-0[data-focus] {
z-index: 1;
}
.emotion-0:focus:not(:active),
.emotion-0[data-focus]:not(:active) {
border-color: var(--tonic-colors-blue-60);
box-shadow: inset 0 0 0 .0625rem #1e5ede,inset 0 0 0 .125rem rgba(0, 0, 0, 1.0);
}
.emotion-0:hover,
.emotion-0[data-hover] {
background-color: var(--tonic-colors-gray-50);
Expand Down

0 comments on commit b68de49

Please sign in to comment.