Skip to content

Commit

Permalink
feat(checkbox): Added theme configuration support to checkbox
Browse files Browse the repository at this point in the history
With this change MDC checkbox provides a separate `theme($theme)` mixin that accepts theme configuration in Sass map format, emits only theme related styles.

This mixin can be included on top of static styles - `static-styles()` with custom theme.

*Example usage:*

```scss
@include checkbox.static-styles();

.custom-checkbox {
  @include checkbox.theme((
    container-checked-color: red,
    density-scale: -3,
  ));
}
```

PiperOrigin-RevId: 327692774
  • Loading branch information
abhiomkar authored and copybara-github committed Aug 20, 2020
1 parent f4532b9 commit fbf73c2
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 35 deletions.
111 changes: 110 additions & 1 deletion packages/mdc-checkbox/_checkbox-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,95 @@ $density-config: (

$ripple-target: '.mdc-checkbox__ripple';

/// Material baseline light theme configuration of checkbox.
/// See https://material.io/components/selection-controls for spec.
$light-theme: (
density-scale: 0,
checkmark-color: $mark-color,
container-checked-color: theme-color.prop-value($baseline-theme-color),
container-checked-hover-color: null,
container-disabled-color: $disabled-color,
outline-color: $border-color,
outline-hover-color: null,
ripple-color: theme-color.$on-surface,
ripple-opacity: ripple-theme.$dark-ink-opacities,
ripple-checked-color: theme-color.prop-value($baseline-theme-color),
ripple-checked-opacity: ripple-theme.$dark-ink-opacities,
);

/// Sets theme to checkbox based on provided theme configuration.
/// Only emits theme related styles. Theme styles should be included after
/// `static-styles()`.
/// @param {Map} $theme - Theme configuration to use for theming checkbox.
@mixin theme($theme, $query: feature-targeting.all()) {
$ripple-color: map.get($theme, ripple-color);
$ripple-opacity: map.get($theme, ripple-opacity);
@if $ripple-color {
@include ripple-color(
$color: $ripple-color,
$opacity-map: $ripple-opacity,
$query: $query
);
}

$ripple-checked-color: map.get($theme, ripple-checked-color);
$ripple-checked-opacity: map.get($theme, ripple-checked-opacity);
@if $ripple-checked-color {
@include focus-indicator-color(
$color: $ripple-checked-color,
$opacity-map: $ripple-checked-opacity,
$query: $query
);
}

$density-scale: map.get($theme, density-scale);
@if $density-scale != null {
@include density($density-scale: $density-scale, $query: $query);
}

$outline-color: map.get($theme, outline-color);
$container-checked-color: map.get($theme, container-checked-color);
@if ($outline-color and $container-checked-color) {
@include container-colors(
$unmarked-stroke-color: $outline-color,
$marked-stroke-color: $container-checked-color,
$marked-fill-color: $container-checked-color,
$query: $query
);
}

$outline-hover-color: map.get($theme, outline-hover-color);
$container-checked-hover-color: map.get(
$theme,
container-checked-hover-color
);
@if ($outline-hover-color and $container-checked-hover-color) {
@include ripple-theme.states-selector() {
@include container-colors(
$unmarked-stroke-color: $outline-hover-color,
$marked-stroke-color: $container-checked-hover-color,
$marked-fill-color: $container-checked-hover-color,
$query: $query
);
}
}

$container-disabled-color: map.get($theme, container-disabled-color);
@if $container-disabled-color {
@include disabled-container-colors(
$unmarked-stroke-color: $container-disabled-color,
$marked-fill-color: $container-disabled-color,
$query: $query
);
}

$checkmark-color: map.get($theme, checkmark-color);
@if $checkmark-color {
@include ink-color($checkmark-color, $query: $query);
@include disabled-ink-color($checkmark-color, $query: $query);
}
}

///
/// Sets density scale for checkbox.
///
Expand Down Expand Up @@ -314,7 +403,26 @@ $ripple-target: '.mdc-checkbox__ripple';
}
}

@mixin focus-indicator-color($color, $query: feature-targeting.all()) {
/// Sets ripple color when checkbox is not in checked state.
@mixin ripple-color(
$color,
$opacity-map: null,
$query: feature-targeting.all()
) {
@include ripple-theme.states(
$color: $color,
$opacity-map: $opacity-map,
$query: $query,
$ripple-target: $ripple-target
);
}

/// Sets focus indicator color when checkbox is in checked state.
@mixin focus-indicator-color(
$color,
$opacity-map: null,
$query: feature-targeting.all()
) {
$feat-color: feature-targeting.create-target($query, color);

.mdc-checkbox__native-control:checked ~ .mdc-checkbox__background::before,
Expand All @@ -330,6 +438,7 @@ $ripple-target: '.mdc-checkbox__ripple';
&.mdc-checkbox--selected {
@include ripple-theme.states(
$color: $color,
$opacity-map: $opacity-map,
$query: $query,
$ripple-target: $ripple-target
);
Expand Down
32 changes: 6 additions & 26 deletions packages/mdc-checkbox/_checkbox.scss
Original file line number Diff line number Diff line change
Expand Up @@ -209,23 +209,8 @@
/// Checkbox styles that are customizable should go here.
@mixin theme-styles($query: feature-targeting.all()) {
.mdc-checkbox {
@include checkbox-theme.focus-indicator-color(
checkbox-theme.$baseline-theme-color,
$query: $query
);
@include checkbox-theme.density(
checkbox-theme.$density-scale,
$query: $query
);
@include checkbox-theme.theme(checkbox-theme.$light-theme, $query: $query);
}

@include checkbox-theme.container-colors($query: $query);
@include checkbox-theme.disabled-container-colors($query: $query);
@include checkbox-theme.ink-color(checkbox-theme.$mark-color, $query: $query);
@include checkbox-theme.disabled-ink-color(
checkbox-theme.$mark-color,
$query: $query
);
}

/// Checkbox's ripple styles.
Expand All @@ -242,15 +227,14 @@
$query: $query,
$ripple-target: checkbox-theme.$ripple-target
);
@include ripple-theme.states(
$color: on-surface,
$query: $query,
$ripple-target: checkbox-theme.$ripple-target
);
@include ripple.radius-unbounded(
$query: $query,
$ripple-target: checkbox-theme.$ripple-target
);
@include ripple-theme.behind-content(
checkbox-theme.$ripple-target,
$query: $query
);
}

#{checkbox-theme.$ripple-target} {
Expand Down Expand Up @@ -283,11 +267,7 @@
}

@mixin child--upgraded_ {
// Due to the myriad of selector combos used to properly style a CSS-only checkbox, all of
// which have varying selector precedence and make use of transitions, it is cleaner and more
// efficient here to simply use !important, since the mdc-checkbox--anim-* classes will take
// over from here.
transition: none !important;
transition: none;
}

// Animation
Expand Down
49 changes: 41 additions & 8 deletions packages/mdc-ripple/_ripple-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -241,13 +241,15 @@ $pressed-light-ink-opacity: 0.32 !default;
$color: theme-color.prop-value(on-surface),
$has-nested-focusable-element: false,
$query: feature-targeting.all(),
$ripple-target: '&'
$ripple-target: '&',
$opacity-map: null
) {
@include states-interactions_(
$color: $color,
$has-nested-focusable-element: $has-nested-focusable-element,
$query: $query,
$ripple-target: $ripple-target
$ripple-target: $ripple-target,
$opacity-map: $opacity-map
);
}

Expand Down Expand Up @@ -317,17 +319,20 @@ $pressed-light-ink-opacity: 0.32 !default;
$has-nested-focusable-element,
$opacity-modifier: 0,
$query: feature-targeting.all(),
$ripple-target: '&'
$ripple-target: '&',
$opacity-map: null
) {
@include target-selector($ripple-target) {
@include states-base-color($color, $query);
}

$opacity-map: (
hover: states-opacity($color, hover) + $opacity-modifier,
focus: states-opacity($color, focus) + $opacity-modifier,
press: states-opacity($color, press) + $opacity-modifier,
);
@if $opacity-map == null {
$opacity-map: (
hover: states-opacity($color, hover) + $opacity-modifier,
focus: states-opacity($color, focus) + $opacity-modifier,
press: states-opacity($color, press) + $opacity-modifier,
);
}

@include states-opacities(
$opacity-map,
Expand All @@ -348,6 +353,34 @@ $pressed-light-ink-opacity: 0.32 !default;
}
}

/// Selector for hover, active and focus states.
@mixin states-selector() {
&:hover,
&:active,
&:focus,
&.mdc-ripple-upgraded--background-focused {
@content;
}
}

/// Keep the ripple (State overlay) behind the content.
@mixin behind-content($ripple-target: '&', $query: feature-targeting.all()) {
// Needed for IE11. Without this, IE11 renders the state layer completely
// underneath the container, making it invisible.
$feat-structure: feature-targeting.create-target($query, structure);

@include feature-targeting.targets($feat-structure) {
z-index: 0;
}

#{$ripple-target}::before,
#{$ripple-target}::after {
@include feature-targeting.targets($feat-structure) {
z-index: -1;
}
}
}

@function states-opacity($color, $state) {
$opacity-map: states-opacities_($color);

Expand Down

0 comments on commit fbf73c2

Please sign in to comment.