Skip to content

refactor(material/table): switch to tokens API #27192

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions src/material/core/tokens/_token-utils.scss
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,21 @@ $_component-prefix: null;

// Emits a slot for the given token, provided that it has a non-null value in the token map passed
// to `use-tokens`.
@mixin create-token-slot($property, $token) {
@mixin create-token-slot($property, $token, $emit-fallback: false) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we comment that having emit-fallback = true would be for temporary workarounds?

@if $_component-prefix == null or $_tokens == null {
@error '`create-token-slot` must be used within `use-tokens`';
}
@if map.get($_tokens, $token) != null {
$value: mdc-custom-properties.create('#{$_component-prefix}-#{$token}');
$fallback: null;

@if ($emit-fallback == true) {
$fallback: map.get($_tokens, $token);
}
@else if ($emit-fallback) {
$fallback: $emit-fallback;
}

$value: mdc-custom-properties.create('#{$_component-prefix}-#{$token}', $fallback: $fallback);
@include mdc-theme.property($property, $value);
}
}
Expand Down
97 changes: 97 additions & 0 deletions src/material/core/tokens/m2/mat/_table.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
@use 'sass:map';
@use '../../../theming/theming';
@use '../../../typography/typography-utils';
@use '../../token-utils';
@use '../../../style/sass-utils';

// The prefix used to generate the fully qualified name for tokens in this file.
$prefix: (mat, table);

// 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 (
row-item-outline-width: 1px,
);
}

// Tokens that can be configured through Angular Material's color theming API.
@function get-color-tokens($config) {
$foreground: map.get($config, foreground);
$background: map.get($config, background);

@return (
background-color: theming.get-color-from-palette($background, 'card'),

header-headline-color: theming.get-color-from-palette($foreground, text),
row-item-label-text-color: theming.get-color-from-palette($foreground, text),
row-item-outline-color: theming.get-color-from-palette($foreground, divider),
);
}

// Tokens that can be configured through Angular Material's typography theming API.
@function get-typography-tokens($config) {
$fallback-font: typography-utils.font-family($config);
$cell-font-family: typography-utils.font-family($config, body-2) or $fallback-font;
$cell-line-height: typography-utils.line-height($config, body-2);
$cell-font-size: typography-utils.font-size($config, body-2);
$cell-font-weight: typography-utils.font-weight($config, body-2);
$cell-letter-spacing: typography-utils.letter-spacing($config, body-2);

@return (
header-headline-font: typography-utils.font-family($config, subtitle-2) or $fallback-font,
header-headline-line-height: typography-utils.line-height($config, subtitle-2),
header-headline-size: typography-utils.font-size($config, subtitle-2),
header-headline-weight: typography-utils.font-weight($config, subtitle-2),
header-headline-tracking: typography-utils.letter-spacing($config, subtitle-2),

// Plain cells and footer cells have the same typography.
row-item-label-text-font: $cell-font-family,
row-item-label-text-line-height: $cell-line-height,
row-item-label-text-size: $cell-font-size,
row-item-label-text-weight: $cell-font-weight,
row-item-label-text-tracking: $cell-letter-spacing,

footer-supporting-text-font: $cell-font-family,
footer-supporting-text-line-height: $cell-line-height,
footer-supporting-text-size: $cell-font-size,
footer-supporting-text-weight: $cell-font-weight,
footer-supporting-text-tracking: $cell-letter-spacing,
);
}

// Tokens that can be configured through Angular Material's density theming API.
@function get-density-tokens($config) {
$scale: theming.clamp-density($config, -4);
$header-scale: (
0: 56px,
-1: 52px,
-2: 48px,
-3: 44px,
-4: 40px
);
$cell-scale: (
0: 52px,
-1: 48px,
-2: 44px,
-3: 40px,
-4: 36px
);

@return (
header-container-height: map.get($header-scale, $scale),
footer-container-height: map.get($cell-scale, $scale),
row-item-container-height: map.get($cell-scale, $scale),
);
}

// Combines the tokens generated by the above functions into a single map with placeholder values.
// This is used to create token slots.
@function get-token-slots() {
@return sass-utils.deep-merge-all(
get-unthemable-tokens(),
get-color-tokens(token-utils.$placeholder-color-config),
get-typography-tokens(token-utils.$placeholder-typography-config),
get-density-tokens(token-utils.$placeholder-density-config)
);
}
64 changes: 24 additions & 40 deletions src/material/table/_table-theme.scss
Original file line number Diff line number Diff line change
@@ -1,60 +1,44 @@
@use 'sass:map';
@use '@material/theme/theme-color' as mdc-theme-color;
@use '@material/data-table/data-table' as mdc-data-table;
@use '@material/data-table' as mdc-data-table-theme;
@use '../core/tokens/m2/mat/table' as tokens-mat-table;
@use '../core/theming/theming';
@use '../core/mdc-helpers/mdc-helpers';
@use '../core/typography/typography';
@use '../core/tokens/token-utils';

@mixin color($config-or-theme) {
$config: theming.get-color-config($config-or-theme);
// Save original values of MDC global variables. We need to save these so we can restore the
// variables to their original values and prevent unintended side effects from using this mixin.
$orig-selected-row-fill-color: mdc-data-table-theme.$selected-row-fill-color;
$orig-divider-color: mdc-data-table-theme.$divider-color;
$orig-row-hover-fill-color: mdc-data-table-theme.$row-hover-fill-color;
$orig-header-row-text-color: mdc-data-table-theme.$header-row-text-color;
$orig-row-text-color: mdc-data-table-theme.$row-text-color;
$orig-stroke-color: mdc-data-table-theme.$stroke-color;

@include mdc-helpers.using-mdc-theme($config) {
mdc-data-table-theme.$selected-row-fill-color: rgba(mdc-theme-color.prop-value(primary), 0.04);
mdc-data-table-theme.$divider-color: rgba(mdc-theme-color.prop-value(on-surface), 0.12);
mdc-data-table-theme.$row-hover-fill-color: rgba(mdc-theme-color.prop-value(on-surface), 0.04);
mdc-data-table-theme.$header-row-text-color: rgba(mdc-theme-color.prop-value(on-surface), 0.87);
mdc-data-table-theme.$row-text-color: rgba(mdc-theme-color.prop-value(on-surface), 0.87);
mdc-data-table-theme.$stroke-color: rgba(mdc-theme-color.prop-value(on-surface), 0.12);

@include mdc-data-table.table-styles($query: mdc-helpers.$mdc-theme-styles-query);
@mixin _output-tokens {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use this function instead: https://github.com/angular/components/blob/main/src/material/core/style/_sass-utils.scss#L11

Also, I'm not sure we need to clean it up, I'd like to move toward emitting the tokens under the user's selector (or document root if they don't specify one)

@if (&) {
@content;
}
@else {
html {
@content;
}
}
}

// Restore original values of MDC global variables.
mdc-data-table-theme.$selected-row-fill-color: $orig-selected-row-fill-color;
mdc-data-table-theme.$divider-color: $orig-divider-color;
mdc-data-table-theme.$row-hover-fill-color: $orig-row-hover-fill-color;
mdc-data-table-theme.$header-row-text-color: $orig-header-row-text-color;
mdc-data-table-theme.$row-text-color: $orig-row-text-color;
mdc-data-table-theme.$stroke-color: $orig-stroke-color;
@mixin color($config-or-theme) {
$config: theming.get-color-config($config-or-theme);

.mat-mdc-table {
$background: map.get($config, background);
background: theming.get-color-from-palette($background, 'card');
@include _output-tokens {
@include token-utils.create-token-values(tokens-mat-table.$prefix,
tokens-mat-table.get-color-tokens($config));
}
}

@mixin typography($config-or-theme) {
$config: typography.private-typography-to-2018-config(
theming.get-typography-config($config-or-theme));
@include mdc-helpers.using-mdc-typography($config) {
@include mdc-data-table.table-styles($query: mdc-helpers.$mdc-typography-styles-query);

@include _output-tokens {
@include token-utils.create-token-values(tokens-mat-table.$prefix,
tokens-mat-table.get-typography-tokens($config));
}
}

@mixin density($config-or-theme) {
$density-scale: theming.get-density-config($config-or-theme);
.mat-mdc-table {
@include mdc-data-table-theme.density($density-scale,
$query: mdc-helpers.$mdc-base-styles-query);

@include _output-tokens {
@include token-utils.create-token-values(tokens-mat-table.$prefix,
tokens-mat-table.get-density-tokens($density-scale));
}
}

Expand Down
108 changes: 95 additions & 13 deletions src/material/table/table.scss
Original file line number Diff line number Diff line change
@@ -1,21 +1,40 @@
@use '@material/data-table/data-table' as mdc-data-table;
@use '@material/data-table/data-table-cell' as mdc-data-table-cell;
@use '@material/data-table/data-table-header-cell' as mdc-data-table-header-cell;
@use '@material/data-table' as mdc-data-table-theme;
@use '@material/typography/typography' as mdc-typography;
@use '../core/mdc-helpers/mdc-helpers';
@use '../core/tokens/token-utils';
@use '../core/tokens/m2/mat/table' as tokens-mat-table;
@use './table-flex-styles';

@include mdc-helpers.disable-mdc-fallback-declarations {
@include mdc-data-table.table-styles(
$query: mdc-helpers.$mdc-base-styles-without-animation-query);
@include table-flex-styles.private-table-flex-styles();
}

.mat-mdc-table-sticky {
// Note that the table can either set this class or an inline style to make something sticky.
// We set the style as `!important` so that we get an identical specificity in both cases
// and to avoid cases where user styles have a higher specificity.
position: sticky !important;
}

@mixin _cell-border {
@include token-utils.create-token-slot(border-bottom-color, row-item-outline-color, true);
@include token-utils.create-token-slot(border-bottom-width, row-item-outline-width, true);
border-bottom-style: solid;
}

@include mdc-data-table.static-styles($query: mdc-helpers.$mdc-base-styles-query);
@include mdc-data-table-cell.static-styles($query: mdc-helpers.$mdc-base-styles-query);
@include mdc-data-table-header-cell.static-styles($query: mdc-helpers.$mdc-base-styles-query);
@include mdc-data-table-theme.cell-padding(
$leading-padding: mdc-data-table-theme.$cell-leading-padding,
$trailing-padding: mdc-data-table-theme.$cell-trailing-padding,
$query: mdc-helpers.$mdc-base-styles-query
);
@include table-flex-styles.private-table-flex-styles();

.mat-mdc-table {
@include token-utils.create-token-values(
tokens-mat-table.$prefix, tokens-mat-table.get-unthemable-tokens());

// MDC Table applies `table-layout: fixed`, but this is a backwards incompatible
// change since the table did not previously apply it.
// TODO: Add a mixin to MDC to set the layout instead of including this override,
Expand All @@ -25,6 +44,76 @@
// The MDC table does not allow text to wrap within the cell. This allows for text to
// wrap when the cell reaches its maximum width.
white-space: normal;

@include token-utils.use-tokens(tokens-mat-table.$prefix, tokens-mat-table.get-token-slots()) {
@include token-utils.create-token-slot(background-color, background-color);
}
}

@include mdc-helpers.disable-mdc-fallback-declarations {
@include token-utils.use-tokens(tokens-mat-table.$prefix, tokens-mat-table.get-token-slots()) {
// TODO(crisbeto): these tokens have default values in order to make the initial token
// work easier to land in g3. Eventually we should remove them.
.mat-mdc-header-row {
@include mdc-typography.smooth-font();
@include token-utils.create-token-slot(height, header-container-height, 56px);
@include token-utils.create-token-slot(color, header-headline-color, true);
@include token-utils.create-token-slot(font-family, header-headline-font, true);
@include token-utils.create-token-slot(line-height, header-headline-line-height);
@include token-utils.create-token-slot(font-size, header-headline-size, 14px);
@include token-utils.create-token-slot(font-weight, header-headline-weight, 500);
}

.mat-mdc-row {
@include token-utils.create-token-slot(height, row-item-container-height, 52px);
@include token-utils.create-token-slot(color, row-item-label-text-color, true);
}

// Note that while it's redundant to apply the typography both to the row
// and the content element since the cell inherit from both of them,
// applying it only to one results in sub-pixel differences in the
// letter spacing which leads to a lot of internal screenshot diffs.
.mat-mdc-row,
.mdc-data-table__content {
@include mdc-typography.smooth-font();
@include token-utils.create-token-slot(font-family, row-item-label-text-font, true);
@include token-utils.create-token-slot(line-height, row-item-label-text-line-height);
@include token-utils.create-token-slot(font-size, row-item-label-text-size, 14px);
@include token-utils.create-token-slot(font-weight, row-item-label-text-weight);
}

.mat-mdc-footer-row {
@include mdc-typography.smooth-font();
@include token-utils.create-token-slot(height, footer-container-height, 52px);
@include token-utils.create-token-slot(color, row-item-label-text-color, true);
@include token-utils.create-token-slot(font-family, footer-supporting-text-font, true);
@include token-utils.create-token-slot(line-height, footer-supporting-text-line-height);
@include token-utils.create-token-slot(font-size, footer-supporting-text-size, 14px);
@include token-utils.create-token-slot(font-weight, footer-supporting-text-weight);
@include token-utils.create-token-slot(letter-spacing, footer-supporting-text-tracking);
}

.mat-mdc-header-cell {
@include _cell-border;
@include token-utils.create-token-slot(letter-spacing, header-headline-tracking);
font-weight: inherit;
line-height: inherit;
}

.mat-mdc-cell {
@include _cell-border;
@include token-utils.create-token-slot(letter-spacing, row-item-label-text-tracking);
line-height: inherit;

.mdc-data-table__row:last-child & {
border-bottom: none;
}
}

.mat-mdc-footer-cell {
@include token-utils.create-token-slot(letter-spacing, row-item-label-text-tracking);
}
}
}

// MDC table rows are styled with a top border, whereas our legacy flex table styles rows with
Expand All @@ -43,13 +132,6 @@ mat-row.mat-mdc-row, mat-header-row.mat-mdc-header-row, mat-footer-row.mat-mdc-f
background: inherit;
}

// Disable hover styling while MDC uses an opacity for its color.
// When the hover style is used with sticky cells, the opacity shows the cells overlapping.
.mat-mdc-table .mat-mdc-row:hover,
.mat-mdc-table .mat-mdc-footer-row:hover {
background-color: inherit;
}

// Flex rows should not set a definite height, but instead stretch to the height of their
// children. Otherwise, the cells grow larger than the row and the layout breaks.
.mat-mdc-table mat-header-row.mat-mdc-header-row,
Expand Down