Skip to content

Commit 26d69c2

Browse files
asynclizcopybara-github
authored andcommitted
fix(focus)!: corrected outward/inward animations
BREAKING CHANGE: inward focus rings must be specified with `inward` rather than a negative offset. PiperOrigin-RevId: 534552625
1 parent 146aa17 commit 26d69c2

File tree

16 files changed

+118
-50
lines changed

16 files changed

+118
-50
lines changed

checkbox/lib/_checkbox.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ $_checkmark-bottom-left: 7px, -14px;
8686

8787
@include focus-ring.theme(
8888
(
89-
'offset': -2px,
89+
'outward-offset': -2px,
9090
)
9191
);
9292
}

chips/lib/_trailing-icon.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
'shape-end-start': var(--_container-shape-end-end),
2222
'shape-end-end': var(--_container-shape-end-end),
2323
'shape-start-end': var(--_container-shape-start-end),
24-
'offset': -2px,
24+
'outward-offset': -2px,
2525
)
2626
);
2727
}

fab/lib/forced-colors-styles.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
// Adjust the focus ring padding to account for the 1px border in HCM.
1313
@include focus-ring.theme(
1414
(
15-
'offset': 3px,
15+
'outward-offset': 3px,
1616
)
1717
);
1818
border: 1px solid ButtonText;

focus/demo/demo.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,25 @@ import './index.js';
88
import './material-collection.js';
99

1010
import {KnobTypesToKnobs, MaterialCollection, materialInitsToStoryInits, setUpDemo} from './material-collection.js';
11-
import {cssCustomProperty, Knob, textInput} from './index.js';
11+
import {boolInput, cssCustomProperty, Knob, textInput} from './index.js';
1212

1313
import {stories, StoryKnobs} from './stories.js';
1414

1515
const collection =
1616
new MaterialCollection<KnobTypesToKnobs<StoryKnobs>>('Focus', [
17+
new Knob('inward', {ui: boolInput(), defaultValue: false}),
1718
new Knob(
1819
'--md-focus-ring-width',
1920
{ui: textInput(), wiring: cssCustomProperty, defaultValue: '3px'}),
20-
new Knob(
21-
'--md-focus-ring-offset',
22-
{ui: textInput(), wiring: cssCustomProperty, defaultValue: '2px'}),
2321
new Knob(
2422
'--md-focus-ring-active-width',
2523
{ui: textInput(), wiring: cssCustomProperty, defaultValue: '8px'}),
24+
new Knob(
25+
'--md-focus-ring-outward-offset',
26+
{ui: textInput(), wiring: cssCustomProperty, defaultValue: '2px'}),
27+
new Knob(
28+
'--md-focus-ring-inward-offset',
29+
{ui: textInput(), wiring: cssCustomProperty, defaultValue: '0px'}),
2630
]);
2731

2832
collection.addStories(...materialInitsToStoryInits(stories));

focus/demo/stories.ts

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@ import {css, html} from 'lit';
1111

1212
/** Knob types for focus ring stories. */
1313
export interface StoryKnobs {
14+
inward: boolean;
1415
'--md-focus-ring-width': string;
15-
'--md-focus-ring-offset': string;
1616
'--md-focus-ring-active-width': string;
17+
'--md-focus-ring-outward-offset': string;
18+
'--md-focus-ring-inward-offset': string;
1719
}
1820

1921
const standard: MaterialStoryInit<StoryKnobs> = {
@@ -22,7 +24,7 @@ const standard: MaterialStoryInit<StoryKnobs> = {
2224
button {
2325
appearance: none;
2426
background: var(--md-sys-color-surface);
25-
border: 1px solid var(--md-sys-color-outline);
27+
border: none;
2628
border-radius: 16px;
2729
--md-focus-ring-shape: 16px;
2830
height: 64px;
@@ -33,20 +35,28 @@ const standard: MaterialStoryInit<StoryKnobs> = {
3335
width: 64px;
3436
}
3537
38+
button::before {
39+
border: 1px solid var(--md-sys-color-outline);
40+
border-radius: inherit;
41+
content: '';
42+
inset: 0;
43+
position: absolute;
44+
}
45+
3646
button:focus {
3747
background: var(--md-sys-color-surface-variant);
3848
}
3949
`,
40-
render() {
50+
render({inward}) {
4151
return html`
4252
<button aria-label="A button with a focus ring">
43-
<md-focus-ring></md-focus-ring>
53+
<md-focus-ring ?inward=${inward}></md-focus-ring>
4454
</button>
4555
<button aria-label="A button with a focus ring">
46-
<md-focus-ring></md-focus-ring>
56+
<md-focus-ring ?inward=${inward}></md-focus-ring>
4757
</button>
4858
<button aria-label="A button with a focus ring">
49-
<md-focus-ring></md-focus-ring>
59+
<md-focus-ring ?inward=${inward}></md-focus-ring>
5060
</button>
5161
`;
5262
}
@@ -59,7 +69,6 @@ const multiAction: MaterialStoryInit<StoryKnobs> = {
5969
align-items: center;
6070
appearance: none;
6171
background: var(--md-sys-color-surface);
62-
border: 1px solid var(--md-sys-color-outline);
6372
border-radius: 16px;
6473
--md-focus-ring-shape: 16px;
6574
display: flex;
@@ -94,17 +103,25 @@ const multiAction: MaterialStoryInit<StoryKnobs> = {
94103
}
95104
96105
#secondary {
97-
border: 1px solid var(--md-sys-color-outline);
98106
height: 32px;
99107
width: 32px;
100108
border-radius: 32px;
101109
--md-focus-ring-shape: 32px;
102110
}
111+
112+
[role="list"]::before,
113+
#secondary::before {
114+
border: 1px solid var(--md-sys-color-outline);
115+
border-radius: inherit;
116+
content: '';
117+
inset: 0;
118+
position: absolute;
119+
}
103120
`,
104-
render() {
121+
render({inward}) {
105122
return html`
106123
<div role="list">
107-
<md-focus-ring for="primary"></md-focus-ring>
124+
<md-focus-ring for="primary" ?inward=${inward}></md-focus-ring>
108125
109126
<div role="listitem">
110127
<button id="primary" aria-label="The primary action for a multi-action component">
@@ -115,7 +132,7 @@ const multiAction: MaterialStoryInit<StoryKnobs> = {
115132
<div role="listitem">
116133
<button id="secondary" aria-label="The secondary action for a multi-action component">
117134
X
118-
<md-focus-ring></md-focus-ring>
135+
<md-focus-ring ?inward=${inward}></md-focus-ring>
119136
</button>
120137
</div>
121138
</div>

focus/lib/_focus-ring.scss

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -44,37 +44,80 @@ $_md-sys-motion: tokens.md-sys-motion-values();
4444
--_shape-end-end: var(--md-focus-ring-shape-end-end, var(--_shape));
4545
--_shape-end-start: var(--md-focus-ring-shape-end-start, var(--_shape));
4646

47-
animation-duration: var(--_duration);
47+
animation-delay: 0s, calc(var(--_duration) * 0.25);
48+
animation-duration: calc(var(--_duration) * 0.25),
49+
calc(var(--_duration) * 0.75);
4850
animation-timing-function: map.get($_md-sys-motion, 'easing-emphasized');
49-
border-end-end-radius: calc(var(--_offset) + var(--_shape-end-end));
50-
border-end-start-radius: calc(var(--_offset) + var(--_shape-end-start));
51-
border-start-end-radius: calc(var(--_offset) + var(--_shape-start-end));
52-
border-start-start-radius: calc(var(--_offset) + var(--_shape-start-start));
53-
box-shadow: inset 0 0 0 0 currentColor;
5451
box-sizing: border-box;
5552
color: var(--_color);
5653
display: none;
57-
inset: calc(-1 * (var(--_offset) + 1px));
58-
// NOTE: this 1px offset hides a transparent ring between the outline and
59-
// offset when border-radius is large
60-
outline-offset: -1px;
61-
outline: var(--_width) solid currentColor;
6254
pointer-events: none;
6355
position: absolute;
6456
}
6557

6658
:host([visible]) {
6759
display: flex;
68-
animation-name: focus-ring;
6960
}
7061

71-
@keyframes focus-ring {
62+
:host(:not([inward])) {
63+
animation-name: outward-grow, outward-shrink;
64+
border-end-end-radius: calc(var(--_shape-end-end) + var(--_outward-offset));
65+
border-end-start-radius: calc(
66+
var(--_shape-end-start) + var(--_outward-offset)
67+
);
68+
border-start-end-radius: calc(
69+
var(--_shape-start-end) + var(--_outward-offset)
70+
);
71+
border-start-start-radius: calc(
72+
var(--_shape-start-start) + var(--_outward-offset)
73+
);
74+
inset: calc(-1 * (var(--_outward-offset)));
75+
outline: var(--_width) solid currentColor;
76+
}
77+
78+
:host([inward]) {
79+
animation-name: inward-grow, inward-shrink;
80+
border-end-end-radius: calc(var(--_shape-end-end) - var(--_inward-offset));
81+
border-end-start-radius: calc(
82+
var(--_shape-end-start) - var(--_inward-offset)
83+
);
84+
border-start-end-radius: calc(
85+
var(--_shape-start-end) - var(--_inward-offset)
86+
);
87+
border-start-start-radius: calc(
88+
var(--_shape-start-start) - var(--_inward-offset)
89+
);
90+
border: var(--_width) solid currentColor;
91+
inset: var(--_inward-offset);
92+
}
93+
94+
@keyframes outward-grow {
7295
from {
73-
outline-width: 0px;
96+
outline-width: 0;
97+
}
98+
to {
99+
outline-width: var(--_active-width);
74100
}
75-
25% {
76-
box-shadow: inset 0 0 0 calc(var(--_active-width) / 2) currentColor;
77-
outline-width: calc(var(--_active-width) / 2);
101+
}
102+
103+
@keyframes outward-shrink {
104+
from {
105+
outline-width: var(--_active-width);
106+
}
107+
}
108+
109+
@keyframes inward-grow {
110+
from {
111+
border-width: 0;
112+
}
113+
to {
114+
border-width: var(--_active-width);
115+
}
116+
}
117+
118+
@keyframes inward-shrink {
119+
from {
120+
border-width: var(--_active-width);
78121
}
79122
}
80123

focus/lib/focus-ring.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export class FocusRing extends LitElement {
1515
* Makes the focus ring visible.
1616
*/
1717
@property({type: Boolean, reflect: true}) visible = false;
18+
@property({type: Boolean, reflect: true}) inward = false;
1819

1920
/**
2021
* Reflects the value of the `for` attribute, which is the ID of the focus

list/lib/listitem/_list-item.scss

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@
4747

4848
@include focus-ring.theme(
4949
(
50-
'offset': -3px,
51-
'shape': map.get(tokens.md-sys-shape-values(), 'corner-extra-small'),
50+
'shape': 8px,
5251
)
5352
);
5453
@include ripple.theme(

list/lib/listitem/list-item.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ export class ListItemEl extends LitElement implements ListItem {
159159
* Handles rendering of the focus ring.
160160
*/
161161
protected renderFocusRing() {
162-
return html`<md-focus-ring class="focus-ring" for="item"></md-focus-ring>`;
162+
return html`<md-focus-ring class="focus-ring" for="item" inward></md-focus-ring>`;
163163
}
164164

165165
/**

navigationtab/lib/_navigation-tab.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ $_custom-property-prefix: 'navigation-bar';
4343

4444
@include focus-ring.theme(
4545
(
46-
'offset': -2px,
4746
'shape': map.get(tokens.md-sys-shape-values(), 'corner-small'),
47+
'inward-offset': -1px,
4848
)
4949
);
5050

0 commit comments

Comments
 (0)