diff --git a/src/material-experimental/theming/_custom-tokens.scss b/src/material-experimental/theming/_custom-tokens.scss index 25e5c0f26821..854381b3bb5d 100644 --- a/src/material-experimental/theming/_custom-tokens.scss +++ b/src/material-experimental/theming/_custom-tokens.scss @@ -59,7 +59,25 @@ text-size: map.get($systems, md-sys-typescale, label-small-size), text-weight: map.get($systems, md-sys-typescale, label-small-weight), small-size-text-size: _hardcode(0, $exclude-hardcoded), + container-shape: map.get($systems, md-sys-shape, corner-full), + container-size: _hardcode(16px, $exclude-hardcoded), + legacy-container-size: _hardcode(unset, $exclude-hardcoded), + legacy-small-size-container-size: _hardcode(unset, $exclude-hardcoded), + small-size-container-size: _hardcode(6px, $exclude-hardcoded), + container-padding: _hardcode(0 4px, $exclude-hardcoded), + small-size-container-padding: _hardcode(0, $exclude-hardcoded), + container-offset: -12px 0, + small-size-container-offset: -6px 0, + container-overlap-offset: -12px, + small-size-container-overlap-offset: -6px, + + // This size isn't in the M3 spec so we emit the same values as for `medium`. + large-size-container-size: _hardcode(16px, $exclude-hardcoded), + large-size-container-offset: -12px 0, + large-size-container-overlap-offset: -12px, large-size-text-size: map.get($systems, md-sys-typescale, label-small-size), + large-size-container-padding: _hardcode(0 4px, $exclude-hardcoded), + legacy-large-size-container-size: _hardcode(unset, $exclude-hardcoded), ), ( primary: ( background-color: map.get($systems, md-sys-color, primary), diff --git a/src/material/badge/_badge-theme.scss b/src/material/badge/_badge-theme.scss index 9e465f92c871..91df4fc15661 100644 --- a/src/material/badge/_badge-theme.scss +++ b/src/material/badge/_badge-theme.scss @@ -13,7 +13,12 @@ @if inspection.get-theme-version($theme) == 1 { @include _theme-from-tokens(inspection.get-theme-tokens($theme, base)); } - @else {} + @else { + @include sass-utils.current-selector-or-root() { + @include token-utils.create-token-values(tokens-mat-badge.$prefix, + tokens-mat-badge.get-unthemable-tokens()); + } + } } /// Outputs color theme styles for the mat-badge. diff --git a/src/material/badge/badge.scss b/src/material/badge/badge.scss index 8aecd84cda02..043505896a82 100644 --- a/src/material/badge/badge.scss +++ b/src/material/badge/badge.scss @@ -1,5 +1,4 @@ @use 'sass:color'; -@use 'sass:math'; @use '@angular/cdk'; @use '../core/tokens/m2/mat/badge' as tokens-mat-badge; @use '../core/tokens/token-utils'; @@ -8,65 +7,33 @@ $default-size: 22px !default; $small-size: $default-size - 6; $large-size: $default-size + 6; - -// Mixin for building offset given different sizes -@mixin _badge-size($size, $font-size-token) { - .mat-badge-content { - width: $size; - height: $size; - line-height: $size; - - @if ($font-size-token) { - @include token-utils.use-tokens(tokens-mat-badge.$prefix, - tokens-mat-badge.get-token-slots()) { - @include token-utils.create-token-slot(font-size, $font-size-token); - } - } - } - - &.mat-badge-above .mat-badge-content { - top: math.div(-$size, 2); - } - - &.mat-badge-below .mat-badge-content { - bottom: math.div(-$size, 2); - } - - &.mat-badge-before .mat-badge-content { - left: -$size; - } - - [dir='rtl'] &.mat-badge-before .mat-badge-content { - left: auto; - right: -$size; - } - - &.mat-badge-after .mat-badge-content { - right: -$size; - } - - [dir='rtl'] &.mat-badge-after .mat-badge-content { - right: auto; - left: -$size; - } - - &.mat-badge-overlap { - &.mat-badge-before .mat-badge-content { - left: math.div(-$size, 2); - } - - [dir='rtl'] &.mat-badge-before .mat-badge-content { - left: auto; - right: math.div(-$size, 2); - } - - &.mat-badge-after .mat-badge-content { - right: math.div(-$size, 2); +@mixin _badge-size($size) { + @include token-utils.use-tokens(tokens-mat-badge.$prefix, tokens-mat-badge.get-token-slots()) { + $prefix: if($size == 'medium', '', $size + '-size-'); + $legacy-size-var: token-utils.get-token-variable('legacy-#{$prefix}container-size'); + $size-var: token-utils.get-token-variable('#{$prefix}container-size'); + + .mat-badge-content { + // The M2 badge is implemented incorrectly because it uses `width` and `height` for its + // size which causes the text to be truncated. For M3 we want to fix this by emitting + // two declarations: + // * `legacy-container-size` token - targets width/height as in M2. In M3 the token is + // emitted as `unset`. + // * `container-size` token - In M2 the token is emitted as `unset` to preserve the legacy + // behavior while in M3 it targets `min-width` and `min-height` which allows the badge to + // grow with the content. + width: var(#{$legacy-size-var}, unset); + height: var(#{$legacy-size-var}, unset); + min-width: var(#{$size-var}, unset); + min-height: var(#{$size-var}, unset); + line-height: var($legacy-size-var, var(#{$size-var})); + @include token-utils.create-token-slot(padding, '#{$prefix}container-padding'); + @include token-utils.create-token-slot(font-size, '#{$prefix}text-size'); + @include token-utils.create-token-slot(margin, '#{$prefix}container-offset'); } - [dir='rtl'] &.mat-badge-after .mat-badge-content { - right: auto; - left: math.div(-$size, 2); + &.mat-badge-overlap .mat-badge-content { + @include token-utils.create-token-slot(margin, '#{$prefix}container-overlap-offset'); } } } @@ -87,25 +54,51 @@ $large-size: $default-size + 6; position: absolute; text-align: center; display: inline-block; - border-radius: 50%; transition: transform 200ms ease-in-out; transform: scale(0.6); overflow: hidden; white-space: nowrap; text-overflow: ellipsis; + box-sizing: border-box; pointer-events: none; + @include cdk.high-contrast(active, off) { + outline: solid 1px; + border-radius: 0; + } + @include token-utils.use-tokens(tokens-mat-badge.$prefix, tokens-mat-badge.get-token-slots()) { @include token-utils.create-token-slot(background-color, background-color); @include token-utils.create-token-slot(color, text-color); @include token-utils.create-token-slot(font-family, text-font); - @include token-utils.create-token-slot(font-size, text-size); @include token-utils.create-token-slot(font-weight, text-weight); - } + @include token-utils.create-token-slot(border-radius, container-shape); - @include cdk.high-contrast(active, off) { - outline: solid 1px; - border-radius: 0; + .mat-badge-above & { + bottom: 100%; + } + + .mat-badge-below & { + top: 100%; + } + + .mat-badge-before & { + right: 100%; + } + + [dir='rtl'] .mat-badge-before & { + right: auto; + left: 100%; + } + + .mat-badge-after & { + left: 100%; + } + + [dir='rtl'] .mat-badge-after & { + left: auto; + right: 100%; + } } } @@ -133,13 +126,13 @@ $large-size: $default-size + 6; } .mat-badge-small { - @include _badge-size($small-size, small-size-text-size); + @include _badge-size('small'); } .mat-badge-medium { - @include _badge-size($default-size, null); + @include _badge-size('medium'); } .mat-badge-large { - @include _badge-size($large-size, large-size-text-size); + @include _badge-size('large'); } diff --git a/src/material/core/tokens/m2/mat/_badge.scss b/src/material/core/tokens/m2/mat/_badge.scss index 72725ad7d3b9..9c28ff0bbb43 100644 --- a/src/material/core/tokens/m2/mat/_badge.scss +++ b/src/material/core/tokens/m2/mat/_badge.scss @@ -1,5 +1,6 @@ @use 'sass:meta'; @use 'sass:map'; +@use 'sass:math'; @use 'sass:color'; @use '../../token-utils'; @use '../../../theming/inspection'; @@ -11,7 +12,32 @@ $prefix: (mat, badge); // Tokens that can't be configured through Angular Material's current theming API, // but may be in a future version of the theming API. @function get-unthemable-tokens() { - @return (); + $default-size: 22px; + $small-size: $default-size - 6; + $large-size: $default-size + 6; + + @return ( + container-shape: 50%, + container-size: unset, + small-size-container-size: unset, + large-size-container-size: unset, + + legacy-container-size: $default-size, + legacy-small-size-container-size: $small-size, + legacy-large-size-container-size: $large-size, + + container-offset: math.div($default-size, -2) 0, + small-size-container-offset: math.div($small-size, -2) 0, + large-size-container-offset: math.div($large-size, -2) 0, + + container-overlap-offset: math.div($default-size, -2), + small-size-container-overlap-offset: math.div($small-size, -2), + large-size-container-overlap-offset: math.div($large-size, -2), + + container-padding: 0, + small-size-container-padding: 0, + large-size-container-padding: 0, + ); } // Tokens that can be configured through Angular Material's color theming API.