Skip to content

Commit 948122c

Browse files
committed
chore(checkbox): get rid of imported MDC's styles
As a first step of getting rid of MDC, we need to make sure that the component renders correctly, without relying on any styles applied by MDC.
1 parent 3d22d12 commit 948122c

File tree

6 files changed

+218
-137
lines changed

6 files changed

+218
-137
lines changed
Lines changed: 181 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,110 +1,208 @@
1-
@use '@material/checkbox';
2-
@use '@material/form-field';
1+
@use '../../style/mixins';
32

43
/**
54
* @prop --checkbox-unchecked-border-color: Affects the border color of the default state of the checkbox (when it is not checked). Defaults to `--contrast-900`.
65
*/
6+
$box-size: 1.25rem;
7+
$gap-size: 0.5rem;
78

8-
@mixin custom-checkbox-styles {
9-
// This is used in other components too, such as `limel-list`
10-
--mdc-checkbox-checked-color: var(
11-
--lime-primary-color,
12-
var(--limel-theme-primary-color)
13-
);
14-
--mdc-checkbox-unchecked-color: var(
15-
--checkbox-unchecked-border-color,
16-
rgb(var(--contrast-900))
17-
);
18-
--lime-checkbox-unchecked-color: rgb(var(--contrast-300));
9+
:host(limel-checkbox) {
10+
min-height: var(--limel-checkbox-min-height, 2.5rem); // prevents flickering
11+
// when switching between `readonly` and normal states in `limel-checkbox`,
12+
// but not where `CheckboxTemplate` is imported & used.
1913
}
2014

21-
:host(limel-checkbox) {
22-
@include custom-checkbox-styles;
23-
min-height: 2.5rem;
15+
*,
16+
*:before,
17+
*:after {
18+
box-sizing: border-box;
2419
}
2520

26-
limel-dynamic-label {
27-
margin-top: 0.375rem;
28-
margin-left: 0.375rem;
29-
gap: 0.375rem;
21+
.checkbox {
22+
position: relative;
23+
isolation: isolate;
24+
25+
display: flex;
26+
align-items: center;
27+
28+
min-height: var(
29+
--limel-checkbox-min-height,
30+
2.5rem
31+
); // helps align with other fields in the form, or within table rows
32+
width: 100%;
3033
}
3134

32-
@include checkbox.core-styles;
33-
@include form-field.core-styles;
34-
35-
.mdc-form-field {
36-
// As long as this component is depended on MDC,
37-
// we need to force it to be font-agnostic.
38-
// When MDC-dependency is removed, this block can also be removed.
39-
// However, on removal of MDC-dependency, we should also make sure to check
40-
// other font-related styles that might be set by MDC,
41-
// such as `letter-spacing` or `font-size`.
42-
font-family: inherit;
43-
font-size: var(--limel-theme-default-font-size);
35+
input[type='checkbox'] {
36+
// Hide the native checkbox
37+
@include mixins.visually-hidden;
38+
-webkit-appearance: none;
39+
-moz-appearance: none;
40+
appearance: none;
4441
}
4542

46-
.mdc-form-field {
47-
display: flex;
48-
align-items: flex-start;
49-
50-
.mdc-checkbox {
51-
.mdc-checkbox__native-control {
52-
&[disabled],
53-
&:enabled {
54-
&:not(:checked):not(:indeterminate) {
55-
~ .mdc-checkbox__background {
56-
background-color: var(--lime-checkbox-unchecked-color);
57-
}
58-
}
59-
}
60-
}
43+
label {
44+
min-width: 0;
6145

62-
&.mdc-checkbox--invalid {
63-
.mdc-checkbox__native-control:enabled:not(:checked):not(
64-
:indeterminate
65-
)
66-
~ .mdc-checkbox__background {
67-
border-color: var(--limel-theme-error-color);
68-
}
69-
}
70-
.mdc-checkbox__native-control {
71-
&:focus-visible {
72-
+ .mdc-checkbox__background {
73-
&:after {
74-
content: '';
75-
display: block;
76-
position: absolute;
77-
inset: -0.25rem;
78-
border-radius: 0.25rem;
79-
box-shadow: var(--shadow-depth-8-focused);
80-
}
81-
}
82-
}
46+
cursor: pointer;
47+
position: relative;
48+
width: 100%;
49+
50+
font-size: var(--limel-theme-default-small-font-size);
51+
color: var(--limel-theme-text-primary-on-background-color);
52+
53+
padding-left: calc($box-size + $gap-size);
54+
55+
.disabled:not([readonly]):not([readonly='true']) & {
56+
cursor: not-allowed;
57+
color: var(--limel-theme-text-disabled-color);
58+
}
59+
60+
.required & {
61+
&:after {
62+
margin-left: 0.0625rem;
63+
content: '*';
8364
}
8465
}
85-
.mdc-checkbox--disabled {
86-
opacity: 0.5;
66+
67+
.invalid:not(.readonly) & {
68+
color: var(--limel-theme-error-text-color);
8769
}
70+
}
8871

89-
label {
90-
cursor: pointer;
91-
line-height: normal;
92-
letter-spacing: normal;
72+
.box {
73+
position: absolute; // since `label` is the clickable part,
74+
// and thus needs to
75+
// stretch below the checkbox
76+
pointer-events: none;
9377

94-
padding-top: 0.75rem;
95-
padding-left: 0;
78+
transition:
79+
border-color 0.4s ease 0.2s,
80+
background-color 0.2s ease,
81+
box-shadow var(--limel-clickable-transform-speed, 0.4s) ease;
9682

97-
color: var(--limel-theme-text-primary-on-background-color);
83+
display: inline-block;
84+
vertical-align: middle;
9885

99-
&.mdc-checkbox--required::after {
100-
margin-left: 0.0625rem;
101-
content: '*';
86+
width: $box-size;
87+
height: $box-size;
88+
89+
margin-right: $gap-size;
90+
border-radius: 0.25rem;
91+
border: 0.125rem solid;
92+
93+
border-color: var(
94+
--checkbox-unchecked-border-color,
95+
rgb(var(--contrast-900))
96+
);
97+
background-color: var(
98+
--limel-checkbox-background-color,
99+
rgb(var(--contrast-300))
100+
);
101+
102+
.checked &,
103+
.checkbox:has(input[type='checkbox']:checked) & {
104+
background-color: var(
105+
--lime-primary-color,
106+
var(--limel-theme-primary-color)
107+
);
108+
border-color: var(
109+
--lime-primary-color,
110+
var(--limel-theme-primary-color)
111+
);
112+
}
113+
114+
.disabled & {
115+
opacity: 0.4;
116+
}
117+
118+
.checkbox:not(.disabled):has(label:hover) & {
119+
will-change: box-shadow;
120+
box-shadow: var(--button-shadow-hovered);
121+
}
122+
123+
.checkbox:not(.disabled):has(label:active) & {
124+
will-change: box-shadow;
125+
box-shadow: var(--button-shadow-pressed);
126+
}
127+
128+
&:before {
129+
// For indicating the hover or focused state
130+
transition: mixins.$clickable-normal-state-transitions;
131+
content: '';
132+
position: absolute;
133+
inset: -0.1875rem; // 3px
134+
border-radius: inherit;
135+
136+
.checkbox:has(input[type='checkbox']:focus-visible) & {
137+
will-change: box-shadow;
138+
139+
box-shadow: var(--shadow-depth-8-focused);
140+
}
141+
}
142+
143+
&:after {
144+
// For indicating the indeterminate state
145+
transition:
146+
opacity 0.2s ease,
147+
width 0.4s ease;
148+
content: '';
149+
position: absolute;
150+
inset: 0;
151+
margin: auto;
152+
153+
height: 0.125rem;
154+
width: 0.25rem;
155+
156+
border-radius: 1rem;
157+
opacity: 0;
158+
159+
background-color: rgb(var(--color-white));
160+
161+
.indeterminate & {
162+
opacity: 1;
163+
width: calc($box-size - 0.5rem);
102164
}
165+
}
166+
}
167+
168+
svg {
169+
position: absolute;
170+
z-index: 1;
171+
inset: 0;
172+
173+
transform: translate3d(-0.125rem, -0.125rem, 0);
174+
175+
width: $box-size;
176+
height: $box-size;
177+
178+
padding: 0.25rem;
179+
180+
color: rgb(var(--color-white));
181+
opacity: 0;
103182

104-
&.mdc-checkbox--invalid {
105-
color: var(--limel-theme-error-text-color);
183+
stroke-width: 0.1875rem; // 3px
184+
stroke: currentColor;
185+
stroke-linecap: round;
186+
stroke-linejoin: round;
187+
188+
path {
189+
stroke-dashoffset: 29.7833;
190+
stroke-dasharray: 29.7833;
191+
transition: stroke-dashoffset 180ms cubic-bezier(0.4, 0, 0.6, 1);
192+
}
193+
194+
.checkbox:not(.indeterminate):has(input[type='checkbox']:checked) & {
195+
opacity: 1;
196+
197+
path {
198+
stroke-dashoffset: 0;
106199
}
107200
}
108201
}
109202

110-
@import './partial-styles/_helper-text.scss';
203+
limel-dynamic-label {
204+
margin-top: 0.375rem;
205+
margin-left: -0.25rem;
206+
}
207+
208+
@include mixins.hide-helper-line-when-not-needed(limel-checkbox);

src/components/checkbox/checkbox.template.tsx

Lines changed: 30 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -50,52 +50,37 @@ export const CheckboxTemplate: FunctionalComponent<CheckboxTemplateProps> = (
5050
}
5151

5252
return [
53-
<div class="mdc-form-field ">
54-
<div
55-
class={{
56-
'mdc-checkbox': true,
57-
'mdc-checkbox--invalid': props.invalid,
58-
'mdc-checkbox--disabled': props.disabled,
59-
'mdc-checkbox--required': props.required,
60-
'mdc-checkbox--indeterminate': props.indeterminate,
61-
'lime-checkbox--readonly': props.readonly,
62-
}}
63-
>
64-
<input
65-
type="checkbox"
66-
class="mdc-checkbox__native-control"
67-
id={props.id}
68-
checked={props.checked}
69-
disabled={props.disabled || props.readonly}
70-
required={props.required}
71-
onChange={props.onChange}
72-
aria-controls={props.helperTextId}
73-
aria-describedby={props.helperTextId}
74-
{...inputProps}
75-
/>
76-
<div class="mdc-checkbox__background">
77-
<svg class="mdc-checkbox__checkmark" viewBox="0 0 24 24">
78-
<path
79-
class="mdc-checkbox__checkmark-path"
80-
fill="none"
81-
d="M1.73,12.91 8.1,19.28 22.79,4.59"
82-
/>
83-
</svg>
84-
<div class="mdc-checkbox__mixedmark" />
85-
</div>
53+
<div
54+
class={{
55+
'mdc-form-field': true, // required by MDC to work
56+
'mdc-checkbox': true, // required by MDC to work
57+
checkbox: true,
58+
checked: props.checked,
59+
invalid: props.invalid,
60+
disabled: props.disabled,
61+
required: props.required,
62+
indeterminate: props.indeterminate,
63+
readonly: props.readonly,
64+
}}
65+
>
66+
<input
67+
type="checkbox"
68+
class="mdc-checkbox__native-control" // required by MDC to work
69+
id={props.id}
70+
checked={props.checked}
71+
disabled={props.disabled || props.readonly}
72+
required={props.required}
73+
onChange={props.onChange}
74+
aria-controls={props.helperTextId}
75+
aria-describedby={props.helperTextId}
76+
{...inputProps}
77+
/>
78+
<div class="box">
79+
<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false">
80+
<path fill="none" d="M1.73,12.91 8.1,19.28 22.79,4.59" />
81+
</svg>
8682
</div>
87-
<label
88-
class={{
89-
'mdc-checkbox--invalid': props.invalid,
90-
'mdc-checkbox--disabled': props.disabled,
91-
'mdc-checkbox--required': props.required,
92-
'mdc-checkbox--indeterminate': props.indeterminate,
93-
'lime-checkbox--readonly': props.readonly,
94-
}}
95-
htmlFor={props.id}
96-
>
97-
{props.label}
98-
</label>
83+
<label htmlFor={props.id}>{props.label}</label>
9984
</div>,
10085
<HelperText
10186
text={props.helperText}

src/components/checkbox/partial-styles/_helper-text.scss

Lines changed: 0 additions & 2 deletions
This file was deleted.

src/components/dynamic-label/dynamic-label.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
:host(limel-dynamic-label) {
77
--limel-dynamic-label-min-height: 1.75rem;
88
display: flex;
9-
gap: 0.5rem;
9+
gap: 0.25rem;
1010
align-items: flex-start;
1111
border-radius: 0.5rem;
1212
min-width: 0;

0 commit comments

Comments
 (0)