mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat: add simplified checkbox component for usage in other components (#2619)
* feat: add simplified checkbox component for usage in other components Adds the `md-pseudo-checkbox`, which is a simplified version of `md-checkbox`, that doesn't have the expensive SVG animations or the form control logic. This will be useful for multiple selection in `md-select`, as well as other components in the future. Relates to #2412. * Remove unnecessary template. * Fix linter error. * Address PR feedback. * Trailing comma.
This commit is contained in:
committed by
Andrew Seguin
parent
408c58d569
commit
3b6cab01c7
@@ -1,26 +1,21 @@
|
||||
@import '../core/theming/theming';
|
||||
@import '../core/style/elevation';
|
||||
@import '../core/style/variables';
|
||||
@import '../core/style/checkbox-common';
|
||||
@import '../core/ripple/ripple';
|
||||
|
||||
|
||||
// The width/height of the checkbox element.
|
||||
$md-checkbox-size: $md-toggle-size !default;
|
||||
// The width of the line used to draw the checkmark / mixedmark.
|
||||
$md-checkbox-mark-stroke-size: 2/15 * $md-checkbox-size !default;
|
||||
// The width of the checkbox border shown when the checkbox is unchecked.
|
||||
$md-checkbox-border-width: 2px;
|
||||
// The base duration used for the majority of transitions for the checkbox.
|
||||
$md-checkbox-transition-duration: 90ms;
|
||||
// The amount of spacing between the checkbox and its label.
|
||||
$md-checkbox-item-spacing: $md-toggle-padding;
|
||||
|
||||
// Manual calculation done on SVG
|
||||
$_md-checkbox-mark-path-length: 22.910259;
|
||||
$_md-checkbox-indeterminate-checked-easing-function: cubic-bezier(0.14, 0, 0, 1);
|
||||
|
||||
// The ripple size of the checkbox
|
||||
$md-checkbox-ripple-size: 15px;
|
||||
$_md-checkbox-ripple-size: 15px;
|
||||
|
||||
// The amount of spacing between the checkbox and its label.
|
||||
$_md-checkbox-item-spacing: $md-toggle-padding;
|
||||
|
||||
// The width of the line used to draw the checkmark / mixedmark.
|
||||
$_md-checkbox-mark-stroke-size: 2 / 15 * $md-checkbox-size !default;
|
||||
|
||||
|
||||
// Fades in the background of the checkbox when it goes from unchecked -> {checked,indeterminate}.
|
||||
@keyframes md-checkbox-fade-in-background {
|
||||
@@ -213,7 +208,7 @@ md-checkbox {
|
||||
height: $md-checkbox-size;
|
||||
line-height: 0;
|
||||
margin: auto;
|
||||
margin-right: $md-checkbox-item-spacing;
|
||||
margin-right: $_md-checkbox-item-spacing;
|
||||
order: 0;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
@@ -223,7 +218,7 @@ md-checkbox {
|
||||
|
||||
[dir='rtl'] & {
|
||||
margin: {
|
||||
left: $md-checkbox-item-spacing;
|
||||
left: $_md-checkbox-item-spacing;
|
||||
right: auto;
|
||||
}
|
||||
}
|
||||
@@ -264,14 +259,14 @@ md-checkbox {
|
||||
stroke: {
|
||||
dashoffset: $_md-checkbox-mark-path-length;
|
||||
dasharray: $_md-checkbox-mark-path-length;
|
||||
width: $md-checkbox-mark-stroke-size;
|
||||
width: $_md-checkbox-mark-stroke-size;
|
||||
}
|
||||
}
|
||||
|
||||
.md-checkbox-mixedmark {
|
||||
@extend %md-checkbox-mark;
|
||||
|
||||
height: floor($md-checkbox-mark-stroke-size);
|
||||
height: floor($_md-checkbox-mark-stroke-size);
|
||||
opacity: 0;
|
||||
transform: scaleX(0) rotate(0deg);
|
||||
}
|
||||
@@ -280,14 +275,14 @@ md-checkbox {
|
||||
.md-checkbox-inner-container {
|
||||
order: 1;
|
||||
margin: {
|
||||
left: $md-checkbox-item-spacing;
|
||||
left: $_md-checkbox-item-spacing;
|
||||
right: auto;
|
||||
}
|
||||
|
||||
[dir='rtl'] & {
|
||||
margin: {
|
||||
left: auto;
|
||||
right: $md-checkbox-item-spacing;
|
||||
right: $_md-checkbox-item-spacing;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,10 +414,10 @@ md-checkbox {
|
||||
|
||||
.md-checkbox-ripple {
|
||||
position: absolute;
|
||||
left: -$md-checkbox-ripple-size;
|
||||
top: -$md-checkbox-ripple-size;
|
||||
right: -$md-checkbox-ripple-size;
|
||||
bottom: -$md-checkbox-ripple-size;
|
||||
left: -$_md-checkbox-ripple-size;
|
||||
top: -$_md-checkbox-ripple-size;
|
||||
right: -$_md-checkbox-ripple-size;
|
||||
bottom: -$_md-checkbox-ripple-size;
|
||||
border-radius: 50%;
|
||||
z-index: 1;
|
||||
pointer-events: none;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
@import 'ripple/ripple';
|
||||
@import 'option/option';
|
||||
@import 'option/option-theme';
|
||||
@import 'selection/pseudo-checkbox/pseudo-checkbox-theme';
|
||||
|
||||
// Mixin that renders all of the core styles that are not theme-dependent.
|
||||
@mixin md-core() {
|
||||
@@ -27,6 +28,7 @@
|
||||
@mixin md-core-theme($theme) {
|
||||
@include md-ripple-theme($theme);
|
||||
@include md-option-theme($theme);
|
||||
@include md-pseudo-checkbox-theme($theme);
|
||||
|
||||
// Wrapper element that provides the theme background when the
|
||||
// user's content isn't inside of a `md-sidenav-container`.
|
||||
|
||||
@@ -7,6 +7,7 @@ import {MdRippleModule} from './ripple/ripple';
|
||||
import {PortalModule} from './portal/portal-directives';
|
||||
import {OverlayModule} from './overlay/overlay-directives';
|
||||
import {A11yModule} from './a11y/index';
|
||||
import {MdSelectionModule} from './selection/index';
|
||||
|
||||
|
||||
// RTL
|
||||
@@ -114,6 +115,9 @@ export * from './compatibility/compatibility';
|
||||
// Animation
|
||||
export * from './animation/animation';
|
||||
|
||||
// Selection
|
||||
export * from './selection/index';
|
||||
|
||||
// Coercion
|
||||
export {coerceBooleanProperty} from './coercion/boolean-property';
|
||||
export {coerceNumberProperty} from './coercion/number-property';
|
||||
@@ -131,7 +135,8 @@ export {CompatibilityModule, NoConflictStyleCompatibilityMode} from './compatibi
|
||||
PortalModule,
|
||||
OverlayModule,
|
||||
A11yModule,
|
||||
MdOptionModule
|
||||
MdOptionModule,
|
||||
MdSelectionModule,
|
||||
],
|
||||
exports: [
|
||||
MdLineModule,
|
||||
@@ -141,7 +146,8 @@ export {CompatibilityModule, NoConflictStyleCompatibilityMode} from './compatibi
|
||||
PortalModule,
|
||||
OverlayModule,
|
||||
A11yModule,
|
||||
MdOptionModule
|
||||
MdOptionModule,
|
||||
MdSelectionModule,
|
||||
],
|
||||
})
|
||||
export class MdCoreModule {
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
import {NgModule} from '@angular/core';
|
||||
import {MdPseudoCheckbox} from './pseudo-checkbox/pseudo-checkbox';
|
||||
|
||||
export * from './pseudo-checkbox/pseudo-checkbox';
|
||||
|
||||
@NgModule({
|
||||
exports: [MdPseudoCheckbox],
|
||||
declarations: [MdPseudoCheckbox]
|
||||
})
|
||||
export class MdSelectionModule { }
|
||||
@@ -0,0 +1,44 @@
|
||||
@import '../../theming/theming';
|
||||
|
||||
|
||||
@mixin md-pseudo-checkbox-theme($theme) {
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$primary: map-get($theme, primary);
|
||||
$accent: map-get($theme, accent);
|
||||
$warn: map-get($theme, warn);
|
||||
$background: map-get($theme, background);
|
||||
|
||||
// The color of the checkbox's checkmark / mixedmark.
|
||||
$checkbox-mark-color: md-color($background, background);
|
||||
|
||||
// NOTE(traviskaufman): While the spec calls for translucent blacks/whites for disabled colors,
|
||||
// this does not work well with elements layered on top of one another. To get around this we
|
||||
// blend the colors together based on the base color and the theme background.
|
||||
$white-30pct-opacity-on-dark: #686868;
|
||||
$black-26pct-opacity-on-light: #b0b0b0;
|
||||
$disabled-color: if($is-dark-theme, $white-30pct-opacity-on-dark, $black-26pct-opacity-on-light);
|
||||
|
||||
md-pseudo-checkbox::after {
|
||||
color: $checkbox-mark-color;
|
||||
}
|
||||
|
||||
.md-pseudo-checkbox-checked, .md-pseudo-checkbox-indeterminate {
|
||||
border: none;
|
||||
|
||||
&.md-primary {
|
||||
background: md-color($primary, 500);
|
||||
}
|
||||
|
||||
&.md-accent {
|
||||
background: md-color($accent, 500);
|
||||
}
|
||||
|
||||
&.md-warn {
|
||||
background: md-color($warn, 500);
|
||||
}
|
||||
|
||||
&.md-pseudo-checkbox-disabled {
|
||||
background: $disabled-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
@import '../../style/checkbox-common';
|
||||
|
||||
// Padding inside of a pseudo checkbox.
|
||||
$_md-pseudo-checkbox-padding: $md-checkbox-border-width * 2;
|
||||
|
||||
// Size of the checkmark in a pseudo checkbox.
|
||||
$_md-pseudo-checkmark-size: $md-checkbox-size - (2 * $_md-pseudo-checkbox-padding);
|
||||
|
||||
|
||||
md-pseudo-checkbox {
|
||||
width: $md-checkbox-size;
|
||||
height: $md-checkbox-size;
|
||||
border: $md-checkbox-border-width solid;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
transition:
|
||||
border-color $md-checkbox-transition-duration $md-linear-out-slow-in-timing-function,
|
||||
background-color $md-checkbox-transition-duration $md-linear-out-slow-in-timing-function;
|
||||
|
||||
// Used to render the checkmark/mixedmark inside of the box.
|
||||
&::after {
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
content: '';
|
||||
border-bottom: $md-checkbox-border-width solid currentColor;
|
||||
transition: opacity $md-checkbox-transition-duration $md-linear-out-slow-in-timing-function;
|
||||
}
|
||||
}
|
||||
|
||||
.md-pseudo-checkbox-disabled {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.md-pseudo-checkbox-indeterminate::after {
|
||||
top: ($md-checkbox-size - $md-checkbox-border-width) / 2;
|
||||
left: $md-checkbox-border-width;
|
||||
width: $md-checkbox-size - ($md-checkbox-border-width * 2);
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.md-pseudo-checkbox-checked::after {
|
||||
top: ($md-checkbox-size / 2) - ($_md-pseudo-checkmark-size / 4) - ($md-checkbox-size / 10);
|
||||
left: $_md-pseudo-checkbox-padding - $md-checkbox-border-width / 2;
|
||||
width: $_md-pseudo-checkmark-size;
|
||||
height: ($_md-pseudo-checkmark-size - $md-checkbox-border-width) / 2;
|
||||
border-left: $md-checkbox-border-width solid currentColor;
|
||||
transform: rotate(-45deg);
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
import {
|
||||
Component,
|
||||
ViewEncapsulation,
|
||||
Input,
|
||||
ElementRef,
|
||||
Renderer,
|
||||
} from '@angular/core';
|
||||
|
||||
export type MdPseudoCheckboxState = 'unchecked' | 'checked' | 'indeterminate';
|
||||
|
||||
/**
|
||||
* Component that shows a simplified checkbox without including any kind of "real" checkbox.
|
||||
* Meant to be used when the checkbox is purely decorative and a large number of them will be
|
||||
* included, such as for the options in a multi-select. Uses no SVGs or complex animations.
|
||||
*
|
||||
* Note that this component will be completely invisible to screen-reader users. This is *not*
|
||||
* interchangeable with <md-checkbox> and should *not* be used if the user would directly interact
|
||||
* with the checkbox. The pseudo-checkbox should only be used as an implementation detail of
|
||||
* more complex components that appropriately handle selected / checked state.
|
||||
* @docs-private
|
||||
*/
|
||||
@Component({
|
||||
moduleId: module.id,
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
selector: 'md-pseudo-checkbox',
|
||||
styleUrls: ['pseudo-checkbox.css'],
|
||||
template: '',
|
||||
host: {
|
||||
'[class.md-pseudo-checkbox-indeterminate]': 'state === "indeterminate"',
|
||||
'[class.md-pseudo-checkbox-checked]': 'state === "checked"',
|
||||
'[class.md-pseudo-checkbox-disabled]': 'disabled',
|
||||
},
|
||||
})
|
||||
export class MdPseudoCheckbox {
|
||||
/** Display state of the checkbox. */
|
||||
@Input() state: MdPseudoCheckboxState = 'unchecked';
|
||||
|
||||
/** Whether the checkbox is disabled. */
|
||||
@Input() disabled: boolean = false;
|
||||
|
||||
/** Color of the checkbox. */
|
||||
@Input()
|
||||
get color(): string { return this._color; };
|
||||
set color(value: string) {
|
||||
if (value) {
|
||||
let nativeElement = this._elementRef.nativeElement;
|
||||
|
||||
this._renderer.setElementClass(nativeElement, `md-${this.color}`, false);
|
||||
this._renderer.setElementClass(nativeElement, `md-${value}`, true);
|
||||
this._color = value;
|
||||
}
|
||||
}
|
||||
|
||||
private _color: string;
|
||||
|
||||
constructor(private _elementRef: ElementRef, private _renderer: Renderer) {
|
||||
this.color = 'accent';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
@import './variables';
|
||||
|
||||
// The width/height of the checkbox element.
|
||||
$md-checkbox-size: $md-toggle-size !default;
|
||||
|
||||
// The width of the checkbox border shown when the checkbox is unchecked.
|
||||
$md-checkbox-border-width: 2px;
|
||||
|
||||
// The base duration used for the majority of transitions for the checkbox.
|
||||
$md-checkbox-transition-duration: 90ms;
|
||||
Reference in New Issue
Block a user