From 5b13b5c05bdbe7a85e30408a33a07de6480317d2 Mon Sep 17 00:00:00 2001 From: Elizabeth Mitchell Date: Tue, 29 Aug 2023 10:47:23 -0700 Subject: [PATCH] fix(tabs)!: split md-tab into md-primary-tab and md-secondary-tab BREAKING CHANGE: remove `variant` attributes and change `md-tab` to `md-primary-tab`, or `md-secondary-tab` if using `variant="secondary" PiperOrigin-RevId: 561077231 --- all.ts | 6 +- catalog/src/ssr.ts | 3 +- common.ts | 4 +- docs/components/tabs.md | 186 ++++++++++++---- tabs/{_tab.scss => _primary-tab.scss} | 2 +- tabs/_secondary-tab.scss | 6 + tabs/demo/stories.ts | 133 ++++++------ tabs/internal/_primary-tab.scss | 61 ++++++ tabs/internal/_secondary-tab.scss | 69 ++++++ tabs/internal/_tab.scss | 99 +-------- tabs/internal/primary-tab-styles.scss | 10 + tabs/internal/primary-tab.ts | 12 ++ tabs/internal/secondary-tab-styles.scss | 10 + tabs/internal/secondary-tab.ts | 12 ++ tabs/internal/tab.ts | 11 +- tabs/internal/tabs.ts | 28 +-- tabs/primary-tab.ts | 27 +++ tabs/secondary-tab.ts | 27 +++ tabs/tab.ts | 28 --- tabs/tabs.ts | 4 - tabs/tabs_test.ts | 19 +- tokens/_index.scss | 3 +- tokens/_md-comp-primary-tab.scss | 134 ++++++++++++ tokens/_md-comp-secondary-tab.scss | 139 ++++++++++++ tokens/_md-comp-tab.scss | 272 ------------------------ 25 files changed, 749 insertions(+), 556 deletions(-) rename tabs/{_tab.scss => _primary-tab.scss} (61%) create mode 100644 tabs/_secondary-tab.scss create mode 100644 tabs/internal/_primary-tab.scss create mode 100644 tabs/internal/_secondary-tab.scss create mode 100644 tabs/internal/primary-tab-styles.scss create mode 100644 tabs/internal/primary-tab.ts create mode 100644 tabs/internal/secondary-tab-styles.scss create mode 100644 tabs/internal/secondary-tab.ts create mode 100644 tabs/primary-tab.ts create mode 100644 tabs/secondary-tab.ts delete mode 100644 tabs/tab.ts create mode 100644 tokens/_md-comp-primary-tab.scss create mode 100644 tokens/_md-comp-secondary-tab.scss delete mode 100644 tokens/_md-comp-tab.scss diff --git a/all.ts b/all.ts index 88e1ea3310..e1a5af0cac 100644 --- a/all.ts +++ b/all.ts @@ -50,7 +50,8 @@ import './select/outlined-select.js'; import './select/select-option.js'; import './slider/slider.js'; import './switch/switch.js'; -import './tabs/tab.js'; +import './tabs/primary-tab.js'; +import './tabs/secondary-tab.js'; import './tabs/tabs.js'; import './textfield/filled-text-field.js'; import './textfield/outlined-text-field.js'; @@ -96,7 +97,8 @@ export * from './select/outlined-select.js'; export * from './select/select-option.js'; export * from './slider/slider.js'; export * from './switch/switch.js'; -export * from './tabs/tab.js'; +export * from './tabs/primary-tab.js'; +export * from './tabs/secondary-tab.js'; export * from './tabs/tabs.js'; export * from './textfield/filled-text-field.js'; export * from './textfield/outlined-text-field.js'; diff --git a/catalog/src/ssr.ts b/catalog/src/ssr.ts index abd303e2ea..1e4a57c351 100644 --- a/catalog/src/ssr.ts +++ b/catalog/src/ssr.ts @@ -18,7 +18,8 @@ import '@material/web/list/list.js'; import '@material/web/list/list-item.js'; import '@material/web/progress/circular-progress.js'; import '@material/web/tabs/tabs.js'; -import '@material/web/tabs/tab.js'; +import '@material/web/tabs/primary-tab.js'; +import '@material/web/tabs/secondary-tab.js'; import '@material/web/iconbutton/icon-button.js'; import '@material/web/iconbutton/filled-icon-button.js'; import '@material/web/iconbutton/filled-tonal-icon-button.js'; diff --git a/common.ts b/common.ts index 72c903bc19..ab13c020e2 100644 --- a/common.ts +++ b/common.ts @@ -34,7 +34,7 @@ import './progress/linear-progress.js'; import './radio/radio.js'; import './select/outlined-select.js'; import './select/select-option.js'; -import './tabs/tab.js'; +import './tabs/primary-tab.js'; import './tabs/tabs.js'; import './textfield/outlined-text-field.js'; // go/keep-sorted end @@ -61,7 +61,7 @@ export * from './progress/linear-progress.js'; export * from './radio/radio.js'; export * from './select/outlined-select.js'; export * from './select/select-option.js'; -export * from './tabs/tab.js'; +export * from './tabs/primary-tab.js'; export * from './tabs/tabs.js'; export * from './textfield/outlined-text-field.js'; // go/keep-sorted end diff --git a/docs/components/tabs.md b/docs/components/tabs.md index 826e5c23b6..0b5ce89ff9 100644 --- a/docs/components/tabs.md +++ b/docs/components/tabs.md @@ -12,7 +12,11 @@ dirname: tabs @@ -44,6 +48,11 @@ related content that are at the same level of hierarchy. * [Source code](https://github.com/material-components/material-web/tree/main/tabs) +## Types + +1. [Primary tabs](#primary-tabs) +1. [Secondary tabs](#secondary-tabs) + + + + ```html - - - Keyboard - - - - Guitar - + Video + Photos + Audio - - - - - Travel - - - - Hotel - - - - Activities - + + Birds + Cats + Dogs ``` +### Selection + To observe changes to tab selections, add an event listener to ``, listening for the `change` event. @@ -107,20 +102,82 @@ tabs.addEventListener('change', (event: Event) => { }); ``` -### Scrollable +### Icons + +Tabs may optionally show an icon. + +Icons communicate the type of content within a tab. Icons should be simple and +recognizable. + + + + + + +```html + + + piano + Keyboard + + + tune + Guitar + + +``` + +## Primary tabs -When a set of tabs cannot fit on screen or container, use scrollable tabs. -Scrollable tabs can use longer text labels and a larger number of tabs. They are -best used for browsing on touch interfaces. + -![Tabs truncated horizontally showing "Tab 1", "Tab 2", "Tab 3", and "Ta".](images/tabs/scrollable.png) +Primary tabs are placed at the top of the content pane under a top app bar. They +display the main content destinations. + + + + + ```html - Tab 1 - Tab 2 - Tab 3 - Tab 4 + + piano + Keyboard + + + tune + Guitar + + +``` + +## Secondary tabs + + + +Secondary tabs are used within a content area to further separate related +content and establish hierarchy. + + + + + + +```html + + + flight + Travel + + + hotel + Hotel + + + hiking + Activities + ``` @@ -131,21 +188,20 @@ best used for browsing on touch interfaces. Tabs supports [Material theming](../theming.md) and can be customized in terms of color, typography, and shape. -### Tokens +### Primary tab tokens Token | Default value ----------------------------------------- | ----------------------------------- `--md-primary-tab-container-color` | `--md-sys-color-surface` -`--md-secondary-tab-container-color` | `--md-sys-color-surface` `--md-primary-tab-label-text-type` | `500 0.875rem/1.25rem Roboto` `--md-primary-tab-active-indicator-color` | `--md-sys-color-primary` `--md-primary-tab-icon-color` | `--md-sys-color-on-surface-variant` `--md-primary-tab-container-shape` | `0px` -* [All tokens](https://github.com/material-components/material-web/blob/main/tokens/_md-comp-tab.scss) +* [All tokens](https://github.com/material-components/material-web/blob/main/tokens/_md-comp-primary-tab.scss) -### Example +### Primary tab example @@ -166,8 +222,46 @@ Token | Default value - Tab 1 - Tab 2 - Tab 3 + Tab 1 + Tab 2 + Tab 3 + +``` + +### Secondary tab tokens + +Token | Default value +------------------------------------------- | ------------- +`--md-secondary-tab-container-color` | `--md-sys-color-surface` +`--md-secondary-tab-label-text-type` | `500 0.875rem/1.25rem Roboto` +`--md-secondary-tab-active-indicator-color` | `--md-sys-color-primary` +`--md-secondary-tab-icon-color` | `--md-sys-color-on-surface-variant` +`--md-secondary-tab-container-shape` | `0px` + +* [All tokens](https://github.com/material-components/material-web/blob/main/tokens/_md-comp-secondary-tab.scss) + + +### Secondary tab example + + + + + +```html + + + + Tab 1 + Tab 2 + Tab 3 ``` diff --git a/tabs/_tab.scss b/tabs/_primary-tab.scss similarity index 61% rename from tabs/_tab.scss rename to tabs/_primary-tab.scss index 952b5054ab..07f04d7bfb 100644 --- a/tabs/_tab.scss +++ b/tabs/_primary-tab.scss @@ -3,4 +3,4 @@ // SPDX-License-Identifier: Apache-2.0 // -@forward './internal/tab' show theme; +@forward './internal/primary-tab' show theme; diff --git a/tabs/_secondary-tab.scss b/tabs/_secondary-tab.scss new file mode 100644 index 0000000000..834c79c716 --- /dev/null +++ b/tabs/_secondary-tab.scss @@ -0,0 +1,6 @@ +// +// Copyright 2023 Google LLC +// SPDX-License-Identifier: Apache-2.0 +// + +@forward './internal/secondary-tab' show theme; diff --git a/tabs/demo/stories.ts b/tabs/demo/stories.ts index 0ba2289f2a..d74413d6ba 100644 --- a/tabs/demo/stories.ts +++ b/tabs/demo/stories.ts @@ -7,6 +7,8 @@ import '@material/web/icon/icon.js'; import '@material/web/iconbutton/icon-button.js'; import '@material/web/tabs/tabs.js'; +import '@material/web/tabs/primary-tab.js'; +import '@material/web/tabs/secondary-tab.js'; import {MaterialStoryInit} from './material-collection.js'; import {MdTabs} from '@material/web/tabs/tabs.js'; @@ -53,25 +55,24 @@ const primary: MaterialStoryInit = { return html` - + ${tabContent('piano', 'Keyboard')} - - + + ${tabContent('tune', 'Guitar')} - - + + ${tabContent('graphic_eq', 'Drums')} - - + + ${tabContent('speaker', 'Bass')} - - + + ${tabContent('nightlife', 'Saxophone')} - + `; } }; @@ -85,22 +86,21 @@ const secondary: MaterialStoryInit = { return html` - + ${tabContent('flight', 'Travel')} - - + + ${tabContent('hotel', 'Hotel')} - - + + ${tabContent('hiking', 'Activities')} - - + + ${tabContent('restaurant', 'Food')} - + `; } }; @@ -115,26 +115,25 @@ const scrolling: MaterialStoryInit = { return html` ${new Array(10).fill(html` - + ${tabContent('piano', 'Keyboard')} - - + + ${tabContent('tune', 'Guitar')} - - + + ${tabContent('graphic_eq', 'Drums')} - - + + ${tabContent('speaker', 'Bass')} - - + + ${tabContent('nightlife', 'Saxophone')} - + `)} `; } @@ -177,22 +176,21 @@ const custom: MaterialStoryInit = { return html` - + ${tabContent('flight', 'Travel')} - - + + ${tabContent('hotel', 'Hotel')} - - + + ${tabContent('hiking', 'Activities')} - - + + ${tabContent('restaurant', 'Food')} - + `; } }; @@ -229,58 +227,54 @@ const primaryAndSecondary: MaterialStoryInit = { return html`
- + ${tabContent('videocam', 'Movies')} - - + + ${tabContent('photo', 'Photos')} - - + + ${tabContent('audiotrack', 'Music')} - +
- Star Wars - Avengers - Jaws - Frozen + Star Wars + Avengers + Jaws + Frozen
@@ -303,7 +297,7 @@ const dynamic: MaterialStoryInit = { function addTab(event: Event) { const tabs = getTabs(event); const count = tabs.childElementCount; - const tab = document.createElement('md-tab'); + const tab = document.createElement('md-primary-tab'); tab.textContent = `Tab ${count + 1}`; if (tabs.selectedItem !== undefined) { tabs.selectedItem.after(tab); @@ -353,19 +347,18 @@ const dynamic: MaterialStoryInit = {
- + Tab 1 - - + + Tab 2 - - + + Tab 3 - + `; } }; diff --git a/tabs/internal/_primary-tab.scss b/tabs/internal/_primary-tab.scss new file mode 100644 index 0000000000..9ed25468bf --- /dev/null +++ b/tabs/internal/_primary-tab.scss @@ -0,0 +1,61 @@ +// +// Copyright 2023 Google LLC +// SPDX-License-Identifier: Apache-2.0 +// + +// go/keep-sorted start +@use 'sass:list'; +// go/keep-sorted end +// go/keep-sorted start +@use '../../tokens'; +// go/keep-sorted end + +@mixin theme($tokens) { + $supported-tokens: list.join( + tokens.$md-comp-primary-tab-supported-tokens, + ( + 'container-shape-start-start', + 'container-shape-start-end', + 'container-shape-end-end', + 'container-shape-end-start' + ) + ); + + @each $token, $value in $tokens { + @if list.index($supported-tokens, $token) == null { + @error 'Token `#{$token}` is not a supported token.'; + } + + @if $value { + --md-primary-tab-#{$token}: #{$value}; + } + } +} + +@mixin styles() { + $tokens: tokens.md-comp-primary-tab-values(); + + :host { + @each $token, $value in $tokens { + --_#{$token}: var(--md-primary-tab-#{$token}, #{$value}); + } + + // Support logical shape properties + --_container-shape-start-start: var( + --md-primary-tab-container-shape-start-start, + var(--_container-shape) + ); + --_container-shape-start-end: var( + --md-primary-tab-container-shape-start-end, + var(--_container-shape) + ); + --_container-shape-end-end: var( + --md-primary-tab-container-shape-end-end, + var(--_container-shape) + ); + --_container-shape-end-start: var( + --md-primary-tab-container-shape-end-start, + var(--_container-shape) + ); + } +} diff --git a/tabs/internal/_secondary-tab.scss b/tabs/internal/_secondary-tab.scss new file mode 100644 index 0000000000..22bcedd81f --- /dev/null +++ b/tabs/internal/_secondary-tab.scss @@ -0,0 +1,69 @@ +// +// Copyright 2023 Google LLC +// SPDX-License-Identifier: Apache-2.0 +// + +// go/keep-sorted start +@use 'sass:list'; +// go/keep-sorted end +// go/keep-sorted start +@use '../../tokens'; +// go/keep-sorted end + +@mixin theme($tokens) { + $supported-tokens: list.join( + tokens.$md-comp-secondary-tab-supported-tokens, + ( + 'container-shape-start-start', + 'container-shape-start-end', + 'container-shape-end-end', + 'container-shape-end-start' + ) + ); + + @each $token, $value in $tokens { + @if list.index($supported-tokens, $token) == null { + @error 'Token `#{$token}` is not a supported token.'; + } + + @if $value { + --md-secondary-tab-#{$token}: #{$value}; + } + } +} + +@mixin styles() { + $tokens: tokens.md-comp-secondary-tab-values(); + + :host { + @each $token, $value in $tokens { + --_#{$token}: var(--md-secondary-tab-#{$token}, #{$value}); + } + + // Support logical shape properties + --_container-shape-start-start: var( + --md-secondary-tab-container-shape-start-start, + var(--_container-shape) + ); + --_container-shape-start-end: var( + --md-secondary-tab-container-shape-start-end, + var(--_container-shape) + ); + --_container-shape-end-end: var( + --md-secondary-tab-container-shape-end-end, + var(--_container-shape) + ); + --_container-shape-end-start: var( + --md-secondary-tab-container-shape-end-start, + var(--_container-shape) + ); + } + + .content { + width: 100%; + } + + .indicator { + min-width: 100%; + } +} diff --git a/tabs/internal/_tab.scss b/tabs/internal/_tab.scss index cc2373435e..8ea5a305d3 100644 --- a/tabs/internal/_tab.scss +++ b/tabs/internal/_tab.scss @@ -15,64 +15,8 @@ @use '../../tokens'; // go/keep-sorted end -@mixin theme($tokens) { - $supported-tokens: list.join( - tokens.$md-comp-tab-supported-tokens, - ( - 'primary-tab-container-shape-start-start', - 'primary-tab-container-shape-start-end', - 'primary-tab-container-shape-end-end', - 'primary-tab-container-shape-end-start', - 'secondary-tab-container-shape-start-start', - 'secondary-tab-container-shape-start-end', - 'secondary-tab-container-shape-end-end', - 'secondary-tab-container-shape-end-start' - ) - ); - - @each $token, $value in $tokens { - @if list.index($supported-tokens, $token) == null { - @error 'Token `#{$token}` is not a supported token.'; - } - - @if $value { - --md-#{$token}: #{$value}; - } - } -} - @mixin styles() { - // contains tokens for all variants and applied where needed - $tokens: tokens.md-comp-tab-values(); - :host { - // apply primary-tokens by default - $primary-prefix: 'primary-tab-'; - @each $token, $value in $tokens { - @if string-ext.has-prefix($token, $primary-prefix) { - $token: string-ext.trim-prefix(#{$token}, $primary-prefix); - --_#{$token}: var(--md-#{$primary-prefix}#{$token}, #{$value}); - } - } - - // Support logical shape properties - --_container-shape-start-start: var( - --md-primary-tab-container-shape-start-start, - var(--_container-shape) - ); - --_container-shape-start-end: var( - --md-primary-tab-container-shape-start-end, - var(--_container-shape) - ); - --_container-shape-end-end: var( - --md-primary-tab-container-shape-end-end, - var(--_container-shape) - ); - --_container-shape-end-start: var( - --md-primary-tab-container-shape-end-start, - var(--_container-shape) - ); - display: inline-flex; outline: none; -webkit-tap-highlight-color: transparent; @@ -264,53 +208,14 @@ color: var(--_active-pressed-icon-color); } - // secondary - :host([variant~='secondary']) { - // apply secondary-tab tokens - $secondary-prefix: 'secondary-tab-'; - @each $token, $value in $tokens { - @if string-ext.has-prefix($token, $secondary-prefix) { - $token: string-ext.trim-prefix(#{$token}, $secondary-prefix); - --_#{$token}: var(--md-#{$secondary-prefix}#{$token}, #{$value}); - } - } - - // Support logical shape properties - --_container-shape-start-start: var( - --md-secondary-tab-container-shape-start-start, - var(--_container-shape) - ); - --_container-shape-start-end: var( - --md-secondary-tab-container-shape-start-end, - var(--_container-shape) - ); - --_container-shape-end-end: var( - --md-secondary-tab-container-shape-end-end, - var(--_container-shape) - ); - --_container-shape-end-start: var( - --md-secondary-tab-container-shape-end-start, - var(--_container-shape) - ); - } - - :host([variant~='secondary']) .content { - width: 100%; - } - - :host([variant~='secondary']) .indicator { - min-width: 100%; - } - :host, ::slotted(*) { white-space: nowrap; } @media (forced-colors: active) { - :host, - :host([variant]) { - --_active-indicator-color: CanvasText; + .indicator { + background: CanvasText; } } } diff --git a/tabs/internal/primary-tab-styles.scss b/tabs/internal/primary-tab-styles.scss new file mode 100644 index 0000000000..072a5641d1 --- /dev/null +++ b/tabs/internal/primary-tab-styles.scss @@ -0,0 +1,10 @@ +// +// Copyright 2023 Google LLC +// SPDX-License-Identifier: Apache-2.0 +// + +// go/keep-sorted start +@use './primary-tab'; +// go/keep-sorted end + +@include primary-tab.styles; diff --git a/tabs/internal/primary-tab.ts b/tabs/internal/primary-tab.ts new file mode 100644 index 0000000000..259c06b6de --- /dev/null +++ b/tabs/internal/primary-tab.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {Tab} from './tab.js'; + +/** + * A primary tab component. + */ +export class PrimaryTab extends Tab {} diff --git a/tabs/internal/secondary-tab-styles.scss b/tabs/internal/secondary-tab-styles.scss new file mode 100644 index 0000000000..f73c469144 --- /dev/null +++ b/tabs/internal/secondary-tab-styles.scss @@ -0,0 +1,10 @@ +// +// Copyright 2023 Google LLC +// SPDX-License-Identifier: Apache-2.0 +// + +// go/keep-sorted start +@use './secondary-tab'; +// go/keep-sorted end + +@include secondary-tab.styles; diff --git a/tabs/internal/secondary-tab.ts b/tabs/internal/secondary-tab.ts new file mode 100644 index 0000000000..9eb30227e9 --- /dev/null +++ b/tabs/internal/secondary-tab.ts @@ -0,0 +1,12 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {Tab} from './tab.js'; + +/** + * A secondary tab component. + */ +export class SecondaryTab extends Tab {} diff --git a/tabs/internal/tab.ts b/tabs/internal/tab.ts index 81576b3258..67e8b59f82 100644 --- a/tabs/internal/tab.ts +++ b/tabs/internal/tab.ts @@ -26,11 +26,6 @@ export interface Tabs extends HTMLElement { previousSelectedItem?: Tab; } -/** - * Tab variant can be `primary` or `secondary`. - */ -export type TabVariant = 'primary'|'secondary'; - /** * Tab component. */ @@ -43,10 +38,8 @@ export class Tab extends LitElement { static override shadowRootOptions: ShadowRootInit = {mode: 'open', delegatesFocus: true}; - /** - * Styling variant to display, 'primary' (default) or 'secondary'. - */ - @property({reflect: true}) variant: TabVariant = 'primary'; + /** @private indicates that the element is a tab for `` */ + static readonly isTab = true; /** * Whether or not the tab is `selected`. diff --git a/tabs/internal/tabs.ts b/tabs/internal/tabs.ts index 9845d7ee9f..7ec0b03cd7 100644 --- a/tabs/internal/tabs.ts +++ b/tabs/internal/tabs.ts @@ -9,7 +9,7 @@ import '../../divider/divider.js'; import {html, isServer, LitElement, PropertyValues} from 'lit'; import {property, queryAssignedElements, state} from 'lit/decorators.js'; -import {Tab, TabVariant} from './tab.js'; +import {Tab} from './tab.js'; const NAVIGATION_KEYS = new Map([ ['default', new Set(['Home', 'End'])], @@ -47,11 +47,6 @@ export class Tabs extends LitElement { delegatesFocus: true }; - /** - * Styling variant to display, 'primary' (default) or 'secondary'. - */ - @property({reflect: true}) variant: TabVariant = 'primary'; - /** * Index of the selected item. */ @@ -66,8 +61,11 @@ export class Tabs extends LitElement { private previousSelected = -1; private readonly scrollMargin = 48; - @queryAssignedElements({selector: 'md-tab', flatten: true}) - private readonly items!: Tab[]; + @queryAssignedElements({flatten: true}) + private readonly maybeTabItems!: HTMLElement[]; + private get items(): Tab[] { + return this.maybeTabItems.filter(isTab); + } // this tracks if items have changed, which triggers rendering so they can // be kept in sync @@ -211,16 +209,14 @@ export class Tabs extends LitElement { } protected override async updated(changed: PropertyValues) { - const itemsOrVariantChanged = - changed.has('itemsDirty') || changed.has('variant'); + const itemsChanged = changed.has('itemsDirty'); // sync state with items. - if (itemsOrVariantChanged) { + if (itemsChanged) { this.items.forEach((item, i) => { item.selected = this.selected === i; - item.variant = this.variant; }); } - if (itemsOrVariantChanged || changed.has('selected')) { + if (itemsChanged || changed.has('selected')) { if (this.previousSelectedItem !== this.selectedItem) { this.previousSelectedItem?.removeAttribute(this.selectedAttribute); this.selectedItem?.setAttribute(this.selectedAttribute, ''); @@ -242,7 +238,7 @@ export class Tabs extends LitElement { return html`
+ this.handleItemClick}>
`; @@ -296,3 +292,7 @@ export class Tabs extends LitElement { this.scrollTo({behavior, top: 0, left: to}); } } + +function isTab(element: HTMLElement): element is Tab { + return 'isTab' in element.constructor && element.constructor.isTab === true; +} diff --git a/tabs/primary-tab.ts b/tabs/primary-tab.ts new file mode 100644 index 0000000000..d73031408c --- /dev/null +++ b/tabs/primary-tab.ts @@ -0,0 +1,27 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {customElement} from 'lit/decorators.js'; + +import {PrimaryTab} from './internal/primary-tab.js'; +import {styles as primaryStyles} from './internal/primary-tab-styles.css.js'; +import {styles as sharedStyles} from './internal/tab-styles.css.js'; + +declare global { + interface HTMLElementTagNameMap { + 'md-primary-tab': MdPrimaryTab; + } +} + +// TODO(b/267336507): add docs +/** + * @summary Tab allow users to display a tab within a Tabs. + * + */ +@customElement('md-primary-tab') +export class MdPrimaryTab extends PrimaryTab { + static override styles = [sharedStyles, primaryStyles]; +} diff --git a/tabs/secondary-tab.ts b/tabs/secondary-tab.ts new file mode 100644 index 0000000000..33de1dff75 --- /dev/null +++ b/tabs/secondary-tab.ts @@ -0,0 +1,27 @@ +/** + * @license + * Copyright 2023 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import {customElement} from 'lit/decorators.js'; + +import {SecondaryTab} from './internal/secondary-tab.js'; +import {styles as secondaryStyles} from './internal/secondary-tab-styles.css.js'; +import {styles as sharedStyles} from './internal/tab-styles.css.js'; + +declare global { + interface HTMLElementTagNameMap { + 'md-secondary-tab': MdSecondaryTab; + } +} + +// TODO(b/267336507): add docs +/** + * @summary Tab allow users to display a tab within a Tabs. + * + */ +@customElement('md-secondary-tab') +export class MdSecondaryTab extends SecondaryTab { + static override styles = [sharedStyles, secondaryStyles]; +} diff --git a/tabs/tab.ts b/tabs/tab.ts deleted file mode 100644 index c53b632357..0000000000 --- a/tabs/tab.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * @license - * Copyright 2023 Google LLC - * SPDX-License-Identifier: Apache-2.0 - */ - -import {customElement} from 'lit/decorators.js'; - -import {Tab} from './internal/tab.js'; -import {styles} from './internal/tab-styles.css.js'; - -export {TabVariant} from './internal/tab.js'; - -declare global { - interface HTMLElementTagNameMap { - 'md-tab': MdTab; - } -} - -// TODO(b/267336507): add docs -/** - * @summary Tab allow users to display a tab within a Tabs. - * - */ -@customElement('md-tab') -export class MdTab extends Tab { - static override styles = [styles]; -} diff --git a/tabs/tabs.ts b/tabs/tabs.ts index 0db9a84f50..94420aed59 100644 --- a/tabs/tabs.ts +++ b/tabs/tabs.ts @@ -4,15 +4,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import './tab.js'; - import {customElement} from 'lit/decorators.js'; import {Tabs} from './internal/tabs.js'; import {styles} from './internal/tabs-styles.css.js'; -export {MdTab, TabVariant} from './tab.js'; - declare global { interface HTMLElementTagNameMap { 'md-tabs': MdTabs; diff --git a/tabs/tabs_test.ts b/tabs/tabs_test.ts index 499a1703b1..d0596bb653 100644 --- a/tabs/tabs_test.ts +++ b/tabs/tabs_test.ts @@ -10,7 +10,8 @@ import {Environment} from '../testing/environment.js'; import {createTokenTests} from '../testing/tokens.js'; import {TabsHarness} from './harness.js'; -import {MdTab} from './tab.js'; +import {MdPrimaryTab} from './primary-tab.js'; +import {MdSecondaryTab} from './secondary-tab.js'; import {MdTabs} from './tabs.js'; interface TabsTestProps { @@ -22,17 +23,16 @@ function getTabsTemplate(props?: TabsTestProps) { - A - B - C + A + B + C `; } describe('', () => { const env = new Environment(); - async function setupTest( - props?: TabsTestProps, template = getTabsTemplate) { + async function setupTest(props?: TabsTestProps, template = getTabsTemplate) { const root = env.render(template(props)); await env.waitForStability(); const tab = root.querySelector('md-tabs')!; @@ -42,7 +42,8 @@ describe('', () => { describe('.styles', () => { createTokenTests(MdTabs.styles); - createTokenTests(MdTab.styles); + createTokenTests(MdPrimaryTab.styles); + createTokenTests(MdSecondaryTab.styles); }); describe('properties', () => { @@ -85,7 +86,7 @@ describe('', () => { it('maintains selection when tabs are mutated', async () => { const {harness} = await setupTest({selected: 1}); expect(harness.element.selectedItem.textContent).toBe('B'); - const tab = document.createElement('md-tab'); + const tab = document.createElement('md-primary-tab'); tab.textContent = 'tab'; // add before selected harness.element.prepend(tab); @@ -105,4 +106,4 @@ describe('', () => { expect(harness.element.selectedItem.textContent).toBe('B'); }); }); -}); \ No newline at end of file +}); diff --git a/tokens/_index.scss b/tokens/_index.scss index 66aead98e6..6d7c0eec44 100644 --- a/tokens/_index.scss +++ b/tokens/_index.scss @@ -42,12 +42,13 @@ md-comp-outlined-segmented-button-*; @forward './md-comp-outlined-select' as md-comp-outlined-select-*; @forward './md-comp-outlined-text-field' as md-comp-outlined-text-field-*; +@forward './md-comp-primary-tab' as md-comp-primary-tab-*; @forward './md-comp-radio' as md-comp-radio-*; @forward './md-comp-ripple' as md-comp-ripple-*; +@forward './md-comp-secondary-tab' as md-comp-secondary-tab-*; @forward './md-comp-slider' as md-comp-slider-*; @forward './md-comp-suggestion-chip' as md-comp-suggestion-chip-*; @forward './md-comp-switch' as md-comp-switch-*; -@forward './md-comp-tab' as md-comp-tab-*; @forward './md-comp-test-table' as md-comp-test-table-*; @forward './md-comp-text-button' as md-comp-text-button-*; @forward './md-ref-palette' as md-ref-palette-*; diff --git a/tokens/_md-comp-primary-tab.scss b/tokens/_md-comp-primary-tab.scss new file mode 100644 index 0000000000..ba40858202 --- /dev/null +++ b/tokens/_md-comp-primary-tab.scss @@ -0,0 +1,134 @@ +// +// Copyright 2023 Google LLC +// SPDX-License-Identifier: Apache-2.0 +// + +// go/keep-sorted start +@use 'sass:map'; +// go/keep-sorted end +// go/keep-sorted start +@use './md-sys-color'; +@use './md-sys-elevation'; +@use './md-sys-shape'; +@use './md-sys-state'; +@use './md-sys-typescale'; +@use './v0_172/md-comp-primary-navigation-tab'; +@use './values'; +// go/keep-sorted end + +$_default: ( + 'md-sys-color': md-sys-color.values-light(), + 'md-sys-elevation': md-sys-elevation.values(), + 'md-sys-shape': md-sys-shape.values(), + 'md-sys-state': md-sys-state.values(), + 'md-sys-typescale': md-sys-typescale.values(), +); + +$supported-tokens: ( + // go/keep-sorted start + 'active-focus-icon-color', + 'active-focus-label-text-color', + 'active-hover-icon-color', + 'active-hover-label-text-color', + 'active-hover-state-layer-color', + 'active-hover-state-layer-opacity', + 'active-icon-color', + 'active-indicator-color', + 'active-indicator-height', + 'active-indicator-shape', + 'active-label-text-color', + 'active-pressed-icon-color', + 'active-pressed-label-text-color', + 'active-pressed-state-layer-color', + 'active-pressed-state-layer-opacity', + 'container-color', + 'container-elevation', + 'container-height', + 'container-shape', + 'focus-icon-color', + 'focus-label-text-color', + 'hover-icon-color', + 'hover-label-text-color', + 'hover-state-layer-color', + 'hover-state-layer-opacity', + 'icon-color', + 'icon-size', + 'label-text-color', + 'label-text-type', + 'pressed-icon-color', + 'pressed-label-text-color', + 'pressed-state-layer-color', + 'pressed-state-layer-opacity', + // go/keep-sorted end +); + +$unsupported-tokens: ( + // include an icon and the size will adjust; + // height is 48 and it's 64 with icon + 'with-icon-and-label-text-container-height', + 'with-label-text-label-text-font', + 'with-label-text-label-text-line-height', + 'with-label-text-label-text-size', + 'with-label-text-label-text-tracking', + 'with-label-text-label-text-weight', + 'active-focus-state-layer-color', + 'active-focus-state-layer-opacity', + 'focus-state-layer-color', + 'focus-state-layer-opacity' +); + +@function values($deps: $_default, $exclude-hardcoded-values: false) { + $tokens: md-comp-primary-navigation-tab.values( + $deps, + $exclude-hardcoded-values: $exclude-hardcoded-values + ); + + // TODO(b/271876162): remove when tokens compiler emits typescale tokens + $tokens: map.merge( + $tokens, + ( + 'label-text-type': map.get($deps, 'md-sys-typescale', 'title-small'), + ) + ); + + @return values.validate( + $tokens, + $supported-tokens: $supported-tokens, + $unsupported-tokens: $unsupported-tokens, + $renamed-tokens: ( + // rename inactive- + 'inactive-focus-state-layer-color': 'focus-state-layer-color', + 'inactive-focus-state-layer-opacity': 'focus-state-layer-opacity', + 'inactive-hover-state-layer-color': 'hover-state-layer-color', + 'inactive-hover-state-layer-opacity': 'hover-state-layer-opacity', + 'inactive-pressed-state-layer-color': 'pressed-state-layer-color', + 'inactive-pressed-state-layer-opacity': 'pressed-state-layer-opacity', + // rename with-icon- and inactive- + 'with-icon-active-focus-icon-color': 'active-focus-icon-color', + 'with-icon-active-hover-icon-color': 'active-hover-icon-color', + 'with-icon-active-icon-color': 'active-icon-color', + 'with-icon-active-pressed-icon-color': 'active-pressed-icon-color', + 'with-icon-icon-size': 'icon-size', + 'with-icon-inactive-focus-icon-color': 'focus-icon-color', + 'with-icon-inactive-hover-icon-color': 'hover-icon-color', + 'with-icon-inactive-icon-color': 'icon-color', + 'with-icon-inactive-pressed-icon-color': 'pressed-icon-color', + // rename with-label-text- and inactive- + 'with-label-text-active-focus-label-text-color': + 'active-focus-label-text-color', + 'with-label-text-active-hover-label-text-color': + 'active-hover-label-text-color', + 'with-label-text-active-label-text-color': 'active-label-text-color', + 'with-label-text-active-pressed-label-text-color': + 'active-pressed-label-text-color', + 'with-label-text-inactive-focus-label-text-color': + 'focus-label-text-color', + 'with-label-text-inactive-hover-label-text-color': + 'hover-label-text-color', + 'with-label-text-inactive-label-text-color': 'label-text-color', + 'with-label-text-inactive-pressed-label-text-color': + 'pressed-label-text-color', + 'with-label-text-label-text-type': 'label-text-type' + ) + ); +} diff --git a/tokens/_md-comp-secondary-tab.scss b/tokens/_md-comp-secondary-tab.scss new file mode 100644 index 0000000000..37f2421874 --- /dev/null +++ b/tokens/_md-comp-secondary-tab.scss @@ -0,0 +1,139 @@ +// +// Copyright 2023 Google LLC +// SPDX-License-Identifier: Apache-2.0 +// + +// go/keep-sorted start +@use 'sass:map'; +// go/keep-sorted end +// go/keep-sorted start +@use './md-sys-color'; +@use './md-sys-elevation'; +@use './md-sys-shape'; +@use './md-sys-state'; +@use './md-sys-typescale'; +@use './v0_172/md-comp-secondary-navigation-tab'; +@use './values'; +// go/keep-sorted end + +$_default: ( + 'md-sys-color': md-sys-color.values-light(), + 'md-sys-elevation': md-sys-elevation.values(), + 'md-sys-shape': md-sys-shape.values(), + 'md-sys-state': md-sys-state.values(), + 'md-sys-typescale': md-sys-typescale.values(), +); + +$supported-tokens: ( + // go/keep-sorted start + 'active-focus-icon-color', + 'active-focus-label-text-color', + 'active-hover-icon-color', + 'active-hover-label-text-color', + 'active-hover-state-layer-color', + 'active-hover-state-layer-opacity', + 'active-icon-color', + 'active-indicator-color', + 'active-indicator-height', + 'active-indicator-shape', + 'active-label-text-color', + 'active-pressed-icon-color', + 'active-pressed-label-text-color', + 'active-pressed-state-layer-color', + 'active-pressed-state-layer-opacity', + 'container-color', + 'container-elevation', + 'container-height', + 'container-shape', + 'focus-icon-color', + 'focus-label-text-color', + 'hover-icon-color', + 'hover-label-text-color', + 'hover-state-layer-color', + 'hover-state-layer-opacity', + 'icon-color', + 'icon-size', + 'label-text-color', + 'label-text-type', + 'pressed-icon-color', + 'pressed-label-text-color', + 'pressed-state-layer-color', + 'pressed-state-layer-opacity', + // go/keep-sorted end +); + +$unsupported-tokens: ( + // include an icon and the size will adjust; + // height is 48 and it's 64 with icon + 'container-shadow-color', + 'label-text-font', + 'label-text-line-height', + 'label-text-size', + 'label-text-tracking', + 'label-text-weight', + 'focus-state-layer-color', + 'focus-state-layer-opacity' +); + +@function values($deps: $_default, $exclude-hardcoded-values: false) { + $tokens: md-comp-secondary-navigation-tab.values( + $deps, + $exclude-hardcoded-values: $exclude-hardcoded-values + ); + + // TODO(b/271876162): remove when tokens compiler emits typescale tokens + $tokens: map.merge( + $tokens, + ( + 'label-text-type': map.get($deps, 'md-sys-typescale', 'title-small'), + ) + ); + + $tokens: _add-missing-secondary-tokens($tokens); + + $tokens: values.validate( + $tokens, + $supported-tokens: $supported-tokens, + $unsupported-tokens: $unsupported-tokens, + $renamed-tokens: ( + 'inactive-label-text-color': 'label-text-color', + 'with-icon-active-icon-color': 'active-icon-color', + 'with-icon-focus-icon-color': 'focus-icon-color', + 'with-icon-hover-icon-color': 'hover-icon-color', + 'with-icon-icon-size': 'icon-size', + 'with-icon-inactive-icon-color': 'icon-color', + 'with-icon-pressed-icon-color': 'pressed-icon-color', + ) + ); + + @return $tokens; +} + +// add missing secondary tokens to match primary variant. +@function _add-missing-secondary-tokens($tokens) { + $tokens: map.merge( + $tokens, + ( + 'active-focus-icon-color': map.get($tokens, 'icon-color'), + 'active-focus-label-text-color': + map.get($tokens, 'active-label-text-color'), + 'active-hover-icon-color': map.get($tokens, 'icon-color'), + 'active-hover-label-text-color': + map.get($tokens, 'active-label-text-color'), + 'active-hover-state-layer-color': + map.get($tokens, 'hover-state-layer-color'), + 'active-hover-state-layer-opacity': + map.get($tokens, 'hover-state-layer-opacity'), + 'active-icon-color': map.get($tokens, 'icon-color'), + 'active-indicator-shape': 0, + 'active-pressed-icon-color': map.get($tokens, 'icon-color'), + 'active-pressed-label-text-color': + map.get($tokens, 'active-label-text-color'), + 'active-pressed-state-layer-color': + map.get($tokens, 'pressed-state-layer-color'), + 'active-pressed-state-layer-opacity': + map.get($tokens, 'pressed-state-layer-opacity'), + ) + ); + @return $tokens; +} diff --git a/tokens/_md-comp-tab.scss b/tokens/_md-comp-tab.scss deleted file mode 100644 index 4f695b4874..0000000000 --- a/tokens/_md-comp-tab.scss +++ /dev/null @@ -1,272 +0,0 @@ -// -// Copyright 2023 Google LLC -// SPDX-License-Identifier: Apache-2.0 -// - -// go/keep-sorted start -@use 'sass:map'; -// go/keep-sorted end -// go/keep-sorted start -@use './md-sys-color'; -@use './md-sys-elevation'; -@use './md-sys-shape'; -@use './md-sys-state'; -@use './md-sys-typescale'; -@use './v0_172/md-comp-primary-navigation-tab'; -@use './v0_172/md-comp-secondary-navigation-tab'; -@use './values'; -// go/keep-sorted end - -$_default: ( - 'md-sys-color': md-sys-color.values-light(), - 'md-sys-elevation': md-sys-elevation.values(), - 'md-sys-shape': md-sys-shape.values(), - 'md-sys-state': md-sys-state.values(), - 'md-sys-typescale': md-sys-typescale.values(), -); - -$supported-tokens: ( - // go/keep-sorted start - 'primary-tab-active-focus-icon-color', - 'primary-tab-active-focus-label-text-color', - 'primary-tab-active-hover-icon-color', - 'primary-tab-active-hover-label-text-color', - 'primary-tab-active-hover-state-layer-color', - 'primary-tab-active-hover-state-layer-opacity', - 'primary-tab-active-icon-color', - 'primary-tab-active-indicator-color', - 'primary-tab-active-indicator-height', - 'primary-tab-active-indicator-shape', - 'primary-tab-active-label-text-color', - 'primary-tab-active-pressed-icon-color', - 'primary-tab-active-pressed-label-text-color', - 'primary-tab-active-pressed-state-layer-color', - 'primary-tab-active-pressed-state-layer-opacity', - 'primary-tab-container-color', - 'primary-tab-container-elevation', - 'primary-tab-container-height', - 'primary-tab-container-shape', - 'primary-tab-focus-icon-color', - 'primary-tab-focus-label-text-color', - 'primary-tab-hover-icon-color', - 'primary-tab-hover-label-text-color', - 'primary-tab-hover-state-layer-color', - 'primary-tab-hover-state-layer-opacity', - 'primary-tab-icon-color', - 'primary-tab-icon-size', - 'primary-tab-label-text-color', - 'primary-tab-label-text-type', - 'primary-tab-pressed-icon-color', - 'primary-tab-pressed-label-text-color', - 'primary-tab-pressed-state-layer-color', - 'primary-tab-pressed-state-layer-opacity', - 'secondary-tab-active-focus-icon-color', - 'secondary-tab-active-focus-label-text-color', - 'secondary-tab-active-hover-icon-color', - 'secondary-tab-active-hover-label-text-color', - 'secondary-tab-active-hover-state-layer-color', - 'secondary-tab-active-hover-state-layer-opacity', - 'secondary-tab-active-icon-color', - 'secondary-tab-active-indicator-color', - 'secondary-tab-active-indicator-height', - 'secondary-tab-active-indicator-shape', - 'secondary-tab-active-label-text-color', - 'secondary-tab-active-pressed-icon-color', - 'secondary-tab-active-pressed-label-text-color', - 'secondary-tab-active-pressed-state-layer-color', - 'secondary-tab-active-pressed-state-layer-opacity', - 'secondary-tab-container-color', - 'secondary-tab-container-elevation', - 'secondary-tab-container-height', - 'secondary-tab-container-shape', - 'secondary-tab-focus-icon-color', - 'secondary-tab-focus-label-text-color', - 'secondary-tab-hover-icon-color', - 'secondary-tab-hover-label-text-color', - 'secondary-tab-hover-state-layer-color', - 'secondary-tab-hover-state-layer-opacity', - 'secondary-tab-icon-color', - 'secondary-tab-icon-size', - 'secondary-tab-label-text-color', - 'secondary-tab-label-text-type', - 'secondary-tab-pressed-icon-color', - 'secondary-tab-pressed-label-text-color', - 'secondary-tab-pressed-state-layer-color', - 'secondary-tab-pressed-state-layer-opacity', - // go/keep-sorted end -); - -$unsupported-tokens: ( - // include an icon and the size will adjust; - // height is 48 and it's 64 with icon - 'primary-tab-with-icon-and-label-text-container-height', - 'primary-tab-with-label-text-label-text-font', - 'primary-tab-with-label-text-label-text-line-height', - 'primary-tab-with-label-text-label-text-size', - 'primary-tab-with-label-text-label-text-tracking', - 'primary-tab-with-label-text-label-text-weight', - 'secondary-tab-container-shadow-color', - 'secondary-tab-label-text-font', - 'secondary-tab-label-text-line-height', - 'secondary-tab-label-text-size', - 'secondary-tab-label-text-tracking', - 'secondary-tab-label-text-weight', - 'primary-tab-active-focus-state-layer-color', - 'primary-tab-active-focus-state-layer-opacity', - 'primary-tab-focus-state-layer-color', - 'primary-tab-focus-state-layer-opacity', - 'secondary-tab-focus-state-layer-color', - 'secondary-tab-focus-state-layer-opacity' -); - -// Note, this combines the raw primary and secondary tab variant tokens -// into a single set prefixed with `primary-tab` or `secondary-tab`. -// Tokens are normalized between the variants, added or removed and renamed -// as needed. -@function values($deps: $_default, $exclude-hardcoded-values: false) { - // prepare token values by normalizing and combinding primary/secondary - // generated tokens *before* fixing up names and limiting to supported tokens. - // 1. for primary - // a. prefix with `primary-tab` - // 2. for secondary - // a. add missing secondary tokens to match primary - // b. prefix with `secondary-tab` - - $primary-tokens: md-comp-primary-navigation-tab.values( - $deps, - $exclude-hardcoded-values - ); - $primary-tokens: _add-missing-tokens($primary-tokens, $deps); - $primary-tokens: _prefix-tokens($primary-tokens, 'primary-tab'); - $secondary-tokens: md-comp-secondary-navigation-tab.values( - $deps, - $exclude-hardcoded-values - ); - $secondary-tokens: _add-missing-tokens($secondary-tokens, $deps); - $secondary-tokens: _add-missing-secondary-tokens($secondary-tokens); - $secondary-tokens: _prefix-tokens($secondary-tokens, 'secondary-tab'); - - $base-tokens: map.merge($primary-tokens, $secondary-tokens); - - // now refine the normalized generated tokens to only renamed/supported tokens. - $tokens: values.validate( - $base-tokens, - $supported-tokens: $supported-tokens, - $unsupported-tokens: $unsupported-tokens, - $renamed-tokens: ( - // rename primary inactive- - 'primary-tab-inactive-focus-state-layer-color': - 'primary-tab-focus-state-layer-color', - 'primary-tab-inactive-focus-state-layer-opacity': - 'primary-tab-focus-state-layer-opacity', - 'primary-tab-inactive-hover-state-layer-color': - 'primary-tab-hover-state-layer-color', - 'primary-tab-inactive-hover-state-layer-opacity': - 'primary-tab-hover-state-layer-opacity', - 'primary-tab-inactive-pressed-state-layer-color': - 'primary-tab-pressed-state-layer-color', - 'primary-tab-inactive-pressed-state-layer-opacity': - 'primary-tab-pressed-state-layer-opacity', - // rename primary with-icon- and inactive- - 'primary-tab-with-icon-active-focus-icon-color': - 'primary-tab-active-focus-icon-color', - 'primary-tab-with-icon-active-hover-icon-color': - 'primary-tab-active-hover-icon-color', - 'primary-tab-with-icon-active-icon-color': 'primary-tab-active-icon-color', - 'primary-tab-with-icon-active-pressed-icon-color': - 'primary-tab-active-pressed-icon-color', - 'primary-tab-with-icon-icon-size': 'primary-tab-icon-size', - 'primary-tab-with-icon-inactive-focus-icon-color': - 'primary-tab-focus-icon-color', - 'primary-tab-with-icon-inactive-hover-icon-color': - 'primary-tab-hover-icon-color', - 'primary-tab-with-icon-inactive-icon-color': 'primary-tab-icon-color', - 'primary-tab-with-icon-inactive-pressed-icon-color': - 'primary-tab-pressed-icon-color', - // rename primary with-label-text- and inactive- - 'primary-tab-with-label-text-active-focus-label-text-color': - 'primary-tab-active-focus-label-text-color', - 'primary-tab-with-label-text-active-hover-label-text-color': - 'primary-tab-active-hover-label-text-color', - 'primary-tab-with-label-text-active-label-text-color': - 'primary-tab-active-label-text-color', - 'primary-tab-with-label-text-active-pressed-label-text-color': - 'primary-tab-active-pressed-label-text-color', - 'primary-tab-with-label-text-inactive-focus-label-text-color': - 'primary-tab-focus-label-text-color', - 'primary-tab-with-label-text-inactive-hover-label-text-color': - 'primary-tab-hover-label-text-color', - 'primary-tab-with-label-text-inactive-label-text-color': - 'primary-tab-label-text-color', - 'primary-tab-with-label-text-inactive-pressed-label-text-color': - 'primary-tab-pressed-label-text-color', - 'primary-tab-with-label-text-label-text-type': - 'primary-tab-label-text-type', - // rename secondary with-icon- and inactive- - 'secondary-tab-inactive-label-text-color': - 'secondary-tab-label-text-color', - 'secondary-tab-with-icon-active-icon-color': - 'secondary-tab-active-icon-color', - 'secondary-tab-with-icon-focus-icon-color': - 'secondary-tab-focus-icon-color', - 'secondary-tab-with-icon-hover-icon-color': - 'secondary-tab-hover-icon-color', - 'secondary-tab-with-icon-icon-size': 'secondary-tab-icon-size', - 'secondary-tab-with-icon-inactive-icon-color': 'secondary-tab-icon-color', - 'secondary-tab-with-icon-pressed-icon-color': - 'secondary-tab-pressed-icon-color' - ) - ); - - @return $tokens; -} - -@function _prefix-tokens($tokens, $prefix: '') { - @each $key, $value in $tokens { - $tokens: map.remove($tokens, $key); - $key: '#{$prefix}-#{$key}'; - $tokens: map.set($tokens, $key, $value); - } - @return $tokens; -} - -// add tokens for label-text -@function _add-missing-tokens($tokens, $deps) { - // TODO(b/271876162): remove when tokens compiler emits typescale tokens - $tokens: map.merge( - $tokens, - ( - 'label-text-type': map.get($deps, 'md-sys-typescale', 'title-small'), - ) - ); - @return $tokens; -} - -// add missing secondary tokens to match primary variant. -@function _add-missing-secondary-tokens($tokens) { - $tokens: map.merge( - $tokens, - ( - 'active-focus-icon-color': map.get($tokens, 'icon-color'), - 'active-focus-label-text-color': - map.get($tokens, 'active-label-text-color'), - 'active-hover-icon-color': map.get($tokens, 'icon-color'), - 'active-hover-label-text-color': - map.get($tokens, 'active-label-text-color'), - 'active-hover-state-layer-color': - map.get($tokens, 'hover-state-layer-color'), - 'active-hover-state-layer-opacity': - map.get($tokens, 'hover-state-layer-opacity'), - 'active-icon-color': map.get($tokens, 'icon-color'), - 'active-indicator-shape': 0, - 'active-pressed-icon-color': map.get($tokens, 'icon-color'), - 'active-pressed-label-text-color': - map.get($tokens, 'active-label-text-color'), - 'active-pressed-state-layer-color': - map.get($tokens, 'pressed-state-layer-color'), - 'active-pressed-state-layer-opacity': - map.get($tokens, 'pressed-state-layer-opacity'), - ) - ); - @return $tokens; -}