diff --git a/src/demo-app/chips/chips-demo.html b/src/demo-app/chips/chips-demo.html index 3ad365c44110..692d23e40da9 100644 --- a/src/demo-app/chips/chips-demo.html +++ b/src/demo-app/chips/chips-demo.html @@ -8,7 +8,7 @@

Simple

Chip 1 Chip 2 - Chip 3 + Chip 3

Unstyled

@@ -31,6 +31,56 @@

Advanced

{{message}}
+ +

With avatar and icons

+ + + + + home + Home + cancel + + + P + Portel + cancel + + + + M + Molly + + + + Koby + cancel + + + + Razzle + + + + + Mal + + + + + Husi + cancel + + + + Good + star + + + Bad + star_border + + diff --git a/src/lib/chips/_chips-theme.scss b/src/lib/chips/_chips-theme.scss index fd5ff8f264e6..26110c83d688 100644 --- a/src/lib/chips/_chips-theme.scss +++ b/src/lib/chips/_chips-theme.scss @@ -37,11 +37,11 @@ $mat-chip-remove-font-size: 18px; $unselected-foreground: mat-color($foreground, text); - .mat-chip:not(.mat-basic-chip) { + .mat-chip.mat-standard-chip { @include mat-chips-color($unselected-foreground, $unselected-background); } - .mat-chip.mat-chip-selected { + .mat-chip.mat-standard-chip.mat-chip-selected { &.mat-primary { @include mat-chips-theme-color($primary); @@ -62,6 +62,7 @@ $mat-chip-remove-font-size: 18px; font-size: $mat-chip-font-size; line-height: $mat-chip-line-height; + .mat-chip-trailing-icon.mat-icon, .mat-chip-remove.mat-icon { font-size: $mat-chip-remove-font-size; } diff --git a/src/lib/chips/chip-list.ts b/src/lib/chips/chip-list.ts index 643b4d6022aa..dc71b062c372 100644 --- a/src/lib/chips/chip-list.ts +++ b/src/lib/chips/chip-list.ts @@ -21,6 +21,7 @@ import { DoCheck, ElementRef, EventEmitter, + Inject, Input, OnDestroy, OnInit, @@ -752,3 +753,4 @@ export class MatChipList extends _MatChipListMixinBase implements MatFormFieldCo }); } } + diff --git a/src/lib/chips/chip.ts b/src/lib/chips/chip.ts index 7871ac4fcc96..bd60b052354b 100644 --- a/src/lib/chips/chip.ts +++ b/src/lib/chips/chip.ts @@ -10,9 +10,11 @@ import {FocusableOption} from '@angular/cdk/a11y'; import {coerceBooleanProperty} from '@angular/cdk/coercion'; import {BACKSPACE, DELETE, SPACE} from '@angular/cdk/keycodes'; import { + ContentChild, Directive, ElementRef, EventEmitter, + forwardRef, Input, OnDestroy, Output, @@ -47,17 +49,27 @@ export class MatChipBase { export const _MatChipMixinBase = mixinColor(mixinDisabled(MatChipBase), 'primary'); +const CHIP_ATTRIBUTE_NAMES = ['mat-basic-chip']; /** - * Dummy directive to add CSS class to basic chips. + * Dummy directive to add CSS class to chip avatar. * @docs-private */ @Directive({ - selector: `mat-basic-chip, [mat-basic-chip]`, - host: {'class': 'mat-basic-chip'}, + selector: 'mat-chip-avatar, [matChipAvatar]', + host: {'class': 'mat-chip-avatar'} }) -export class MatBasicChip { -} +export class MatChipAvatar {} + +/** + * Dummy directive to add CSS class to chip trailing icon. + * @docs-private + */ +@Directive({ + selector: 'mat-chip-trailing-icon, [matChipTrailingIcon]', + host: {'class': 'mat-chip-trailing-icon'} +}) +export class MatChipTrailingIcon {} /** * Material design styled Chip component. Used inside the MatChipList component. @@ -71,6 +83,8 @@ export class MatBasicChip { '[attr.tabindex]': 'disabled ? null : -1', 'role': 'option', '[class.mat-chip-selected]': 'selected', + '[class.mat-chip-with-avatar]': 'avatar', + '[class.mat-chip-with-trailing-icon]': 'trailingIcon || removeIcon', '[attr.disabled]': 'disabled || null', '[attr.aria-disabled]': 'disabled.toString()', '[attr.aria-selected]': 'ariaSelected', @@ -95,6 +109,15 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes /** Whether the chip has focus. */ _hasFocus: boolean = false; + /** The chip avatar */ + @ContentChild(MatChipAvatar) avatar: MatChipAvatar; + + /** The chip's trailing icon. */ + @ContentChild(MatChipTrailingIcon) trailingIcon: MatChipTrailingIcon; + + /** The chip's remove toggler. */ + @ContentChild(forwardRef(() => MatChipRemove)) removeIcon: MatChipRemove; + /** Whether the chip is selected. */ @Input() get selected(): boolean { return this._selected; } @@ -170,6 +193,20 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes constructor(public _elementRef: ElementRef) { super(_elementRef); + + this._addHostClassName(); + } + + _addHostClassName() { + // Add class for the different chips + for (const attr of CHIP_ATTRIBUTE_NAMES) { + if (this._elementRef.nativeElement.hasAttribute(attr) || + this._elementRef.nativeElement.tagName.toLowerCase() === attr) { + (this._elementRef.nativeElement as HTMLElement).classList.add(attr); + return; + } + } + (this._elementRef.nativeElement as HTMLElement).classList.add('mat-standard-chip'); } ngOnDestroy(): void { @@ -300,7 +337,7 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes @Directive({ selector: '[matChipRemove]', host: { - 'class': 'mat-chip-remove', + 'class': 'mat-chip-remove mat-chip-trailing-icon', '(click)': '_handleClick()', } }) diff --git a/src/lib/chips/chips-module.ts b/src/lib/chips/chips-module.ts index 3a8ca64e0f81..8c4cb7131cc9 100644 --- a/src/lib/chips/chips-module.ts +++ b/src/lib/chips/chips-module.ts @@ -9,14 +9,22 @@ import {NgModule} from '@angular/core'; import {ErrorStateMatcher} from '@angular/material/core'; import {MatChipList} from './chip-list'; -import {MatBasicChip, MatChip, MatChipRemove} from './chip'; +import {MatChip, MatChipRemove, MatChipAvatar, MatChipTrailingIcon} from './chip'; import {MatChipInput} from './chip-input'; +const CHIP_DECLARATIONS = [ + MatChipList, + MatChip, + MatChipInput, + MatChipRemove, + MatChipAvatar, + MatChipTrailingIcon, +]; @NgModule({ imports: [], - exports: [MatChipList, MatChip, MatChipInput, MatChipRemove, MatChipRemove, MatBasicChip], - declarations: [MatChipList, MatChip, MatChipInput, MatChipRemove, MatChipRemove, MatBasicChip], + exports: CHIP_DECLARATIONS, + declarations: CHIP_DECLARATIONS, providers: [ErrorStateMatcher] }) export class MatChipsModule {} diff --git a/src/lib/chips/chips.scss b/src/lib/chips/chips.scss index 541e9cc2bb13..de53e33fd911 100644 --- a/src/lib/chips/chips.scss +++ b/src/lib/chips/chips.scss @@ -3,22 +3,24 @@ $mat-chip-vertical-padding: 7px; $mat-chip-horizontal-padding: 12px; -$mat-chip-remove-margin-before: 6px; -$mat-chip-remove-margin-after: -4px; -$mat-chips-chip-margin: 8px; +$mat-chip-remove-vertical-padding: 7px; +$mat-chip-remove-before-margin: 7px; +$mat-chip-remove-after-padding: 7px; + +$mat-chip-avatar-vertical-padding: 0; +$mat-chip-avatar-before-padding: 0; +$mat-chip-avatar-after-margin: 8px; + +$mat-chips-chip-margin: 4px; $mat-chip-input-width: 150px; $mat-chip-input-margin: 3px; -.mat-chip-list-wrapper { - display: flex; - flex-direction: row; - flex-wrap: wrap; - align-items: baseline; -} +$mat-chip-avatar-size: 32px; +$mat-chip-remove-size: 18px; -.mat-chip:not(.mat-basic-chip) { +.mat-standard-chip { @include mat-elevation-transition; display: inline-flex; padding: $mat-chip-vertical-padding $mat-chip-horizontal-padding; @@ -26,28 +28,13 @@ $mat-chip-input-margin: 3px; align-items: center; cursor: default; - // Apply a margin to adjacent sibling chips. - & + & { - margin: 0 0 0 $mat-chips-chip-margin; - - [dir='rtl'] & { - margin: 0 $mat-chips-chip-margin 0 0; - } - } - - .mat-form-field-prefix & { - &:last-child { - margin-right: $mat-chips-chip-margin; - } - - [dir='rtl'] &:last-child { - margin-left: $mat-chips-chip-margin; - } + .mat-chip-list-wrapper & { + margin: $mat-chips-chip-margin; } .mat-chip-remove.mat-icon { - width: 1em; - height: 1em; + width: $mat-chip-remove-size; + height: $mat-chip-remove-size; } &:focus { @@ -58,42 +45,100 @@ $mat-chip-input-margin: 3px; @include cdk-high-contrast { outline: solid 1px; } -} -.mat-chip-list-stacked .mat-chip-list-wrapper { - display: block; + &.mat-chip-with-trailing-icon.mat-chip-with-avatar, + &.mat-chip-with-avatar { + padding-top: $mat-chip-avatar-vertical-padding; + padding-bottom: $mat-chip-avatar-vertical-padding; + } + + &.mat-chip-with-trailing-icon.mat-chip-with-avatar { + padding-right: $mat-chip-remove-after-padding; + padding-left: $mat-chip-avatar-before-padding; + + [dir='rtl'] & { + padding-left: $mat-chip-remove-after-padding; + padding-right: $mat-chip-avatar-before-padding; + } + } + + &.mat-chip-with-trailing-icon { + padding-top: $mat-chip-remove-vertical-padding; + padding-bottom: $mat-chip-remove-vertical-padding; + padding-right: $mat-chip-remove-after-padding; + padding-left: $mat-chip-horizontal-padding; - .mat-chip:not(.mat-basic-chip) { - display: block; - margin: 0; - margin-bottom: $mat-chips-chip-margin; + [dir='rtl'] & { + padding-left: $mat-chip-remove-after-padding; + padding-right: $mat-chip-horizontal-padding; + } + } + + &.mat-chip-with-avatar { + padding-left: $mat-chip-avatar-before-padding; + padding-right: $mat-chip-horizontal-padding; + + [dir='rtl'] & { + padding-right: $mat-chip-avatar-before-padding; + padding-left: $mat-chip-horizontal-padding; + } + } + + .mat-chip-avatar { + width: $mat-chip-avatar-size; + height: $mat-chip-avatar-size; + margin-right: $mat-chip-avatar-after-margin; + margin-left: 0; [dir='rtl'] & { - margin: 0; - margin-bottom: $mat-chips-chip-margin; + margin-left: $mat-chip-avatar-after-margin; + margin-right: 0; } + } + + .mat-chip-remove, + .mat-chip-trailing-icon { + width: $mat-chip-remove-size; + height: $mat-chip-remove-size; + cursor: pointer; + } - &:last-child, [dir='rtl'] &:last-child { - margin-bottom: 0; + .mat-chip-remove, + .mat-chip-trailing-icon { + margin-left: $mat-chip-remove-before-margin; + margin-right: 0; + + [dir='rtl'] & { + margin-right: $mat-chip-remove-before-margin; + margin-left: 0; } } } -.mat-form-field-prefix .mat-chip-list-wrapper { - margin-bottom: $mat-chips-chip-margin; +.mat-chip-list-wrapper { + display: flex; + flex-direction: row; + flex-wrap: wrap; + align-items: center; } -.mat-chip-remove { - margin-right: $mat-chip-remove-margin-after; - margin-left: $mat-chip-remove-margin-before; - cursor: pointer; +.mat-chip-list-stacked .mat-chip-list-wrapper { + flex-direction: column; + align-items: flex-start; - [dir='rtl'] & { - margin-right: $mat-chip-remove-margin-before; - margin-left: $mat-chip-remove-margin-after; + .mat-standard-chip { + width: 100%; } } +.mat-chip-avatar { + border-radius: 50%; + justify-content: center; + align-items: center; + display: flex; + overflow: hidden; +} + input.mat-chip-input { width: $mat-chip-input-width; margin: $mat-chip-input-margin; diff --git a/src/lib/chips/public-api.ts b/src/lib/chips/public-api.ts index a93755ac6646..940403e4c0be 100644 --- a/src/lib/chips/public-api.ts +++ b/src/lib/chips/public-api.ts @@ -10,4 +10,3 @@ export * from './chips-module'; export * from './chip-list'; export * from './chip'; export * from './chip-input'; -