Skip to content

Commit

Permalink
feat(material/theming): Add APIs to get color info from theme
Browse files Browse the repository at this point in the history
  • Loading branch information
mmalerba committed Aug 14, 2023
1 parent a7dbf08 commit 1a85dd2
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 16 deletions.
8 changes: 8 additions & 0 deletions src/material-experimental/theming/_definition.scss
Expand Up @@ -46,6 +46,14 @@ $theme-version: 1;
$internals: (
theme-version: $theme-version,
theme-type: $type,
palettes: (
primary: map.remove($primary, neutral-variant),
secondary: map.remove($secondary, neutral-variant),
tertiary: map.remove($tertiary, neutral-variant),
neutral: m3-palettes.$neutral-palette,
neutral-variant: map.get($primary, neutral-variant),
error: m3-palettes.$red-palette
),
color-tokens: m3-tokens.generate-color-tokens($type, $primary, $secondary, $tertiary,
m3-palettes.$neutral-palette, m3-palettes.$red-palette)
)
Expand Down
3 changes: 2 additions & 1 deletion src/material/_index.scss
Expand Up @@ -144,4 +144,5 @@ list-density, list-base;
$private-mdc-theme-styles-query, $private-mdc-typography-styles-query;

// New theming APIs, currently in development:
@forward './core/theming/inspection' as private-* show private-get-theme-version;
@forward './core/theming/inspection' as private-* show private-get-theme-version,
private-get-theme-type, private-get-theme-color;
80 changes: 77 additions & 3 deletions src/material/core/theming/_inspection.scss
Expand Up @@ -24,6 +24,81 @@ $_internals: _mat-theming-internals-do-not-access;
@return if($err, 0, map.get($theme, $_internals, theme-version) or 0);
}

/// Gets the type of theme represented by a theme object (light or dark).
/// @param {Map} $theme The theme
/// @return {String} The type of theme (either `light` or `dark`).
@function get-theme-type($theme) {
$err: _validate-theme-object($theme);
@if $err {
// TODO(mmalerba): implement for old style theme objects.
@error #{'get-theme-type does not support legacy theme objects.'};
}
@return map.get($theme, $_internals, theme-type) or light;
}

/// Gets a color from a theme object. This function can take 2 or 3 arguments. If 2 arguments are
/// passed, the second argument is treated as the name of a color role. If 3 arguments are passed,
/// the second argument is treated as the name of a color palette (primary, secondary, etc.) and the
/// third is treated as the palette hue (10, 50, etc.)
/// @param {Map} $theme The theme
/// @param {String} $color-role-or-palette-name The name of the color role to get, or the name of a
/// color palette.
/// @param {Number} $hue The palette hue to get (passing this argument means the second argument is
/// interpreted as a palette name).
/// @return {Color} The requested theme color.
@function get-theme-color($theme, $args...) {
$args-count: list.length($args);
@if $args-count == 1 {
@return _get-theme-role-color($theme, $args...);
} @else if $args-count == 2 {
@return _get-theme-palette-color($theme, $args...);
}
@error #{'Expected 2 or 3 arguments. Got:'} $args-count + 1;
}

/// Gets a role color from a theme object.
/// @param {Map} $theme The theme
/// @param {String} $color-role-name The name of the color role to get.
/// @return {Color} The requested role color.
@function _get-theme-role-color($theme, $color-role-name) {
$err: _validate-theme-object($theme);
@if $err {
// TODO(mmalerba): implement for old style theme objects.
@error #{'get-theme-color does not support legacy theme objects.'};
}
$color-roles: map.get($theme, $_internals, color-tokens, (mdc, theme));
$result: map.get($color-roles, $color-role-name);
@if not $result {
@error #{'Valid color roles are: #{map.keys($color-roles)}. Got:'} $color-role-name;
}
@return $result;
}

/// Gets a palette color from a theme object.
/// @param {Map} $theme The theme
/// @param {String} $palette-name The name of the palette to get the color from.
/// @param {Number} $hue The hue to read from the palette.
/// @return {Color} The requested palette color.
@function _get-theme-palette-color($theme, $palette-name, $hue) {
$err: _validate-theme-object($theme);
@if $err {
// TODO(mmalerba): implement for old style theme objects.
@error #{'get-theme-color does not support legacy theme objects.'};
}
$palettes: map.get($theme, $_internals, palettes);
$palette: map.get($palettes, $palette-name);
@if not $palette {
$supported-palettes: map.keys($palettes);
@error #{'Valid palettes are: #{$supported-palettes}. Got:'} $palette-name;
}
$result: map.get($palette, $hue);
@if not $result {
$supported-hues: map.keys($palette);
@error #{'Valid hues for'} $palette-name #{'are: #{$supported-hues}. Got:'} $hue;
}
@return $result;
}

/// Gets the set of tokens from the given theme, limited to those affected by the requested theming
/// systems.
/// @param {Map} $theme The theme to get tokens from.
Expand All @@ -38,9 +113,8 @@ $_internals: _mat-theming-internals-do-not-access;
}
$err: validation.validate-allowed-values($systems, color, typography, density, base);
@if $err {
@error
#{'Expected $systems to contain valid system names (color, typographt, density, or base).'}
#{'Got invalid system names:'} $err;
@error #{'Expected $systems to contain valid system names (color, typography, density, or'}
#{'base). Got invalid system names:'} $err;
}
$result: ();
@each $system in $systems {
Expand Down
99 changes: 87 additions & 12 deletions src/material/core/theming/tests/theming-inspection-api.spec.ts
Expand Up @@ -124,13 +124,12 @@ describe('theming inspection api', () => {
it('should get theme version', () => {
expect(
transpile(`
$theme: ${defineM2Theme()};
div {
content: mat.private-get-theme-version($theme);
}
`),
).toMatch('content: 0;');
$theme: ${defineM2Theme()};
div {
content: mat.private-get-theme-version($theme);
}
`),
).toMatch(/content: 0;/);
});
});

Expand All @@ -139,12 +138,88 @@ describe('theming inspection api', () => {
expect(
transpile(`
$theme: ${defineM3Theme()};
div {
content: mat.private-get-theme-version($theme);
}
`),
).toMatch(/content: 1;/);
});

it('should get theme type', () => {
expect(
transpile(`
$theme: ${defineM3Theme()};
div {
content: mat.private-get-theme-type($theme);
}
`),
).toMatch(/content: light;/);
});

it('should get role color', () => {
expect(
transpile(`
$theme: ${defineM3Theme()};
div {
content: mat.private-get-theme-color($theme, primary-container);
}
`),
).toMatch(/content: #e0e0ff;/);
});

it('should error on invalid color role', () => {
expect(() =>
transpile(`
$theme: ${defineM3Theme()};
div {
content: mat.private-get-theme-color($theme, fake-role);
}
`),
).toThrowError(/Valid color roles are.*Got: fake-role/);
});

it('should get palette color', () => {
expect(
transpile(`
$theme: ${defineM3Theme()};
div {
content: mat.private-get-theme-color($theme, tertiary, 20);
}
`),
).toMatch(/content: #323200;/);
});

it('should error on invalid color palette', () => {
expect(() =>
transpile(`
$theme: ${defineM3Theme()};
div {
content: mat.private-get-theme-color($theme, fake-palette, 20);
}
`),
).toThrowError(/Valid palettes are.*Got: fake-palette/);
});

it('should error on invalid color hue', () => {
expect(() =>
transpile(`
$theme: ${defineM3Theme()};
div {
content: mat.private-get-theme-color($theme, neutral, 11);
}
`),
).toThrowError(/Valid hues for neutral are.*Got: 11/);
});

div {
content: mat.private-get-theme-version($theme);
}
`),
).toMatch('content: 1;');
it('should error on wrong number of get-color-theme args', () => {
expect(() =>
transpile(`
$theme: ${defineM3Theme()};
div {
content: mat.private-get-theme-color($theme);
}
`),
).toThrowError(/Expected 2 or 3 arguments. Got: 1/);
});
});
});

0 comments on commit 1a85dd2

Please sign in to comment.