Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.

Commit 3fb3a02

Browse files
allan-chencopybara-github
authored andcommitted
refactor(button): introduce theme config for text button
PiperOrigin-RevId: 353122075
1 parent fd61b04 commit 3fb3a02

12 files changed

+973
-595
lines changed

packages/mdc-button/_button-base.scss

Lines changed: 213 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,213 @@
1+
//
2+
// Copyright 2020 Google Inc.
3+
//
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy
5+
// of this software and associated documentation files (the "Software"), to deal
6+
// in the Software without restriction, including without limitation the rights
7+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
// copies of the Software, and to permit persons to whom the Software is
9+
// furnished to do so, subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included in
12+
// all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
// THE SOFTWARE.
21+
//
22+
23+
// stylelint-disable selector-class-pattern --
24+
// Selector '.mdc-*' should only be used in this project.
25+
26+
@use '@material/elevation/elevation';
27+
@use '@material/elevation/elevation-theme';
28+
@use '@material/feature-targeting/feature-targeting';
29+
@use '@material/rtl/rtl';
30+
@use '@material/touch-target/touch-target';
31+
@use '@material/typography/typography';
32+
@use './button-ripple';
33+
@use './button-shared-theme';
34+
35+
@mixin static-styles($query: feature-targeting.all()) {
36+
@include static-styles-without-ripple($query: $query);
37+
@include button-ripple.static-styles($query: $query);
38+
}
39+
40+
@mixin static-styles-without-ripple($query: feature-targeting.all()) {
41+
$feat-structure: feature-targeting.create-target($query, structure);
42+
43+
@include touch-target.wrapper($query); // COPYBARA_COMMENT_THIS_LINE
44+
// prettier-ignore
45+
@include elevation.overlay-common($query); // COPYBARA_COMMENT_THIS_LINE
46+
47+
// postcss-bem-linter: define button
48+
.mdc-button {
49+
@include base($query);
50+
// The icon CSS class overrides styles defined in the .material-icons CSS
51+
// class, which is loaded separately so the order of CSS definitions is not
52+
// guaranteed. Therefore, increase specifity by nesting this class to ensure
53+
// overrides apply.
54+
.mdc-button__icon {
55+
@include feature-targeting.targets($feat-structure) {
56+
@include icon;
57+
}
58+
}
59+
60+
.mdc-button__touch {
61+
@include touch-target.touch-target($query: $query);
62+
}
63+
}
64+
65+
.mdc-button__label + .mdc-button__icon {
66+
@include feature-targeting.targets($feat-structure) {
67+
@include icon-trailing;
68+
}
69+
}
70+
71+
svg.mdc-button__icon {
72+
@include feature-targeting.targets($feat-structure) {
73+
@include icon-svg;
74+
}
75+
}
76+
77+
// TODO: figure out the correct place for this rule.
78+
.mdc-button--raised,
79+
.mdc-button--unelevated,
80+
.mdc-button--outlined {
81+
.mdc-button__icon {
82+
@include feature-targeting.targets($feat-structure) {
83+
// Icons inside contained buttons have different styles due to increased button padding
84+
@include icon-contained;
85+
}
86+
}
87+
88+
.mdc-button__label + .mdc-button__icon {
89+
@include feature-targeting.targets($feat-structure) {
90+
@include icon-contained-trailing;
91+
}
92+
}
93+
}
94+
95+
.mdc-button--touch {
96+
// Touch target doesn't change with height. It simply gets removed if
97+
// density (height) changes. Therefore, it is a static style.
98+
@include touch-target.margin(
99+
$component-height: button-shared-theme.$height,
100+
$query: $query
101+
);
102+
}
103+
// postcss-bem-linter: end
104+
}
105+
106+
@mixin deprecated-base($query) {
107+
@include base($query);
108+
}
109+
110+
@mixin base($query) {
111+
$feat-structure: feature-targeting.create-target($query, structure);
112+
113+
@include typography.typography(button, $query);
114+
@include elevation-theme.overlay-surface-position($query: $query);
115+
@include elevation-theme.overlay-dimensions(100%, $query: $query);
116+
117+
@include feature-targeting.targets($feat-structure) {
118+
display: inline-flex;
119+
// position: relative; already set in mdc-elevation-overlay-surface-position
120+
align-items: center;
121+
justify-content: center;
122+
box-sizing: border-box;
123+
min-width: 64px;
124+
border: none;
125+
outline: none;
126+
/* @alternate */
127+
line-height: inherit;
128+
user-select: none;
129+
-webkit-appearance: none;
130+
// Even though `visible` is the default, IE 11 computes the property as
131+
// `hidden` in some cases, unless it's explicitly defined here.
132+
overflow: visible;
133+
vertical-align: middle;
134+
}
135+
136+
&::-moz-focus-inner {
137+
@include feature-targeting.targets($feat-structure) {
138+
padding: 0;
139+
border: 0;
140+
}
141+
}
142+
143+
// postcss-bem-linter: ignore
144+
&:active {
145+
@include feature-targeting.targets($feat-structure) {
146+
outline: none;
147+
}
148+
}
149+
150+
&:hover {
151+
@include feature-targeting.targets($feat-structure) {
152+
cursor: pointer;
153+
}
154+
}
155+
156+
&:disabled {
157+
@include feature-targeting.targets($feat-structure) {
158+
cursor: default;
159+
pointer-events: none;
160+
}
161+
}
162+
}
163+
164+
@mixin icon {
165+
@include rtl.reflexive-box(margin, right, 8px);
166+
167+
display: inline-block;
168+
width: 18px;
169+
height: 18px;
170+
font-size: 18px;
171+
vertical-align: top;
172+
}
173+
174+
@mixin icon-trailing {
175+
@include rtl.reflexive-box(margin, left, 8px);
176+
}
177+
178+
@mixin icon-svg {
179+
fill: currentColor;
180+
}
181+
182+
@mixin icon-contained {
183+
@include rtl.reflexive-property(margin, -4px, 8px);
184+
}
185+
186+
@mixin icon-contained-trailing {
187+
@include rtl.reflexive-property(margin, 8px, -4px);
188+
}
189+
190+
/// @deprecated Private style mixin for partners; not available for public use.
191+
@mixin deprecated-icon {
192+
@include icon;
193+
}
194+
195+
/// @deprecated Private style mixin for partners; not available for public use.
196+
@mixin deprecated-icon-trailing {
197+
@include icon-trailing;
198+
}
199+
200+
/// @deprecated Private style mixin for partners; not available for public use.
201+
@mixin deprecated-icon-svg {
202+
@include icon-svg;
203+
}
204+
205+
/// @deprecated Private style mixin for partners; not available for public use.
206+
@mixin deprecated-icon-contained {
207+
@include icon-contained;
208+
}
209+
210+
/// @deprecated Private style mixin for partners; not available for public use.
211+
@mixin deprecated-icon-contained-trailing {
212+
@include icon-contained-trailing;
213+
}

packages/mdc-button/_button-filled.scss

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,33 +26,62 @@
2626
@use '@material/elevation/functions' as elevation-functions;
2727
@use '@material/elevation/mixins' as elevation-mixins;
2828
@use '@material/feature-targeting/feature-targeting';
29-
@use './button-theme';
29+
@use './button-base';
30+
@use './button-shared-theme';
3031

31-
@mixin core-styles($query: feature-targeting.all()) {
32-
.mdc-button--raised,
32+
@mixin styles($query: feature-targeting.all()) {
33+
@include button-base.static-styles($query: $query);
34+
@include static-styles($query: $query);
35+
@include theme-styles($query: $query);
36+
}
37+
38+
@mixin theme-styles($query: feature-targeting.all()) {
3339
.mdc-button--unelevated {
34-
@include filled($query);
40+
@include filled($query: $query);
3541
}
3642
}
3743

44+
@mixin static-styles($query: feature-targeting.all()) {
45+
// Intentionally left blank for future-proofing.
46+
}
47+
48+
@mixin filled($query) {
49+
@include _filled-without-ripple($query: $query);
50+
51+
@include button-shared-theme.ripple-states(
52+
$color: on-primary,
53+
$query: $query
54+
);
55+
}
56+
3857
/// @deprecated Private style mixin for partners; not available for public use.
3958
@mixin deprecated-filled($query) {
4059
@include filled($query);
4160
}
4261

43-
@mixin filled($query) {
44-
@include button-theme.horizontal-padding(
45-
button-theme.$contained-horizontal-padding,
62+
@mixin deprecated-theme-styles-without-ripple($query: feature-targeting.all()) {
63+
.mdc-button--raised,
64+
.mdc-button--unelevated {
65+
@include _filled-without-ripple($query: $query);
66+
}
67+
}
68+
69+
@mixin _filled-without-ripple($query: feature-targeting.all()) {
70+
// TODO: move into theme config.
71+
@include button-shared-theme.horizontal-padding(
72+
button-shared-theme.$contained-horizontal-padding,
4673
$query
4774
);
48-
@include button-theme.container-fill-color(primary, $query);
49-
@include button-theme.ink-color(on-primary, $query);
50-
@include button-theme.disabled-container-fill-color(
51-
button-theme.$disabled-container-color,
75+
// TODO(b/175614964): Replace with map that nulls out default ripple values
76+
// when theme mixin is implemented.
77+
@include button-shared-theme.container-fill-color(primary, $query);
78+
@include button-shared-theme.ink-color(on-primary, $query);
79+
@include button-shared-theme.disabled-container-fill-color(
80+
button-shared-theme.$disabled-container-color,
5281
$query
5382
);
54-
@include button-theme.disabled-ink-color(
55-
button-theme.$disabled-ink-color,
83+
@include button-shared-theme.disabled-ink-color(
84+
button-shared-theme.$disabled-ink-color,
5685
$query
5786
);
5887
}
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
//
2+
// Copyright 2021 Google Inc.
3+
//
4+
// Permission is hereby granted, free of charge, to any person obtaining a copy
5+
// of this software and associated documentation files (the "Software"), to deal
6+
// in the Software without restriction, including without limitation the rights
7+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
// copies of the Software, and to permit persons to whom the Software is
9+
// furnished to do so, subject to the following conditions:
10+
//
11+
// The above copyright notice and this permission notice shall be included in
12+
// all copies or substantial portions of the Software.
13+
//
14+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
// THE SOFTWARE.
21+
//
22+
23+
// stylelint-disable selector-class-pattern --
24+
// Selector '.mdc-*' should only be used in this project.
25+
26+
@use 'sass:math';
27+
@use '@material/feature-targeting/feature-targeting';
28+
@use '@material/theme/theme';
29+
@use '@material/theme/theme-color';
30+
@use './button-base';
31+
@use './button-shared-theme';
32+
@use './button-ripple';
33+
34+
$outlined-border-width: 1px !default;
35+
$outline-color: rgba(theme-color.prop-value(on-surface), 0.12) !default;
36+
37+
///
38+
/// Sets the outline color to the given color for an enabled button.
39+
/// @param {Color} $color - The desired outline color.
40+
///
41+
@mixin outline-color($color, $query: feature-targeting.all()) {
42+
&:not(:disabled) {
43+
@include _outline-color($color, $query: $query);
44+
}
45+
}
46+
47+
///
48+
/// Sets the outline color to the given color for a disabled button.
49+
/// @param {Color} $color - The desired outline color.
50+
///
51+
@mixin disabled-outline-color($color, $query: feature-targeting.all()) {
52+
&:disabled {
53+
@include _outline-color($color, $query: $query);
54+
}
55+
}
56+
57+
@mixin outline-width(
58+
$outline-width,
59+
$padding: button-shared-theme.$contained-horizontal-padding,
60+
$query: feature-targeting.all()
61+
) {
62+
$feat-structure: feature-targeting.create-target($query, structure);
63+
// Note: Adjust padding to maintain consistent width with non-outlined buttons
64+
$padding-value: math.max($padding - $outline-width, 0);
65+
66+
@include button-shared-theme.horizontal-padding($padding-value, $query);
67+
68+
@include feature-targeting.targets($feat-structure) {
69+
border-width: $outline-width;
70+
}
71+
72+
#{button-ripple.$ripple-target} {
73+
@include feature-targeting.targets($feat-structure) {
74+
top: -$outline-width;
75+
left: -$outline-width;
76+
border: $outline-width solid transparent;
77+
}
78+
}
79+
80+
.mdc-button__touch {
81+
@include feature-targeting.targets($feat-structure) {
82+
left: -$outline-width;
83+
width: calc(100% + 2 * #{$outline-width});
84+
}
85+
}
86+
}
87+
88+
///
89+
/// Sets the outline color to the given color. This mixin should be
90+
/// wrapped in a selector that qualifies button state.
91+
/// @access private
92+
///
93+
@mixin _outline-color($color, $query: feature-targeting.all()) {
94+
$feat-color: feature-targeting.create-target($query, color);
95+
96+
@if $color {
97+
@include feature-targeting.targets($feat-color) {
98+
@include theme.prop(border-color, $color);
99+
}
100+
}
101+
}

0 commit comments

Comments
 (0)