From 1433949cc85118d770e65262155861e528570755 Mon Sep 17 00:00:00 2001 From: Yuan Gao Date: Fri, 19 Jan 2018 11:15:42 -0800 Subject: [PATCH 1/3] feat(chips): Add chip avatar and chip trailing icon --- src/demo-app/chips/chips-demo.html | 43 +++++++++- src/lib/chips/_chips-theme.scss | 4 +- src/lib/chips/chip-list.ts | 2 + src/lib/chips/chip.ts | 48 ++++++++++- src/lib/chips/chips-module.ts | 16 +++- src/lib/chips/chips.scss | 124 +++++++++++++++++------------ src/lib/chips/public-api.ts | 1 - 7 files changed, 179 insertions(+), 59 deletions(-) diff --git a/src/demo-app/chips/chips-demo.html b/src/demo-app/chips/chips-demo.html index 3ad365c44110..f4a5b7b980d3 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,47 @@

Advanced

{{message}}
+ +

With avatar and icons

+ + + + + home + Home + cancel + + + P + Portel + cancel + + + + M + Molly + + + + Koby + cancel + + + + Razzle + + + + + Mal + + + + + Husi + cancel + + diff --git a/src/lib/chips/_chips-theme.scss b/src/lib/chips/_chips-theme.scss index fd5ff8f264e6..231dc0d82671 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); 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..058a127756c8 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,7 +49,6 @@ export class MatChipBase { export const _MatChipMixinBase = mixinColor(mixinDisabled(MatChipBase), 'primary'); - /** * Dummy directive to add CSS class to basic chips. * @docs-private @@ -56,8 +57,37 @@ export const _MatChipMixinBase = mixinColor(mixinDisabled(MatChipBase), 'primary selector: `mat-basic-chip, [mat-basic-chip]`, host: {'class': 'mat-basic-chip'}, }) -export class MatBasicChip { -} +export class MatBasicChip {} + +/** + * Dummy directive to add CSS class to standard chips. + * @docs-private + */ +@Directive({ + selector: `mat-chip, [mat-chip]`, + host: {'class': 'mat-standard-chip'}, +}) +export class MatStandardChip {} + +/** + * Dummy directive to add CSS class to chip avatar. + * @docs-private + */ +@Directive({ + selector: 'mat-chip-avatar, [matChipAvatar]', + host: {'class': 'mat-chip-avatar'} +}) +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 +101,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]': 'hasTrailingIcon', '[attr.disabled]': 'disabled || null', '[attr.aria-disabled]': 'disabled.toString()', '[attr.aria-selected]': 'ariaSelected', @@ -95,6 +127,16 @@ 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 remove toggler */ + @ContentChild(MatChipTrailingIcon) trailingIcon: MatChipTrailingIcon; + + @ContentChild(forwardRef(() => MatChipRemove)) removeIcon: Element; + + get hasTrailingIcon() { return this.removeIcon || this.trailingIcon; } + /** Whether the chip is selected. */ @Input() get selected(): boolean { return this._selected; } diff --git a/src/lib/chips/chips-module.ts b/src/lib/chips/chips-module.ts index 3a8ca64e0f81..004929dfe7da 100644 --- a/src/lib/chips/chips-module.ts +++ b/src/lib/chips/chips-module.ts @@ -9,14 +9,24 @@ import {NgModule} from '@angular/core'; import {ErrorStateMatcher} from '@angular/material/core'; import {MatChipList} from './chip-list'; -import {MatBasicChip, MatChip, MatChipRemove} from './chip'; +import {MatBasicChip, MatChip, MatChipRemove, MatChipAvatar, MatChipTrailingIcon, MatStandardChip } from './chip'; import {MatChipInput} from './chip-input'; +const CHIP_DECLARATIONS = [ + MatChipList, + MatChip, + MatChipInput, + MatChipRemove, + MatBasicChip, + MatChipAvatar, + MatChipTrailingIcon, + MatStandardChip +]; @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..10cf25218155 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-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,81 @@ $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:not(.mat-basic-chip) { - display: block; - margin: 0; - margin-bottom: $mat-chips-chip-margin; + &.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; [dir='rtl'] & { - margin: 0; - margin-bottom: $mat-chips-chip-margin; + padding-left: $mat-chip-remove-after-padding; } + } + + &.mat-chip-with-avatar { + padding-left: $mat-chip-avatar-before-padding; - &:last-child, [dir='rtl'] &:last-child { - margin-bottom: 0; + [dir='rtl'] & { + padding-right: $mat-chip-avatar-before-padding; + } + } + + .mat-chip-avatar { + width: $mat-chip-avatar-size; + height: $mat-chip-avatar-size; + margin-right: $mat-chip-avatar-after-margin; + + [dir='rtl'] & { + margin-left: $mat-chip-avatar-after-margin; + } + } + + .mat-chip-remove { + width: $mat-chip-remove-size; + height: $mat-chip-remove-size; + cursor: pointer; + } + + .mat-chip-remove, + .mat-chip-trailing-icon { + margin-left: $mat-chip-remove-before-margin; + + [dir='rtl'] & { + margin-right: $mat-chip-remove-before-margin; } } } -.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-chip.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'; - From 971876658fbbedbd254589b51e9aef34309046c0 Mon Sep 17 00:00:00 2001 From: Yuan Gao Date: Wed, 24 Jan 2018 12:03:50 -0800 Subject: [PATCH 2/3] Removed MatBasicChip and MatStandardChip --- src/demo-app/chips/chips-demo.html | 4 +-- src/lib/chips/chip.ts | 42 ++++++++++++------------------ src/lib/chips/chips-module.ts | 4 +-- src/lib/chips/chips.scss | 22 ++++++++++++++-- 4 files changed, 40 insertions(+), 32 deletions(-) diff --git a/src/demo-app/chips/chips-demo.html b/src/demo-app/chips/chips-demo.html index f4a5b7b980d3..bfc3cf019e22 100644 --- a/src/demo-app/chips/chips-demo.html +++ b/src/demo-app/chips/chips-demo.html @@ -41,7 +41,7 @@

With avatar and icons

Home cancel - + P Portel cancel @@ -66,7 +66,7 @@

With avatar and icons

Mal
- + Husi cancel diff --git a/src/lib/chips/chip.ts b/src/lib/chips/chip.ts index 058a127756c8..e11a78796b17 100644 --- a/src/lib/chips/chip.ts +++ b/src/lib/chips/chip.ts @@ -49,25 +49,7 @@ export class MatChipBase { export const _MatChipMixinBase = mixinColor(mixinDisabled(MatChipBase), 'primary'); -/** - * Dummy directive to add CSS class to basic chips. - * @docs-private - */ -@Directive({ - selector: `mat-basic-chip, [mat-basic-chip]`, - host: {'class': 'mat-basic-chip'}, -}) -export class MatBasicChip {} - -/** - * Dummy directive to add CSS class to standard chips. - * @docs-private - */ -@Directive({ - selector: `mat-chip, [mat-chip]`, - host: {'class': 'mat-standard-chip'}, -}) -export class MatStandardChip {} +const CHIP_ATTRIBUTE_NAMES = ['mat-basic-chip']; /** * Dummy directive to add CSS class to chip avatar. @@ -102,7 +84,7 @@ export class MatChipTrailingIcon {} 'role': 'option', '[class.mat-chip-selected]': 'selected', '[class.mat-chip-with-avatar]': 'avatar', - '[class.mat-chip-with-trailing-icon]': 'hasTrailingIcon', + '[class.mat-chip-with-trailing-icon]': 'trailingIcon', '[attr.disabled]': 'disabled || null', '[attr.aria-disabled]': 'disabled.toString()', '[attr.aria-selected]': 'ariaSelected', @@ -130,13 +112,9 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes /** The chip avatar */ @ContentChild(MatChipAvatar) avatar: MatChipAvatar; - /** The chip remove toggler */ + /** The chip's trailing icon. */ @ContentChild(MatChipTrailingIcon) trailingIcon: MatChipTrailingIcon; - @ContentChild(forwardRef(() => MatChipRemove)) removeIcon: Element; - - get hasTrailingIcon() { return this.removeIcon || this.trailingIcon; } - /** Whether the chip is selected. */ @Input() get selected(): boolean { return this._selected; } @@ -212,6 +190,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 { diff --git a/src/lib/chips/chips-module.ts b/src/lib/chips/chips-module.ts index 004929dfe7da..8c4cb7131cc9 100644 --- a/src/lib/chips/chips-module.ts +++ b/src/lib/chips/chips-module.ts @@ -9,7 +9,7 @@ import {NgModule} from '@angular/core'; import {ErrorStateMatcher} from '@angular/material/core'; import {MatChipList} from './chip-list'; -import {MatBasicChip, MatChip, MatChipRemove, MatChipAvatar, MatChipTrailingIcon, MatStandardChip } from './chip'; +import {MatChip, MatChipRemove, MatChipAvatar, MatChipTrailingIcon} from './chip'; import {MatChipInput} from './chip-input'; const CHIP_DECLARATIONS = [ @@ -17,10 +17,8 @@ const CHIP_DECLARATIONS = [ MatChip, MatChipInput, MatChipRemove, - MatBasicChip, MatChipAvatar, MatChipTrailingIcon, - MatStandardChip ]; @NgModule({ diff --git a/src/lib/chips/chips.scss b/src/lib/chips/chips.scss index 10cf25218155..3c3f93ce6cf6 100644 --- a/src/lib/chips/chips.scss +++ b/src/lib/chips/chips.scss @@ -20,7 +20,7 @@ $mat-chip-input-margin: 3px; $mat-chip-avatar-size: 32px; $mat-chip-remove-size: 18px; -.mat-chip.mat-standard-chip { +.mat-standard-chip { @include mat-elevation-transition; display: inline-flex; padding: $mat-chip-vertical-padding $mat-chip-horizontal-padding; @@ -52,21 +52,35 @@ $mat-chip-remove-size: 18px; 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; [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; } } @@ -74,9 +88,11 @@ $mat-chip-remove-size: 18px; width: $mat-chip-avatar-size; height: $mat-chip-avatar-size; margin-right: $mat-chip-avatar-after-margin; + margin-left: 0; [dir='rtl'] & { margin-left: $mat-chip-avatar-after-margin; + margin-right: 0; } } @@ -89,9 +105,11 @@ $mat-chip-remove-size: 18px; .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; } } } @@ -107,7 +125,7 @@ $mat-chip-remove-size: 18px; flex-direction: column; align-items: flex-start; - .mat-chip.mat-standard-chip { + .mat-standard-chip { width: 100%; } } From b8a820562e5a7bc7c67c86a0d8c74e49200144db Mon Sep 17 00:00:00 2001 From: Yuan Gao Date: Wed, 24 Jan 2018 14:55:51 -0800 Subject: [PATCH 3/3] Add mat-chip-trailing-icon style to MatChipRemove and add examples in demo --- src/demo-app/chips/chips-demo.html | 17 +++++++++++++---- src/lib/chips/_chips-theme.scss | 1 + src/lib/chips/chip.ts | 7 +++++-- src/lib/chips/chips.scss | 3 ++- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/src/demo-app/chips/chips-demo.html b/src/demo-app/chips/chips-demo.html index bfc3cf019e22..692d23e40da9 100644 --- a/src/demo-app/chips/chips-demo.html +++ b/src/demo-app/chips/chips-demo.html @@ -39,12 +39,12 @@

With avatar and icons

home Home - cancel + cancel P Portel - cancel + cancel @@ -54,7 +54,7 @@

With avatar and icons

Koby - cancel + cancel @@ -69,7 +69,16 @@

With avatar and icons

Husi - cancel + cancel + + + + Good + star + + + Bad + star_border diff --git a/src/lib/chips/_chips-theme.scss b/src/lib/chips/_chips-theme.scss index 231dc0d82671..26110c83d688 100644 --- a/src/lib/chips/_chips-theme.scss +++ b/src/lib/chips/_chips-theme.scss @@ -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.ts b/src/lib/chips/chip.ts index e11a78796b17..bd60b052354b 100644 --- a/src/lib/chips/chip.ts +++ b/src/lib/chips/chip.ts @@ -84,7 +84,7 @@ export class MatChipTrailingIcon {} 'role': 'option', '[class.mat-chip-selected]': 'selected', '[class.mat-chip-with-avatar]': 'avatar', - '[class.mat-chip-with-trailing-icon]': 'trailingIcon', + '[class.mat-chip-with-trailing-icon]': 'trailingIcon || removeIcon', '[attr.disabled]': 'disabled || null', '[attr.aria-disabled]': 'disabled.toString()', '[attr.aria-selected]': 'ariaSelected', @@ -115,6 +115,9 @@ export class MatChip extends _MatChipMixinBase implements FocusableOption, OnDes /** 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; } @@ -334,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.scss b/src/lib/chips/chips.scss index 3c3f93ce6cf6..de53e33fd911 100644 --- a/src/lib/chips/chips.scss +++ b/src/lib/chips/chips.scss @@ -96,7 +96,8 @@ $mat-chip-remove-size: 18px; } } - .mat-chip-remove { + .mat-chip-remove, + .mat-chip-trailing-icon { width: $mat-chip-remove-size; height: $mat-chip-remove-size; cursor: pointer;