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

Commit

Permalink
feat(chips): Add touch target (#2071)
Browse files Browse the repository at this point in the history
closes #2063
  • Loading branch information
trimox committed Feb 11, 2020
1 parent ea2fe58 commit 8e5f85b
Show file tree
Hide file tree
Showing 12 changed files with 130 additions and 61 deletions.
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

0 comments on commit 8e5f85b

Please sign in to comment.