Skip to content

Commit

Permalink
Add the new mat.theme API
Browse files Browse the repository at this point in the history
  • Loading branch information
mmalerba committed May 16, 2023
1 parent f990c0b commit 96f7d46
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 1 deletion.
37 changes: 36 additions & 1 deletion src/dev-app/theme-token-api.scss
@@ -1,4 +1,5 @@
@use '@angular/material' as mat;
@use '@angular/material-experimental';

dev-app {
&::before {
Expand All @@ -15,4 +16,38 @@ dev-app {
}
}

@debug 'Generated M2 tokens:' mat.m2-tokens-from-theme();
.demo-unicorn-dark-theme {
background: black;
color: white;
}

@include mat.core();

$dark-theme: mat.define-dark-theme((
color: (
primary: mat.define-palette(mat.$blue-grey-palette),
accent: mat.define-palette(mat.$amber-palette, A200, A100, A400),
warn: mat.define-palette(mat.$deep-orange-palette),
),
typography: mat.define-typography-config(),
density: 0,
));

// Set up light theme.

@include material-experimental.theme($components: (
material-experimental.card(),
material-experimental.checkbox(),
));

// Set up dark theme.

.demo-unicorn-dark-theme {
@include material-experimental.theme($tokens: mat.m2-tokens-from-theme($dark-theme), $components: (
material-experimental.checkbox((
(mdc, checkbox): (
selected-checkmark-color: red,
)
)),
));
}
3 changes: 3 additions & 0 deletions src/material-experimental/_index.scss
Expand Up @@ -4,4 +4,7 @@
@forward './popover-edit/popover-edit-theme' as popover-edit-* show popover-edit-color,
popover-edit-typography, popover-edit-density, popover-edit-theme;

// Token-based theming API
@forward './theming/theming' show theme, card, checkbox;

// Additional public APIs for individual components
102 changes: 102 additions & 0 deletions src/material-experimental/theming/_theming.scss
@@ -0,0 +1,102 @@
@use 'sass:list';
@use 'sass:map';
@use 'sass:meta';
@use 'sass:string';
@use '@angular/material' as mat;

// Whether to throw an error when a required dep is not configured. If false, the dep will be
// automatically configured instead.
$_error-on-missing-dep: false;

// Applies the theme for the given component configuration.
@mixin _apply-theme($tokens, $component) {
$id: map.get($component, id);
$tokens: map.deep-merge($tokens, map.get($component, customizations));

// NOTE: for now we use a hardcoded if-chain, but in the future when first-class mixins are
// supported, the configuration data will contain a reference to its own theme mixin.
@if $id == 'mat.card' {
@include mat.private-apply-card-theme-from-tokens($tokens);
} @else if $id == 'mat.checkbox' {
@include mat.private-apply-checkbox-theme-from-tokens($tokens);
} @else {
@error 'Unrecognized component theme: #{id}';
}
}

// Gets the transitive dependency configurations for the given list of component configurations.
@function _get-transitive-deps($components, $configured: ()) {
// Mark the given components as configured.
@each $component in $components {
$configured: map.set($configured, map.get($component, id), true);
}
$new-deps: ();

// Check each of the given components for new deps.
@each $component in $components {
@each $dep-getter in mat.private-normalize-args-list(map.get($component, deps)) {
$dep: meta.call($dep-getter);
$dep-id: map.get($dep, id);
@if not (map.has-key($configured, $dep-id)) {
@if $_error-on-missing-dep {
@error 'Missing theme: `#{map.get($component, id)}` depends on `#{$dep-id}`.' +
' Please configure the theme for `#{$dep-id}` in your call to `mat.theme`';
} @else {
$configured: map.set($configured, $dep-id, true);
$new-deps: list.append($new-deps, $dep);
}
}
}
}

// Append on the new deps to this list of component configurations and return.
@if list.length($new-deps) > 0 {
$components: list.join($components, _get-transitive-deps($new-deps, $configured));
}
@return $components;
}

@mixin _theme($tokens, $components) {
// Call the theme mixin for each configured component.
@at-root #{& or body} {
@each $component in $components {
@include _apply-theme($tokens, $component);
}
}
}

// Takes the full list of tokens and a list of components to configure, and outputs all theme
// tokens for the configured components.
@mixin theme($tokens: mat.m2-tokens-from-theme(), $components) {
@include _theme($tokens, _get-transitive-deps(mat.private-normalize-args-list($components)));
}

// TODO(mmalerba): What should we call this?
// - update-theme
// - adjust-theme
// - edit-theme
// - override-theme
// - retheme
// Takes a list of components to configure, and outputs only the theme tokens that are explicitly
// customized by the configurations.
@mixin update-theme($components) {
@include _theme((), $components);
}

// Configure the mat-card's theme.
@function card($customizations: ()) {
@return (
id: 'mat.card',
customizations: $customizations,
deps: (),
);
}

// Configure the mat-checkbox's theme.
@function checkbox($customizations: ()) {
@return (
id: 'mat.checkbox',
customizations: $customizations,
deps: (),
);
}
1 change: 1 addition & 0 deletions src/material/_index.scss
Expand Up @@ -38,6 +38,7 @@
// The form field density mixin needs to be exposed, because the paginator depends on it.
@forward './form-field/form-field-theme' as private-form-field-* show private-form-field-density;
@forward './token-theming' as private-apply-*;
@forward './core/style/sass-utils' as private-*;

// Structural
@forward './core/core' show core;
Expand Down
9 changes: 9 additions & 0 deletions src/material/core/style/_sass-utils.scss
@@ -1,4 +1,6 @@
@use 'sass:list';
@use 'sass:map';
@use 'sass:meta';

// A version of the standard `map.deep-merge` function that takes a variable number of arguments.
// Each argument is deep-merged into the final result from left to right.
Expand All @@ -9,3 +11,10 @@
}
@return $result;
}

// Normalizes a list of arguments to ensure it really is a list and not a single arg.
// This should be used when dealing with user-passed lists of args to avoid confusing errors,
// since Sass treats `($x)` as equivalent to `$x`.
@function normalize-args-list($list) {
@return if(meta.type-of($list) != 'list', ($list,), $list);
}

0 comments on commit 96f7d46

Please sign in to comment.