mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(button-toggle): align with 2018 material design spec (#12443)
Aligns the button toggle component with the latest Material design spec.
This commit is contained in:
committed by
Jeremy Elbourn
parent
3192dfa1f3
commit
fd3eb6acc5
@@ -25,6 +25,23 @@
|
||||
</mat-button-toggle-group>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<mat-button-toggle-group appearance="legacy" name="alignment" [vertical]="isVertical">
|
||||
<mat-button-toggle value="left" [disabled]="isDisabled">
|
||||
<mat-icon>format_align_left</mat-icon>
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle value="center" [disabled]="isDisabled">
|
||||
<mat-icon>format_align_center</mat-icon>
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle value="right" [disabled]="isDisabled">
|
||||
<mat-icon>format_align_right</mat-icon>
|
||||
</mat-button-toggle>
|
||||
<mat-button-toggle value="justify" [disabled]="isDisabled">
|
||||
<mat-icon>format_align_justify</mat-icon>
|
||||
</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
</section>
|
||||
|
||||
<h1>Disabled Group</h1>
|
||||
|
||||
<section>
|
||||
@@ -50,9 +67,18 @@
|
||||
<mat-button-toggle [disabled]="isDisabled">Milk</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
</section>
|
||||
<section>
|
||||
<mat-button-toggle-group appearance="legacy" multiple [vertical]="isVertical">
|
||||
<mat-button-toggle>Flour</mat-button-toggle>
|
||||
<mat-button-toggle>Eggs</mat-button-toggle>
|
||||
<mat-button-toggle>Sugar</mat-button-toggle>
|
||||
<mat-button-toggle [disabled]="isDisabled">Milk</mat-button-toggle>
|
||||
</mat-button-toggle-group>
|
||||
</section>
|
||||
|
||||
<h1>Single Toggle</h1>
|
||||
<mat-button-toggle>Yes</mat-button-toggle>
|
||||
<mat-button-toggle appearance="legacy">Yes</mat-button-toggle>
|
||||
|
||||
<h1>Dynamic Exclusive Selection</h1>
|
||||
<section>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
section {
|
||||
margin-bottom: 16px;
|
||||
}
|
||||
@@ -13,6 +13,7 @@ import {Component} from '@angular/core';
|
||||
moduleId: module.id,
|
||||
selector: 'button-toggle-demo',
|
||||
templateUrl: 'button-toggle-demo.html',
|
||||
styleUrls: ['button-toggle-demo.css'],
|
||||
})
|
||||
export class ButtonToggleDemo {
|
||||
isVertical = false;
|
||||
|
||||
@@ -6,11 +6,18 @@
|
||||
@mixin mat-button-toggle-theme($theme) {
|
||||
$foreground: map-get($theme, foreground);
|
||||
$background: map-get($theme, background);
|
||||
$divider-color: mat-color($foreground, divider);
|
||||
|
||||
.mat-button-toggle-standalone, .mat-button-toggle-group {
|
||||
.mat-button-toggle-standalone,
|
||||
.mat-button-toggle-group {
|
||||
@include _mat-theme-elevation(2, $theme);
|
||||
}
|
||||
|
||||
.mat-button-toggle-standalone.mat-button-toggle-appearance-standard,
|
||||
.mat-button-toggle-group-appearance-standard {
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.mat-button-toggle {
|
||||
color: mat-color($foreground, hint-text);
|
||||
|
||||
@@ -19,19 +26,56 @@
|
||||
}
|
||||
}
|
||||
|
||||
.mat-button-toggle-appearance-standard {
|
||||
color: mat-color($foreground, text);
|
||||
background: mat-color($background, card);
|
||||
|
||||
.mat-button-toggle-focus-overlay {
|
||||
background-color: mat-color($background, focused-button, 1);
|
||||
}
|
||||
}
|
||||
|
||||
.mat-button-toggle-group-appearance-standard .mat-button-toggle + .mat-button-toggle {
|
||||
border-left: solid 1px $divider-color;
|
||||
}
|
||||
|
||||
[dir='rtl'] .mat-button-toggle-group-appearance-standard .mat-button-toggle + .mat-button-toggle {
|
||||
border-left: none;
|
||||
border-right: solid 1px $divider-color;
|
||||
}
|
||||
|
||||
.mat-button-toggle-vertical-appearance-standard .mat-button-toggle + .mat-button-toggle {
|
||||
border-left: none;
|
||||
border-right: none;
|
||||
border-top: solid 1px $divider-color;
|
||||
}
|
||||
|
||||
.mat-button-toggle-checked {
|
||||
background-color: mat-color($background, selected-button);
|
||||
color: mat-color($foreground, secondary-text);
|
||||
|
||||
&.mat-button-toggle-appearance-standard {
|
||||
color: mat-color($foreground, text);
|
||||
}
|
||||
}
|
||||
|
||||
.mat-button-toggle-disabled {
|
||||
background-color: mat-color($background, disabled-button-toggle);
|
||||
color: mat-color($foreground, disabled-button);
|
||||
background-color: mat-color($background, disabled-button-toggle);
|
||||
|
||||
&.mat-button-toggle-appearance-standard {
|
||||
background: mat-color($background, card);
|
||||
}
|
||||
|
||||
&.mat-button-toggle-checked {
|
||||
background-color: mat-color($background, selected-disabled-button);
|
||||
}
|
||||
}
|
||||
|
||||
.mat-button-toggle-standalone.mat-button-toggle-appearance-standard,
|
||||
.mat-button-toggle-group-appearance-standard {
|
||||
border: solid 1px $divider-color;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin mat-button-toggle-typography($config) {
|
||||
|
||||
@@ -2,27 +2,38 @@
|
||||
@import '../core/style/layout-common';
|
||||
@import '../../cdk/a11y/a11y';
|
||||
|
||||
$mat-button-toggle-padding: 0 16px !default;
|
||||
$mat-button-toggle-height: 36px !default;
|
||||
$mat-button-toggle-border-radius: 2px !default;
|
||||
$mat-button-toggle-standard-padding: 0 12px !default;
|
||||
$mat-button-toggle-standard-height: 48px !default;
|
||||
$mat-button-toggle-standard-border-radius: 4px !default;
|
||||
|
||||
$mat-button-toggle-legacy-padding: 0 16px !default;
|
||||
$mat-button-toggle-legacy-height: 36px !default;
|
||||
$mat-button-toggle-legacy-border-radius: 2px !default;
|
||||
|
||||
.mat-button-toggle-standalone,
|
||||
.mat-button-toggle-group {
|
||||
position: relative;
|
||||
display: inline-flex;
|
||||
flex-direction: row;
|
||||
|
||||
border-radius: $mat-button-toggle-border-radius;
|
||||
|
||||
cursor: pointer;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
border-radius: $mat-button-toggle-legacy-border-radius;
|
||||
|
||||
@include cdk-high-contrast {
|
||||
outline: solid 1px;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-button-toggle-standalone.mat-button-toggle-appearance-standard,
|
||||
.mat-button-toggle-group-appearance-standard {
|
||||
border-radius: $mat-button-toggle-standard-border-radius;
|
||||
|
||||
@include cdk-high-contrast {
|
||||
outline: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-button-toggle-vertical {
|
||||
flex-direction: column;
|
||||
|
||||
@@ -38,10 +49,6 @@ $mat-button-toggle-border-radius: 2px !default;
|
||||
position: relative;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
// Similar to components like the checkbox, slide-toggle and radio, we cannot show the focus
|
||||
// overlay for `.cdk-program-focused` because mouse clicks on the <label> element would be always
|
||||
// treated as programmatic focus.
|
||||
// TODO(paul): support `program` as well. See https://github.com/angular/material2/issues/9889
|
||||
&.cdk-keyboard-focused {
|
||||
.mat-button-toggle-focus-overlay {
|
||||
opacity: 1;
|
||||
@@ -54,11 +61,35 @@ $mat-button-toggle-border-radius: 2px !default;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-button-toggle-appearance-standard {
|
||||
&:not(.mat-button-toggle-disabled):hover .mat-button-toggle-focus-overlay {
|
||||
opacity: 0.04;
|
||||
}
|
||||
|
||||
// Similar to components like the checkbox, slide-toggle and radio, we cannot show the focus
|
||||
// overlay for `.cdk-program-focused` because mouse clicks on the <label> element would be always
|
||||
// treated as programmatic focus. Note that it needs the extra `:not` in order to have more
|
||||
// specificity than the `:hover` above.
|
||||
// TODO(paul): support `program` as well. See https://github.com/angular/material2/issues/9889
|
||||
&.cdk-keyboard-focused:not(.mat-button-toggle-disabled) .mat-button-toggle-focus-overlay {
|
||||
opacity: 0.12;
|
||||
|
||||
@include cdk-high-contrast {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.mat-button-toggle-label-content {
|
||||
@include user-select(none);
|
||||
display: inline-block;
|
||||
line-height: $mat-button-toggle-height;
|
||||
padding: $mat-button-toggle-padding;
|
||||
line-height: $mat-button-toggle-legacy-height;
|
||||
padding: $mat-button-toggle-legacy-padding;
|
||||
|
||||
.mat-button-toggle-appearance-standard & {
|
||||
line-height: $mat-button-toggle-standard-height;
|
||||
padding: $mat-button-toggle-standard-padding;
|
||||
}
|
||||
}
|
||||
|
||||
.mat-button-toggle-label-content > * {
|
||||
@@ -75,13 +106,22 @@ $mat-button-toggle-border-radius: 2px !default;
|
||||
@include mat-fill;
|
||||
|
||||
.mat-button-toggle-checked & {
|
||||
border-bottom: solid $mat-button-toggle-legacy-height;
|
||||
|
||||
// Changing the background color for the selected item won't be visible in high contrast mode.
|
||||
// We fall back to using the overlay to draw a brighter, semi-transparent tint on top instead.
|
||||
// It uses a border, because the browser will render it using a brighter color.
|
||||
@include cdk-high-contrast {
|
||||
opacity: 0.5;
|
||||
height: 0;
|
||||
border-bottom: solid $mat-button-toggle-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@include cdk-high-contrast {
|
||||
.mat-button-toggle-checked {
|
||||
&.mat-button-toggle-appearance-standard .mat-button-toggle-focus-overlay {
|
||||
border-bottom: solid $mat-button-toggle-standard-height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,8 @@ import {
|
||||
QueryList,
|
||||
ViewChild,
|
||||
ViewEncapsulation,
|
||||
InjectionToken,
|
||||
Inject,
|
||||
} from '@angular/core';
|
||||
import {ControlValueAccessor, NG_VALUE_ACCESSOR} from '@angular/forms';
|
||||
import {
|
||||
@@ -40,6 +42,26 @@ import {
|
||||
/** Acceptable types for a button toggle. */
|
||||
export type ToggleType = 'checkbox' | 'radio';
|
||||
|
||||
/** Possible appearance styles for the button toggle. */
|
||||
export type MatButtonToggleAppearance = 'legacy' | 'standard';
|
||||
|
||||
/**
|
||||
* Represents the default options for the button toggle that can be configured
|
||||
* using the `MAT_BUTTON_TOGGLE_DEFAULT_OPTIONS` injection token.
|
||||
*/
|
||||
export interface MatButtonToggleDefaultOptions {
|
||||
appearance?: MatButtonToggleAppearance;
|
||||
}
|
||||
|
||||
/**
|
||||
* Injection token that can be used to configure the
|
||||
* default options for all button toggles within an app.
|
||||
*/
|
||||
export const MAT_BUTTON_TOGGLE_DEFAULT_OPTIONS =
|
||||
new InjectionToken<MatButtonToggleDefaultOptions>('MAT_BUTTON_TOGGLE_DEFAULT_OPTIONS');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Provider Expression that allows mat-button-toggle-group to register as a ControlValueAccessor.
|
||||
* This allows it to support [(ngModel)].
|
||||
@@ -80,12 +102,12 @@ export class MatButtonToggleChange {
|
||||
'role': 'group',
|
||||
'class': 'mat-button-toggle-group',
|
||||
'[attr.aria-disabled]': 'disabled',
|
||||
'[class.mat-button-toggle-vertical]': 'vertical'
|
||||
'[class.mat-button-toggle-vertical]': 'vertical',
|
||||
'[class.mat-button-toggle-group-appearance-standard]': 'appearance === "standard"',
|
||||
},
|
||||
exportAs: 'matButtonToggleGroup',
|
||||
})
|
||||
export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, AfterContentInit {
|
||||
|
||||
private _vertical = false;
|
||||
private _multiple = false;
|
||||
private _disabled = false;
|
||||
@@ -111,6 +133,9 @@ export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, After
|
||||
/** Child button toggle buttons. */
|
||||
@ContentChildren(forwardRef(() => MatButtonToggle)) _buttonToggles: QueryList<MatButtonToggle>;
|
||||
|
||||
/** The appearance for all the buttons in the group. */
|
||||
@Input() appearance: MatButtonToggleAppearance;
|
||||
|
||||
/** `name` attribute for the underlying `input` element. */
|
||||
@Input()
|
||||
get name(): string { return this._name; }
|
||||
@@ -181,7 +206,14 @@ export class MatButtonToggleGroup implements ControlValueAccessor, OnInit, After
|
||||
@Output() readonly change: EventEmitter<MatButtonToggleChange> =
|
||||
new EventEmitter<MatButtonToggleChange>();
|
||||
|
||||
constructor(private _changeDetector: ChangeDetectorRef) {}
|
||||
constructor(
|
||||
private _changeDetector: ChangeDetectorRef,
|
||||
@Optional() @Inject(MAT_BUTTON_TOGGLE_DEFAULT_OPTIONS)
|
||||
defaultOptions?: MatButtonToggleDefaultOptions) {
|
||||
|
||||
this.appearance =
|
||||
defaultOptions && defaultOptions.appearance ? defaultOptions.appearance : 'standard';
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this._selectionModel = new SelectionModel<MatButtonToggle>(this.multiple, undefined, false);
|
||||
@@ -331,6 +363,7 @@ export const _MatButtonToggleMixinBase: CanDisableRippleCtor & typeof MatButtonT
|
||||
'[class.mat-button-toggle-standalone]': '!buttonToggleGroup',
|
||||
'[class.mat-button-toggle-checked]': 'checked',
|
||||
'[class.mat-button-toggle-disabled]': 'disabled',
|
||||
'[class.mat-button-toggle-appearance-standard]': 'appearance === "standard"',
|
||||
'class': 'mat-button-toggle',
|
||||
// Clear out the native tabindex here since we forward it to the underlying button
|
||||
'[attr.tabindex]': 'null',
|
||||
@@ -377,6 +410,16 @@ export class MatButtonToggle extends _MatButtonToggleMixinBase implements OnInit
|
||||
/** Tabindex for the toggle. */
|
||||
@Input() tabIndex: number | null;
|
||||
|
||||
/** The appearance style of the button. */
|
||||
@Input()
|
||||
get appearance(): MatButtonToggleAppearance {
|
||||
return this.buttonToggleGroup ? this.buttonToggleGroup.appearance : this._appearance;
|
||||
}
|
||||
set appearance(value: MatButtonToggleAppearance) {
|
||||
this._appearance = value;
|
||||
}
|
||||
private _appearance: MatButtonToggleAppearance;
|
||||
|
||||
/** Whether the button is checked. */
|
||||
@Input()
|
||||
get checked(): boolean {
|
||||
@@ -413,12 +456,16 @@ export class MatButtonToggle extends _MatButtonToggleMixinBase implements OnInit
|
||||
private _elementRef: ElementRef<HTMLElement>,
|
||||
private _focusMonitor: FocusMonitor,
|
||||
// @breaking-change 8.0.0 `defaultTabIndex` to be made a required parameter.
|
||||
@Attribute('tabindex') defaultTabIndex: string) {
|
||||
@Attribute('tabindex') defaultTabIndex: string,
|
||||
@Optional() @Inject(MAT_BUTTON_TOGGLE_DEFAULT_OPTIONS)
|
||||
defaultOptions?: MatButtonToggleDefaultOptions) {
|
||||
super();
|
||||
|
||||
const parsedTabIndex = Number(defaultTabIndex);
|
||||
this.tabIndex = (parsedTabIndex || parsedTabIndex === 0) ? parsedTabIndex : null;
|
||||
this.buttonToggleGroup = toggleGroup;
|
||||
this.appearance =
|
||||
defaultOptions && defaultOptions.appearance ? defaultOptions.appearance : 'standard';
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
|
||||
Reference in New Issue
Block a user