Skip to content
This repository was archived by the owner on Nov 16, 2023. It is now read-only.

Commit 5b54c09

Browse files
BrendanMcKswese44
authored andcommitted
feat(focus): Add focus outlines to NavigationLink and Clickable (#522)
* feat(focus): Add focus outlines to NavigationLink and Clickable Add focusOutlines style helper that returns styles that NaviagionLink and Clickable merge into their own styles. Initial version is provididing just a basic box-shadow-based outline, only showing it when needed. We avoid using Office UI Fabric's focus styles, as they assume block elements, and don't work well on non-block links that wrap. Can consider switching to their style in future if they resolve that issue (microsoft/fluentui#4883) Later commit will also add option to use a overlay focus style, which is needed for links and buttons that contain images or other content that covers their surface area competely - main use case there is for eg. images in a gif picker, or image attachments. * Update visual diff snapshots
1 parent d0d5340 commit 5b54c09

17 files changed

+222
-32
lines changed
Loading
Loading
Loading
Loading
Loading
Loading
Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*! Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. */
22
import { mergeStyleSets, ITheme } from 'office-ui-fabric-react/lib/Styling';
33
import { memoizeFunction } from 'office-ui-fabric-react/lib/Utilities';
4+
import { getNormalFocusStyle } from '../../util/styles/focusOutlines';
45

56
export interface ClickableStyleProps {
67
block?: boolean;
@@ -10,30 +11,35 @@ export interface ClickableStyleProps {
1011
export const getClassNames = memoizeFunction((styleProps: ClickableStyleProps) => {
1112
const { block, theme } = styleProps;
1213

14+
const focusOutlineStyles = getNormalFocusStyle();
15+
1316
return mergeStyleSets({
14-
root: {
15-
color: 'inherit',
16-
font: 'inherit',
17-
margin: 0,
18-
padding: 0,
19-
textAlign: 'inherit',
20-
lineHeight: 'inherit',
21-
background: 'none',
22-
overflow: 'visible',
23-
border: 'none',
24-
cursor: 'pointer',
25-
display: block ? 'block' : 'inline',
26-
width: block ? '100%' : 'undefined',
27-
selectors: {
28-
'> .y-block': {
29-
width: '100%',
30-
},
31-
'&:active .y-fakeLink, &:focus .y-fakeLink, &:hover .y-fakeLink': {
32-
textDecoration: 'underline',
33-
cursor: 'pointer',
34-
color: theme.semanticColors.linkHovered,
17+
root: [
18+
{
19+
color: 'inherit',
20+
font: 'inherit',
21+
margin: 0,
22+
padding: 0,
23+
textAlign: 'inherit',
24+
lineHeight: 'inherit',
25+
background: 'none',
26+
overflow: 'visible',
27+
border: 'none',
28+
cursor: 'pointer',
29+
display: block ? 'block' : 'inline',
30+
width: block ? '100%' : 'undefined',
31+
selectors: {
32+
'> .y-block': {
33+
width: '100%',
34+
},
35+
'&:active .y-fakeLink, &:focus .y-fakeLink, &:hover .y-fakeLink': {
36+
textDecoration: 'underline',
37+
cursor: 'pointer',
38+
color: theme.semanticColors.linkHovered,
39+
},
3540
},
3641
},
37-
},
42+
focusOutlineStyles,
43+
],
3844
});
3945
});

src/components/Clickable/__snapshots__/Clickable.test.tsx.snap

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ exports[`<Clickable /> when ariaLabel is passed matches its snapshot 1`] = `
1717
margin-left: 0px;
1818
margin-right: 0px;
1919
margin-top: 0px;
20+
outline: none;
2021
overflow: visible;
2122
padding-bottom: 0px;
2223
padding-left: 0px;
@@ -33,6 +34,12 @@ exports[`<Clickable /> when ariaLabel is passed matches its snapshot 1`] = `
3334
cursor: pointer;
3435
text-decoration: underline;
3536
}
37+
.ms-Fabric--isFocusVisible &:focus {
38+
box-shadow: inset 0 0 0 1px;
39+
}
40+
@media screen and (-ms-high-contrast: active){.ms-Fabric--isFocusVisible &:focus {
41+
box-shadow: inset 0 0 0 1px;
42+
}
3643
type="button"
3744
>
3845
<span
@@ -71,6 +78,7 @@ exports[`<Clickable /> when block is true matches its snapshot 1`] = `
7178
margin-left: 0px;
7279
margin-right: 0px;
7380
margin-top: 0px;
81+
outline: none;
7482
overflow: visible;
7583
padding-bottom: 0px;
7684
padding-left: 0px;
@@ -87,6 +95,12 @@ exports[`<Clickable /> when block is true matches its snapshot 1`] = `
8795
cursor: pointer;
8896
text-decoration: underline;
8997
}
98+
.ms-Fabric--isFocusVisible &:focus {
99+
box-shadow: inset 0 0 0 1px;
100+
}
101+
@media screen and (-ms-high-contrast: active){.ms-Fabric--isFocusVisible &:focus {
102+
box-shadow: inset 0 0 0 1px;
103+
}
90104
type="button"
91105
>
92106
<span
@@ -125,6 +139,7 @@ exports[`<Clickable /> when focusableRef is passed matches its snapshot 1`] = `
125139
margin-left: 0px;
126140
margin-right: 0px;
127141
margin-top: 0px;
142+
outline: none;
128143
overflow: visible;
129144
padding-bottom: 0px;
130145
padding-left: 0px;
@@ -141,6 +156,12 @@ exports[`<Clickable /> when focusableRef is passed matches its snapshot 1`] = `
141156
cursor: pointer;
142157
text-decoration: underline;
143158
}
159+
.ms-Fabric--isFocusVisible &:focus {
160+
box-shadow: inset 0 0 0 1px;
161+
}
162+
@media screen and (-ms-high-contrast: active){.ms-Fabric--isFocusVisible &:focus {
163+
box-shadow: inset 0 0 0 1px;
164+
}
144165
type="button"
145166
>
146167
<span
@@ -179,6 +200,7 @@ exports[`<Clickable /> when title is passed matches its snapshot 1`] = `
179200
margin-left: 0px;
180201
margin-right: 0px;
181202
margin-top: 0px;
203+
outline: none;
182204
overflow: visible;
183205
padding-bottom: 0px;
184206
padding-left: 0px;
@@ -195,6 +217,12 @@ exports[`<Clickable /> when title is passed matches its snapshot 1`] = `
195217
cursor: pointer;
196218
text-decoration: underline;
197219
}
220+
.ms-Fabric--isFocusVisible &:focus {
221+
box-shadow: inset 0 0 0 1px;
222+
}
223+
@media screen and (-ms-high-contrast: active){.ms-Fabric--isFocusVisible &:focus {
224+
box-shadow: inset 0 0 0 1px;
225+
}
198226
title="extra browser tooltip content"
199227
type="button"
200228
>
@@ -234,6 +262,7 @@ exports[`<Clickable /> when unstyled matches its snapshot 1`] = `
234262
margin-left: 0px;
235263
margin-right: 0px;
236264
margin-top: 0px;
265+
outline: none;
237266
overflow: visible;
238267
padding-bottom: 0px;
239268
padding-left: 0px;
@@ -250,6 +279,12 @@ exports[`<Clickable /> when unstyled matches its snapshot 1`] = `
250279
cursor: pointer;
251280
text-decoration: underline;
252281
}
282+
.ms-Fabric--isFocusVisible &:focus {
283+
box-shadow: inset 0 0 0 1px;
284+
}
285+
@media screen and (-ms-high-contrast: active){.ms-Fabric--isFocusVisible &:focus {
286+
box-shadow: inset 0 0 0 1px;
287+
}
253288
type="button"
254289
>
255290
clickable content
@@ -273,6 +308,7 @@ exports[`<Clickable /> with additional className matches its snapshot 1`] = `
273308
margin-left: 0px;
274309
margin-right: 0px;
275310
margin-top: 0px;
311+
outline: none;
276312
overflow: visible;
277313
padding-bottom: 0px;
278314
padding-left: 0px;
@@ -289,6 +325,12 @@ exports[`<Clickable /> with additional className matches its snapshot 1`] = `
289325
cursor: pointer;
290326
text-decoration: underline;
291327
}
328+
.ms-Fabric--isFocusVisible &:focus {
329+
box-shadow: inset 0 0 0 1px;
330+
}
331+
@media screen and (-ms-high-contrast: active){.ms-Fabric--isFocusVisible &:focus {
332+
box-shadow: inset 0 0 0 1px;
333+
}
292334
type="button"
293335
>
294336
<span
@@ -327,6 +369,7 @@ exports[`<Clickable /> with default options matches its snapshot 1`] = `
327369
margin-left: 0px;
328370
margin-right: 0px;
329371
margin-top: 0px;
372+
outline: none;
330373
overflow: visible;
331374
padding-bottom: 0px;
332375
padding-left: 0px;
@@ -343,6 +386,12 @@ exports[`<Clickable /> with default options matches its snapshot 1`] = `
343386
cursor: pointer;
344387
text-decoration: underline;
345388
}
389+
.ms-Fabric--isFocusVisible &:focus {
390+
box-shadow: inset 0 0 0 1px;
391+
}
392+
@media screen and (-ms-high-contrast: active){.ms-Fabric--isFocusVisible &:focus {
393+
box-shadow: inset 0 0 0 1px;
394+
}
346395
type="button"
347396
>
348397
<span
@@ -381,6 +430,7 @@ exports[`<Clickable /> with theme matches its snapshot 1`] = `
381430
margin-left: 0px;
382431
margin-right: 0px;
383432
margin-top: 0px;
433+
outline: none;
384434
overflow: visible;
385435
padding-bottom: 0px;
386436
padding-left: 0px;
@@ -397,6 +447,12 @@ exports[`<Clickable /> with theme matches its snapshot 1`] = `
397447
cursor: pointer;
398448
text-decoration: underline;
399449
}
450+
.ms-Fabric--isFocusVisible &:focus {
451+
box-shadow: inset 0 0 0 1px;
452+
}
453+
@media screen and (-ms-high-contrast: active){.ms-Fabric--isFocusVisible &:focus {
454+
box-shadow: inset 0 0 0 1px;
455+
}
400456
type="button"
401457
>
402458
<span

src/components/NavigationLink/NavigationLink.styles.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*! Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. */
22
import { mergeStyleSets, ITheme } from 'office-ui-fabric-react/lib/Styling';
33
import { memoizeFunction } from 'office-ui-fabric-react/lib/Utilities';
4+
import { getNormalFocusStyle } from '../../util/styles/focusOutlines';
45

56
export interface NavigationLinkStyleProps {
67
block?: boolean;
@@ -23,16 +24,20 @@ export const getClassNames = memoizeFunction((styleProps: NavigationLinkStylePro
2324
color: theme.semanticColors.linkHovered,
2425
};
2526

26-
return mergeStyleSets({
27-
root: {
28-
display: block ? 'block' : undefined,
29-
cursor: 'pointer',
30-
color: unstyled ? 'inherit' : theme.semanticColors.link,
31-
textDecoration: 'none',
32-
selectors: {
33-
'&:active, &:focus, &:hover': overrides,
34-
'&:active .y-fakeLink, &:focus .y-fakeLink, &:hover .y-fakeLink': overrides,
35-
},
27+
const baseStyles = {
28+
display: block ? 'block' : undefined,
29+
cursor: 'pointer',
30+
color: unstyled ? 'inherit' : theme.semanticColors.link,
31+
textDecoration: 'none',
32+
selectors: {
33+
'&:active, &:focus, &:hover': overrides,
34+
'&:active .y-fakeLink, &:focus .y-fakeLink, &:hover .y-fakeLink': overrides,
3635
},
36+
};
37+
38+
const focusOutlineStyles = getNormalFocusStyle();
39+
40+
return mergeStyleSets({
41+
root: [baseStyles, focusOutlineStyles],
3742
});
3843
});

0 commit comments

Comments
 (0)