2023-05-09 03:29:12 +03:00
|
|
|
//
|
|
|
|
// Copyright 2023 Google LLC
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
//
|
|
|
|
|
|
|
|
// go/keep-sorted start
|
2023-08-15 00:38:46 +03:00
|
|
|
@use 'sass:list';
|
2023-05-09 03:29:12 +03:00
|
|
|
@use 'sass:map';
|
|
|
|
// go/keep-sorted end
|
|
|
|
// go/keep-sorted start
|
|
|
|
@use '../../elevation/elevation';
|
|
|
|
@use '../../focus/focus-ring';
|
2023-05-30 21:22:25 +03:00
|
|
|
@use '../../internal/sass/string-ext';
|
2023-05-09 03:29:12 +03:00
|
|
|
@use '../../ripple/ripple';
|
|
|
|
@use '../../tokens';
|
|
|
|
// go/keep-sorted end
|
|
|
|
|
|
|
|
@mixin theme($tokens) {
|
2023-08-18 00:35:24 +03:00
|
|
|
$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'
|
|
|
|
)
|
|
|
|
);
|
2023-08-15 00:38:46 +03:00
|
|
|
|
|
|
|
@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};
|
|
|
|
}
|
|
|
|
}
|
2023-05-09 03:29:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
@mixin styles() {
|
|
|
|
// contains tokens for all variants and applied where needed
|
2023-08-15 00:38:46 +03:00
|
|
|
$tokens: tokens.md-comp-tab-values();
|
2023-05-09 03:29:12 +03:00
|
|
|
|
|
|
|
: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);
|
2023-08-15 00:38:46 +03:00
|
|
|
--_#{$token}: var(--md-#{$primary-prefix}#{$token}, #{$value});
|
2023-05-09 03:29:12 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-18 00:35:24 +03:00
|
|
|
// 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)
|
|
|
|
);
|
|
|
|
|
2023-05-09 03:29:12 +03:00
|
|
|
display: inline-flex;
|
|
|
|
outline: none;
|
|
|
|
-webkit-tap-highlight-color: transparent;
|
|
|
|
vertical-align: middle;
|
|
|
|
|
|
|
|
@include ripple.theme(
|
|
|
|
(
|
|
|
|
hover-color: var(--_hover-state-layer-color),
|
|
|
|
hover-opacity: var(--_hover-state-layer-opacity),
|
|
|
|
pressed-color: var(--_pressed-state-layer-color),
|
|
|
|
pressed-opacity: var(--_pressed-state-layer-opacity),
|
|
|
|
)
|
|
|
|
);
|
2023-07-18 06:23:56 +03:00
|
|
|
}
|
2023-05-09 03:29:12 +03:00
|
|
|
|
2023-07-18 06:23:56 +03:00
|
|
|
md-focus-ring {
|
2023-05-09 03:29:12 +03:00
|
|
|
@include focus-ring.theme(
|
|
|
|
(
|
2023-05-24 00:07:59 +03:00
|
|
|
'shape': 8px,
|
2023-05-09 03:29:12 +03:00
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-05-24 00:07:59 +03:00
|
|
|
:host([selected]) md-focus-ring {
|
|
|
|
margin-bottom: calc(var(--_active-indicator-height) + 1px);
|
|
|
|
}
|
|
|
|
|
2023-05-09 03:29:12 +03:00
|
|
|
.button {
|
2023-08-25 20:16:13 +03:00
|
|
|
appearance: none;
|
2023-05-09 03:29:12 +03:00
|
|
|
display: inline-flex;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
border: none;
|
|
|
|
outline: none;
|
|
|
|
user-select: none;
|
|
|
|
vertical-align: middle;
|
2023-08-18 00:35:24 +03:00
|
|
|
background: none;
|
2023-05-09 03:29:12 +03:00
|
|
|
text-decoration: none;
|
|
|
|
width: 100%;
|
|
|
|
position: relative;
|
|
|
|
padding: 0;
|
|
|
|
margin: 0;
|
|
|
|
z-index: 0; // Ensure this is a stacking context so the indicator displays
|
|
|
|
font: var(--_label-text-type);
|
|
|
|
color: var(--_label-text-color);
|
|
|
|
|
|
|
|
&::-moz-focus-inner {
|
|
|
|
padding: 0;
|
|
|
|
border: 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-18 00:35:24 +03:00
|
|
|
.button::before {
|
|
|
|
background: var(--_container-color);
|
|
|
|
content: '';
|
|
|
|
inset: 0;
|
|
|
|
position: absolute;
|
|
|
|
z-index: -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
.button::before,
|
2023-05-09 03:29:12 +03:00
|
|
|
md-ripple {
|
2023-08-18 00:35:24 +03:00
|
|
|
border-start-start-radius: var(--_container-shape-start-start);
|
|
|
|
border-start-end-radius: var(--_container-shape-start-end);
|
|
|
|
border-end-end-radius: var(--_container-shape-end-end);
|
|
|
|
border-end-start-radius: var(--_container-shape-end-start);
|
2023-05-09 03:29:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
.content {
|
|
|
|
position: relative;
|
|
|
|
box-sizing: border-box;
|
|
|
|
display: inline-flex;
|
|
|
|
flex-direction: column;
|
|
|
|
align-items: center;
|
|
|
|
justify-content: center;
|
|
|
|
|
|
|
|
$_content-padding: 8px;
|
|
|
|
// tabs are naturally sized up to their max height.
|
|
|
|
max-height: calc(var(--_container-height) + 2 * $_content-padding);
|
2023-05-17 21:03:29 +03:00
|
|
|
// min-height of touch target
|
|
|
|
min-height: 48px;
|
|
|
|
padding: $_content-padding calc(2 * $_content-padding);
|
2023-05-09 03:29:12 +03:00
|
|
|
gap: 4px;
|
|
|
|
}
|
|
|
|
|
|
|
|
.content.inline-icon {
|
|
|
|
flex-direction: row;
|
|
|
|
}
|
|
|
|
|
|
|
|
.indicator {
|
|
|
|
position: absolute;
|
|
|
|
box-sizing: border-box;
|
|
|
|
z-index: -1;
|
|
|
|
transform-origin: bottom left;
|
|
|
|
background: var(--_active-indicator-color);
|
|
|
|
border-radius: var(--_active-indicator-shape);
|
|
|
|
height: var(--_active-indicator-height);
|
|
|
|
inset: auto 0 0 0;
|
|
|
|
// hidden unless the tab is selected
|
|
|
|
opacity: 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// unselected states
|
|
|
|
.button ::slotted([slot='icon']) {
|
|
|
|
display: inline-flex;
|
|
|
|
position: relative;
|
|
|
|
writing-mode: horizontal-tb;
|
|
|
|
fill: currentColor;
|
|
|
|
color: var(--_icon-color);
|
|
|
|
font-size: var(--_icon-size);
|
|
|
|
width: var(--_icon-size);
|
|
|
|
height: var(--_icon-size);
|
|
|
|
}
|
|
|
|
|
|
|
|
.button:hover {
|
|
|
|
color: var(--_hover-label-text-color);
|
|
|
|
cursor: pointer;
|
|
|
|
}
|
|
|
|
|
|
|
|
.button:hover ::slotted([slot='icon']) {
|
|
|
|
color: var(--_hover-icon-color);
|
|
|
|
}
|
|
|
|
|
|
|
|
.button:focus {
|
|
|
|
color: var(--_focus-label-text-color);
|
|
|
|
}
|
|
|
|
|
|
|
|
.button:focus ::slotted([slot='icon']) {
|
|
|
|
color: var(--_focus-icon-color);
|
|
|
|
}
|
|
|
|
|
|
|
|
.button:active {
|
|
|
|
color: var(--_pressed-label-text-color);
|
|
|
|
outline: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
.button:active ::slotted([slot='icon']) {
|
|
|
|
color: var(--_pressed-icon-color);
|
|
|
|
}
|
|
|
|
|
|
|
|
// selected styling
|
|
|
|
:host([selected]) .indicator {
|
|
|
|
opacity: 1;
|
|
|
|
}
|
|
|
|
:host([selected]) .button {
|
|
|
|
color: var(--_active-label-text-color);
|
|
|
|
@include elevation.theme(
|
|
|
|
(
|
|
|
|
level: var(--_container-elevation),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
|
|
|
|
@include ripple.theme(
|
|
|
|
(
|
|
|
|
hover-color: var(--_active-hover-state-layer-color),
|
|
|
|
hover-opacity: var(--_active-hover-state-layer-opacity),
|
|
|
|
pressed-color: var(--_active-pressed-state-layer-color),
|
|
|
|
pressed-opacity: var(--_active-pressed-state-layer-opacity),
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
:host([selected]) .button ::slotted([slot='icon']) {
|
|
|
|
color: var(--_active-icon-color);
|
|
|
|
}
|
|
|
|
|
|
|
|
// selected states
|
|
|
|
:host([selected]) .button:hover {
|
|
|
|
color: var(--_active-hover-label-text-color);
|
|
|
|
}
|
|
|
|
|
|
|
|
:host([selected]) .button:hover ::slotted([slot='icon']) {
|
|
|
|
color: var(--_active-hover-icon-color);
|
|
|
|
}
|
|
|
|
|
|
|
|
:host([selected]) .button:focus {
|
|
|
|
color: var(--_active-focus-label-text-color);
|
|
|
|
}
|
|
|
|
|
|
|
|
:host([selected]) .button:focus ::slotted([slot='icon']) {
|
|
|
|
color: var(--_active-focus-icon-color);
|
|
|
|
}
|
|
|
|
|
|
|
|
:host([selected]) .button:active {
|
|
|
|
color: var(--_active-pressed-label-text-color);
|
|
|
|
}
|
|
|
|
|
|
|
|
:host([selected]) .button:active ::slotted([slot='icon']) {
|
|
|
|
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);
|
2023-08-15 00:38:46 +03:00
|
|
|
--_#{$token}: var(--md-#{$secondary-prefix}#{$token}, #{$value});
|
2023-05-09 03:29:12 +03:00
|
|
|
}
|
|
|
|
}
|
2023-08-18 00:35:24 +03:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
);
|
2023-05-09 03:29:12 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
:host([variant~='secondary']) .content {
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
:host([variant~='secondary']) .indicator {
|
|
|
|
min-width: 100%;
|
|
|
|
}
|
|
|
|
|
|
|
|
:host,
|
|
|
|
::slotted(*) {
|
|
|
|
white-space: nowrap;
|
|
|
|
}
|
2023-05-15 21:53:17 +03:00
|
|
|
|
|
|
|
@media (forced-colors: active) {
|
|
|
|
:host,
|
|
|
|
:host([variant]) {
|
|
|
|
--_active-indicator-color: CanvasText;
|
|
|
|
}
|
|
|
|
}
|
2023-05-09 03:29:12 +03:00
|
|
|
}
|