Skip to content
This repository has been archived by the owner on Oct 7, 2020. It is now read-only.

feat(chips): Add touch target #2071

Merged
merged 5 commits into from
Feb 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demos/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const routes: Routes = [
},
{
path: 'chips-demo', loadChildren: () =>
import('./components/chips-demo/chips.module').then(m => m.ChipsModule)
import('./components/chips/module').then(m => m.ChipsModule)
},
{path: 'theme-docs', loadChildren: () => import('./components/theme-docs/theme.module').then(m => m.ThemeModule)},
{
Expand Down
29 changes: 0 additions & 29 deletions demos/src/app/components/chips-demo/routing.module.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,22 @@ <h4 mdcSubtitle2>Properties</h4>
<tbody>
<tr>
<td>choice: boolean</td>
<td>Indicates that the chips in the set are choice chips, which allow a single selection from a set of options.</td>
<td>Indicates that the chips in the set are choice chips, which allow a
single selection from a set of options.</td>
</tr>
<tr>
<td>filter: boolean</td>
<td>Indicates that the chips in the set are filter chips, which allow multiple selection from a set of options.</td>
<td>Indicates that the chips in the set are filter chips, which allow
multiple selection from a set of options.</td>
</tr>
<tr>
<td>input: boolean</td>
<td>Indicates that the chips in the set are input chips, which enable user input by converting text into chips.</td>
<td>Indicates that the chips in the set are input chips, which enable
user input by converting text into chips.</td>
</tr>
<tr>
<td>touch: boolean</td>
<td>Set the component touch target to 48 x 48 px.</td>
</tr>
</tbody>
</table>
Expand All @@ -39,7 +46,8 @@ <h4 mdcSubtitle2>Methods</h4>
</tr>
<tr>
<td>select(chipId: string): void</td>
<td>Selects the chip with the given id. Deselects all other chips if the chip set is of the choice variant.</td>
<td>Selects the chip with the given id. Deselects all other chips if the
chip set is of the choice variant.</td>
</tr>
</tbody>
</table>
Expand All @@ -49,7 +57,8 @@ <h4 mdcSubtitle2>Events</h4>
<tbody>
<tr>
<td>interaction: MdcChipInteractionEvent</td>
<td>Indicates when a chip is interacted with (via click/tap or Enter key)</td>
<td>Indicates when a chip is interacted with (via click/tap or Enter
key)</td>
</tr>
<tr>
<td>change: MdcChipSetChange</td>
Expand Down Expand Up @@ -78,27 +87,32 @@ <h4 mdcSubtitle2>Properties</h4>
<tbody>
<tr>
<td>choice: boolean</td>
<td>Indicates that the chips in the set are choice chips, which allow a single selection from a set of options.</td>
<td>Indicates that the chips in the set are choice chips, which allow a
single selection from a set of options.</td>
</tr>
<tr>
<td>filter: boolean</td>
<td>Indicates that the chips in the set are filter chips, which allow multiple selection from a set of options.</td>
<td>Indicates that the chips in the set are filter chips, which allow
multiple selection from a set of options.</td>
</tr>
<tr>
<td>input: boolean</td>
<td>Indicates that the chips in the set are input chips, which enable user input by converting text into chips.</td>
<td>Indicates that the chips in the set are input chips, which enable
user input by converting text into chips.</td>
</tr>
<tr>
<td>label: string</td>
<td>Sets the text content of the chip.</td>
</tr>
<tr>
<td>value: string | string[]</td>
<td>The value of the chip. Defaults to the content inside <code>mdc-chip</code>.</td>
<td>The value of the chip. Defaults to the content inside
<code>mdc-chip</code>.</td>
</tr>
<tr>
<td>removable: boolean</td>
<td>Sets whether a trailing icon click should trigger exit/removal of the chip. (Default is true)</td>
<td>Sets whether a trailing icon click should trigger exit/removal of
the chip. (Default is true)</td>
</tr>
<tr>
<td>disableRipple: boolean</td>
Expand All @@ -122,11 +136,13 @@ <h4 mdcSubtitle2>Events</h4>
<tbody>
<tr>
<td>interactionEvent: MdcChipInteractionEvent</td>
<td>Indicates the chip was interacted with (via click/tap or Enter key)</td>
<td>Indicates the chip was interacted with (via click/tap or Enter key)
</td>
</tr>
<tr>
<td>selectionChange: MdcChipSelectionEvent</td>
<td>Indicates the chip's selection state has changed (for choice/filter chips)</td>
<td>Indicates the chip's selection state has changed (for choice/filter
chips)</td>
</tr>
<tr>
<td>removalEvent: MdcChipRemovalEvent</td>
Expand All @@ -138,7 +154,8 @@ <h4 mdcSubtitle2>Events</h4>
</tr>
<tr>
<td>trailingIconInteraction: MdcChipInteractionEvent</td>
<td>Indicates the chip's trailing icon was interacted with (via click/tap or Enter key)</td>
<td>Indicates the chip's trailing icon was interacted with (via
click/tap or Enter key)</td>
</tr>
</tbody>
</table>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class Api {}
export class Sass {}

@Component({template: '<component-viewer></component-viewer>'})
export class ChipsDemo implements OnInit {
export class Chips implements OnInit {
@ViewChild(ComponentViewer, {static: true}) _componentViewer: ComponentViewer;

ngOnInit(): void {
Expand Down Expand Up @@ -304,4 +304,10 @@ formControl = new FormControl('steak-0', Validators.required);

@ViewChild('form') form: NgForm;`
};

exampleAccessibility = {
html: `<div class="mdc-touch-target-wrapper">
<mdc-chip touch label="My Accessibility Chip"></mdc-chip>
</div>`
};
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<div class="demo-content">
<div class="demo-layout__row">
<button mdc-button (click)="simplechip.disableRipple = !simplechip.disableRipple">Disable
<button mdc-button
(click)="simplechip.disableRipple = !simplechip.disableRipple">Disable
Ripple: {{simplechip.disableRipple ? 'On' : 'Off'}}</button>
</div>
<mdc-chip-set>
Expand Down Expand Up @@ -129,7 +130,8 @@ <h3 class="demo-content__headline">Action Chips</h3>

<div class="demo-content">
<h3 class="demo-content__headline">Choice with value</h3>
<mdc-chip-set choice #chipSetValue (change)="onChipSetChange($event)" (interaction)="onChipInteraction($event)" [value]="demoChipValue">
<mdc-chip-set choice #chipSetValue (change)="onChipSetChange($event)"
(interaction)="onChipInteraction($event)" [value]="demoChipValue">
<mdc-chip *ngFor="let food of foods" [value]="food.value"
(selectionChange)="onChipSelection($event)">
{{food.viewValue}}
Expand Down Expand Up @@ -242,4 +244,22 @@ <h3 class="demo-content__headline">Custom</h3>
</mdc-chip-set>
</div>
<example-viewer [example]="exampleCustom"></example-viewer>
</div>

<div class="demo-content">
<h3 class="demo-content__headline">Accessibility</h3>
<p>
Material Design spec advises that touch targets should be at least 48 x 48
px. To meet this requirement, add the `touch` property.
</p>
<p>
Note that the outer mdc-touch-target-wrapper element is only necessary if
you want to avoid potentially overlapping touch targets on adjacent elements
(due to collapsing margins). </p>
<div class="demo-layout__row">
<div class="mdc-touch-target-wrapper">
<mdc-chip touch label="My Accessibility Chip"></mdc-chip>
</div>
</div>
<example-viewer [example]="exampleAccessibility"></example-viewer>
</div>
29 changes: 29 additions & 0 deletions demos/src/app/components/chips/routing.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import {NgModule} from '@angular/core';
import {Routes, RouterModule} from '@angular/router';

import {Api, Examples, Sass, Chips} from './chips';

export const ROUTE_DECLARATIONS = [
Api,
Examples,
Sass,
Chips
];

const ROUTES: Routes = [
{
path: '', component: Chips,
children: [
{path: '', redirectTo: 'api'},
{path: 'api', component: Api},
{path: 'sass', component: Sass},
{path: 'examples', component: Examples}
]
}
];

@NgModule({
imports: [RouterModule.forChild(ROUTES)],
exports: [RouterModule]
})
export class RoutingModule {}
20 changes: 16 additions & 4 deletions packages/chips/chip-directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,28 @@ import {
} from '@angular/core';

@Directive({
selector: 'mdc-chip-text, [mdcChipText]',
selector: 'mdc-chip-primary-action, [mdcChipPrimaryAction]',
host: {
'[attr.role]': 'role',
'[attr.tabindex]': 'tabIndex',
'class': 'mdc-chip__text mdc-chip__action--primary'
'class': 'mdc-chip__action--primary'
}
})
export class MdcChipText {
export class MdcChipPrimaryAction {
@Input() role: string | null = 'button';
@Input() tabIndex: number | null = null;

constructor(public elementRef: ElementRef<HTMLElement>) {}
_root!: HTMLElement;

constructor(public elementRef: ElementRef<HTMLElement>) {
this._root = this.elementRef.nativeElement;
}
}

@Directive({
selector: 'mdc-chip-text, [mdcChipText]',
host: {
'class': 'mdc-chip__text'
}
})
export class MdcChipText {}
31 changes: 21 additions & 10 deletions packages/chips/chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ import {
MdcChipRemovalEvent,
MdcChipSelectionEvent
} from './types';
import {MdcChipText} from './chip-directives';
import {MdcChipPrimaryAction, MdcChipText} from './chip-directives';

import {
MDCChipAdapter,
Expand Down Expand Up @@ -88,20 +88,21 @@ export class MdcChipCheckmark {
'role': 'row',
'class': 'mdc-chip',
'[class.mdc-chip--selected]': 'selected',
'[class.mdc-chip--touch]': 'touch',
'(click)': '_handleInteraction($event)',
'(keydown)': '_onKeydown($event)'
},
template: `
<div class="mdc-chip__ripple"></div>
<ng-content select="mdc-chip-icon[leading]"></ng-content>
<mdc-chip-checkmark *ngIf="filter"></mdc-chip-checkmark>
<span role="gridcell" *ngIf="label">
<mdc-chip-text>{{label}}</mdc-chip-text>
</span>
<span role="gridcell">
<ng-content></ng-content>
</span>
`,
<mdc-chip-primary-action>
<div class="mdc-chip__touch" *ngIf="touch"></div>
<mdc-chip-text *ngIf="label">{{label}}</mdc-chip-text>
<ng-content></ng-content>
</mdc-chip-primary-action>
</span>`,
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [MdcRipple]
Expand Down Expand Up @@ -175,6 +176,15 @@ export class MdcChip extends MDCComponent<MDCChipFoundation> implements AfterVie
}
private _removable = true;

@Input()
get touch(): boolean {
return this._touch;
}
set touch(value: boolean) {
this._touch = coerceBooleanProperty(value);
}
private _touch: boolean = false;

/** Whether the chip ripple is disabled. */
@Input()
get disableRipple(): boolean {
Expand Down Expand Up @@ -217,7 +227,8 @@ export class MdcChip extends MDCComponent<MDCChipFoundation> implements AfterVie

@ContentChild(MdcChipCheckmark, {static: false}) _checkmark?: MdcChipCheckmark;
@ContentChildren(forwardRef(() => MdcChipIcon), {descendants: true}) _icons!: QueryList<MdcChipIcon>;
@ViewChild(MdcChipText, {static: true}) _primaryAction!: ElementRef<HTMLElement>;
@ViewChild(MdcChipPrimaryAction, {static: true}) _primaryAction!: MdcChipPrimaryAction;
@ViewChild(MdcChipText, {static: true}) _chipText!: MdcChipText;

getDefaultFoundation() {
const adapter: MDCChipAdapter = {
Expand All @@ -230,7 +241,7 @@ export class MdcChip extends MDCComponent<MDCChipFoundation> implements AfterVie
this.leadingIcon?.elementRef?.nativeElement?.classList?.remove(className),
eventTargetHasClass: (target: EventTarget | null, className: string) =>
(target && (target as Element).classList) ? (target as Element).classList.contains(className) : false,
focusPrimaryAction: () => this._primaryAction?.nativeElement?.focus(),
focusPrimaryAction: () => this._primaryAction._root.focus(),
focusTrailingAction: () => this.trailingIcon?.elementRef?.nativeElement?.focus(),
notifyInteraction: () => this.interactionEvent.emit({
chipId: this._id,
Expand Down Expand Up @@ -267,7 +278,7 @@ export class MdcChip extends MDCComponent<MDCChipFoundation> implements AfterVie
this.trailingIcon?.elementRef?.nativeElement?.setAttribute(attr, value),
hasLeadingIcon: () => !!this.leadingIcon,
hasTrailingAction: () => !!this.trailingIcon,
setPrimaryActionAttr: (attr: string, value: string) => this._elementRef.nativeElement.setAttribute(attr, value),
setPrimaryActionAttr: (attr: string, value: string) => this._primaryAction._root.setAttribute(attr, value),
getRootBoundingClientRect: () => this._root.getBoundingClientRect(),
getCheckmarkBoundingClientRect: () =>
this._checkmark?.elementRef?.nativeElement?.getBoundingClientRect() ?? null,
Expand Down
3 changes: 2 additions & 1 deletion packages/chips/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@ import {CommonModule} from '@angular/common';

import {MdcIconModule} from '@angular-mdc/web/icon';
import {MdcChip, MdcChipIcon, MdcChipCheckmark} from './chip';
import {MdcChipText} from './chip-directives';
import {MdcChipPrimaryAction, MdcChipText} from './chip-directives';
import {MdcChipSet} from './chip-set';

export const CHIP_DECLARATIONS = [
MdcChip,
MdcChipCheckmark,
MdcChipIcon,
MdcChipPrimaryAction,
MdcChipSet,
MdcChipText
];
Expand Down
2 changes: 2 additions & 0 deletions test/chips/chips.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ describe('Chips', () => {
<mdc-chip-set filter>
<mdc-chip
[removable]="removable"
[touch]="touch"
(trailingIconInteraction)="iconInteraction()"
(selectionChange)="chipSelectionChange($event)">
<mdc-chip-icon leading>face</mdc-chip-icon>
Expand All @@ -393,6 +394,7 @@ describe('Chips', () => {
class ChipTest {
removable: boolean = true;
disableRipple: boolean;
touch: boolean;

@ViewChild('trailingIcon', {static: false}) trailingIcon: MdcIcon;

Expand Down