From f52e97958ac8d9845017a5ead077952f3228144f Mon Sep 17 00:00:00 2001 From: Miles Malerba Date: Wed, 9 Aug 2023 18:08:03 +0000 Subject: [PATCH] feat(material/theming): Add APIs to get typography info from theme --- src/material/_index.scss | 2 +- src/material/core/theming/_inspection.scss | 50 +++++++++++++ .../tests/theming-inspection-api.spec.ts | 70 +++++++++++++++---- 3 files changed, 107 insertions(+), 15 deletions(-) diff --git a/src/material/_index.scss b/src/material/_index.scss index c2e2076abb86..df46cc06041d 100644 --- a/src/material/_index.scss +++ b/src/material/_index.scss @@ -145,4 +145,4 @@ list-density, list-base; // New theming APIs, currently in development: @forward './core/theming/inspection' as private-* show private-get-theme-version, - private-get-theme-type, private-get-theme-color; + private-get-theme-type, private-get-theme-color, private-get-theme-typography; diff --git a/src/material/core/theming/_inspection.scss b/src/material/core/theming/_inspection.scss index de6a3446adde..b538a8174c08 100644 --- a/src/material/core/theming/_inspection.scss +++ b/src/material/core/theming/_inspection.scss @@ -6,6 +6,26 @@ $_internals: _mat-theming-internals-do-not-access; +$_m3-typescales: ( + display-large, + display-medium, + display-small, + headline-large, + headline-medium, + headline-small, + title-large, + title-medium, + title-small, + label-large, + label-medium, + label-small, + body-large, + body-medium, + body-small, +); + +$_typography-properties: (font, font-family, line-height, font-size, letter-spacing, font-weight); + /// Validates that the given value is a versioned theme object. /// @param {Any} $theme The theme object to validate. /// @return {Boolean|Null} true if the theme has errors, else null. @@ -99,6 +119,36 @@ $_internals: _mat-theming-internals-do-not-access; @return $result; } +/// Gets a typography value from a theme object. +/// @param {Map} $theme The theme +/// @param {String} $typescale The typescale name. +/// @param {String} $property The CSS font property to get +/// (font, font-family, font-size, font-weight, line-height, or letter-spacing). +/// @return {*} The value of the requested font property. +@function get-theme-typography($theme, $typescale, $property: font) { + $err: _validate-theme-object($theme); + @if $err { + // TODO(mmalerba): implement for old style theme objects. + @error #{'get-theme-typography does not support legacy theme objects.'}; + } + @if not list.index($_m3-typescales, $typescale) { + @error #{'Valid typescales are: #{$_m3-typescales}. Got:'} $typescale; + } + @if not list.index($_typography-properties, $property) { + @error #{'Valid typography properties are: #{$_typography-properties}. Got:'} $property; + } + $property-key: map.get(( + font: '', + font-family: '-font', + line-height: '-line-height', + font-size: '-size', + letter-spacing: '-tracking', + font-weight: '-weight' + ), $property); + $token-name: '#{$typescale}#{$property-key}'; + @return map.get($theme, $_internals, typography-tokens, (mdc, typography), $token-name); +} + /// 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. diff --git a/src/material/core/theming/tests/theming-inspection-api.spec.ts b/src/material/core/theming/tests/theming-inspection-api.spec.ts index 188199eaf069..5d65b831e4f8 100644 --- a/src/material/core/theming/tests/theming-inspection-api.spec.ts +++ b/src/material/core/theming/tests/theming-inspection-api.spec.ts @@ -126,10 +126,10 @@ describe('theming inspection api', () => { transpile(` $theme: ${defineM2Theme()}; div { - content: mat.private-get-theme-version($theme); + --theme-version: #{mat.private-get-theme-version($theme)}; } `), - ).toMatch(/content: 0;/); + ).toMatch('--theme-version: 0;'); }); }); @@ -139,10 +139,10 @@ describe('theming inspection api', () => { transpile(` $theme: ${defineM3Theme()}; div { - content: mat.private-get-theme-version($theme); + --theme-version: #{mat.private-get-theme-version($theme)}; } `), - ).toMatch(/content: 1;/); + ).toMatch('--theme-version: 1;'); }); it('should get theme type', () => { @@ -150,10 +150,10 @@ describe('theming inspection api', () => { transpile(` $theme: ${defineM3Theme()}; div { - content: mat.private-get-theme-type($theme); + --theme-type: #{mat.private-get-theme-type($theme)}; } `), - ).toMatch(/content: light;/); + ).toMatch('--theme-type: light;'); }); it('should get role color', () => { @@ -161,10 +161,10 @@ describe('theming inspection api', () => { transpile(` $theme: ${defineM3Theme()}; div { - content: mat.private-get-theme-color($theme, primary-container); + color: mat.private-get-theme-color($theme, primary-container); } `), - ).toMatch(/content: #e0e0ff;/); + ).toMatch('color: #e0e0ff;'); }); it('should error on invalid color role', () => { @@ -172,7 +172,7 @@ describe('theming inspection api', () => { transpile(` $theme: ${defineM3Theme()}; div { - content: mat.private-get-theme-color($theme, fake-role); + color: mat.private-get-theme-color($theme, fake-role); } `), ).toThrowError(/Valid color roles are.*Got: fake-role/); @@ -183,10 +183,10 @@ describe('theming inspection api', () => { transpile(` $theme: ${defineM3Theme()}; div { - content: mat.private-get-theme-color($theme, tertiary, 20); + color: mat.private-get-theme-color($theme, tertiary, 20); } `), - ).toMatch(/content: #323200;/); + ).toMatch('color: #323200;'); }); it('should error on invalid color palette', () => { @@ -194,7 +194,7 @@ describe('theming inspection api', () => { transpile(` $theme: ${defineM3Theme()}; div { - content: mat.private-get-theme-color($theme, fake-palette, 20); + color: mat.private-get-theme-color($theme, fake-palette, 20); } `), ).toThrowError(/Valid palettes are.*Got: fake-palette/); @@ -205,7 +205,7 @@ describe('theming inspection api', () => { transpile(` $theme: ${defineM3Theme()}; div { - content: mat.private-get-theme-color($theme, neutral, 11); + color: mat.private-get-theme-color($theme, neutral, 11); } `), ).toThrowError(/Valid hues for neutral are.*Got: 11/); @@ -216,10 +216,52 @@ describe('theming inspection api', () => { transpile(` $theme: ${defineM3Theme()}; div { - content: mat.private-get-theme-color($theme); + color: mat.private-get-theme-color($theme); } `), ).toThrowError(/Expected 2 or 3 arguments. Got: 1/); }); + + it('should get typography properties from theme', () => { + const css = transpile(` + $theme: ${defineM3Theme()}; + div { + font: mat.private-get-theme-typography($theme, headline-large); + font-family: mat.private-get-theme-typography($theme, headline-large, font-family); + font-size: mat.private-get-theme-typography($theme, headline-large, font-size); + font-weight: mat.private-get-theme-typography($theme, headline-large, font-weight); + line-height: mat.private-get-theme-typography($theme, headline-large, line-height); + letter-spacing: mat.private-get-theme-typography($theme, headline-large, letter-spacing); + } + `); + expect(css).toMatch('font: 400 2rem / 2.5rem Google Sans;'); + expect(css).toMatch('font-family: Google Sans;'); + expect(css).toMatch('font-size: 2rem;'); + expect(css).toMatch('font-weight: 400;'); + expect(css).toMatch('line-height: 2.5rem;'); + expect(css).toMatch('letter-spacing: 0rem;'); + }); + }); + + it('should error on invalid typescale', () => { + expect(() => + transpile(` + $theme: ${defineM3Theme()}; + div { + font: mat.private-get-theme-typography($theme, subtitle-large); + } + `), + ).toThrowError(/Valid typescales are:.*Got: subtitle-large/); + }); + + it('should error on invalid typography property', () => { + expect(() => + transpile(` + $theme: ${defineM3Theme()}; + div { + font: mat.private-get-theme-typography($theme, body-small, text-transform); + } + `), + ).toThrowError(/Valid typography properties are:.*Got: text-transform/); }); });