Skip to content

Commit

Permalink
feat(expansion): allow expansion toggle indicator positioning
Browse files Browse the repository at this point in the history
  • Loading branch information
josephperrott committed Jun 10, 2019
1 parent c1e07ad commit 85e0aad
Show file tree
Hide file tree
Showing 9 changed files with 106 additions and 15 deletions.
8 changes: 7 additions & 1 deletion src/dev-app/expansion/expansion-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ <h1>matAccordion</h1>
<mat-radio-button value="default">Default</mat-radio-button>
<mat-radio-button value="flat">Flat</mat-radio-button>
</mat-radio-group>

<p>Toggle Position</p>
<mat-radio-group [(ngModel)]="togglePosition">
<mat-radio-button value="before">Before</mat-radio-button>
<mat-radio-button value="after">After</mat-radio-button>
</mat-radio-group>
<p>Accordion Actions <sup>('Multi Expansion' mode only)</sup></p>
<div>
<button mat-button (click)="accordion.openAll()" [disabled]="!multi">Expand All</button>
Expand All @@ -63,7 +69,7 @@ <h1>matAccordion</h1>
</div>
<br>
<mat-accordion [displayMode]="displayMode" [multi]="multi" [hideToggle]="hideToggle"
class="demo-expansion-width">
[togglePosition]="togglePosition" class="demo-expansion-width">
<mat-expansion-panel #panel1>
<mat-expansion-panel-header>Section 1</mat-expansion-panel-header>
<p>This is the content text that makes sense here.</p>
Expand Down
1 change: 1 addition & 0 deletions src/dev-app/expansion/expansion-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class ExpansionDemo {
hideToggle = false;
disabled = false;
showPanel3 = true;
togglePosition = 'after';
expandedHeight: string;
collapsedHeight: string;
events: string[] = [];
Expand Down
6 changes: 6 additions & 0 deletions src/material/expansion/accordion-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ import {CdkAccordion} from '@angular/cdk/accordion';
/** MatAccordion's display modes. */
export type MatAccordionDisplayMode = 'default' | 'flat';

/** MatAccordion's toggle positions. */
export type MatAccordionTogglePosition = 'before' | 'after';

/**
* Base interface for a `MatAccordion`.
* @docs-private
Expand All @@ -23,6 +26,9 @@ export interface MatAccordionBase extends CdkAccordion {
/** Display mode used for all expansion panels in the accordion. */
displayMode: MatAccordionDisplayMode;

/** The position of the expansion indicator. */
togglePosition: MatAccordionTogglePosition;

/** Handles keyboard events coming in from the panel headers. */
_handleHeaderKeydown: (event: KeyboardEvent) => void;

Expand Down
30 changes: 30 additions & 0 deletions src/material/expansion/accordion.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ describe('MatAccordion', () => {
],
declarations: [
AccordionWithHideToggle,
AccordionWithTogglePosition,
NestedPanel,
SetOfItems,
],
Expand Down Expand Up @@ -137,6 +138,22 @@ describe('MatAccordion', () => {
.toBeFalsy('Expected the expansion indicator to be removed.');
});

it('should update the expansion panel if togglePosition changed', () => {
const fixture = TestBed.createComponent(AccordionWithTogglePosition);
const panel = fixture.debugElement.query(By.directive(MatExpansionPanel));

fixture.detectChanges();

expect(panel.nativeElement.querySelector('.mat-expansion-toggle-indicator-after'))
.toBeTruthy('Expected the expansion indicator to be positioned after.');

fixture.componentInstance.togglePosition = 'before';
fixture.detectChanges();

expect(panel.nativeElement.querySelector('.mat-expansion-toggle-indicator-before'))
.toBeTruthy('Expected the expansion indicator to be positioned before.');
});

it('should move focus to the next header when pressing the down arrow', () => {
const fixture = TestBed.createComponent(SetOfItems);
fixture.detectChanges();
Expand Down Expand Up @@ -307,3 +324,16 @@ class NestedPanel {
class AccordionWithHideToggle {
hideToggle = false;
}


@Component({template: `
<mat-accordion [togglePosition]="togglePosition">
<mat-expansion-panel>
<mat-expansion-panel-header>Header</mat-expansion-panel-header>
<p>Content</p>
</mat-expansion-panel>
</mat-accordion>`
})
class AccordionWithTogglePosition {
togglePosition = 'after';
}
10 changes: 9 additions & 1 deletion src/material/expansion/accordion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {CdkAccordion} from '@angular/cdk/accordion';
import {FocusKeyManager} from '@angular/cdk/a11y';
import {HOME, END, hasModifierKey} from '@angular/cdk/keycodes';
import {MAT_ACCORDION, MatAccordionBase, MatAccordionDisplayMode} from './accordion-base';
import {
MAT_ACCORDION,
MatAccordionBase,
MatAccordionDisplayMode,
MatAccordionTogglePosition
} from './accordion-base';
import {MatExpansionPanelHeader} from './expansion-panel-header';

/**
Expand Down Expand Up @@ -51,6 +56,9 @@ export class MatAccordion extends CdkAccordion implements MatAccordionBase, Afte
*/
@Input() displayMode: MatAccordionDisplayMode = 'default';

/** The position of the expansion indicator. */
@Input() togglePosition: MatAccordionTogglePosition = 'after';

ngAfterContentInit() {
this._keyManager = new FocusKeyManager(this._headers).withWrap();
}
Expand Down
28 changes: 20 additions & 8 deletions src/material/expansion/expansion-panel-header.scss
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,14 @@
&:not([aria-disabled='true']) {
cursor: pointer;
}

&.mat-expansion-toggle-indicator-before {
flex-direction: row-reverse;

.mat-expansion-indicator {
padding: 0 16px 0 0;
}
}
}

.mat-content {
Expand Down Expand Up @@ -47,12 +55,16 @@
* Creates the expansion indicator arrow. Done using ::after rather than having
* additional nodes in the template.
*/
.mat-expansion-indicator::after {
border-style: solid;
border-width: 0 2px 2px 0;
content: '';
display: inline-block;
padding: 3px;
transform: rotate(45deg);
vertical-align: middle;
.mat-expansion-indicator {
padding: 0 0 0 16px;

&::after {
border-style: solid;
border-width: 0 2px 2px 0;
content: '';
display: inline-block;
padding: 3px;
transform: rotate(45deg);
vertical-align: middle;
}
}
17 changes: 15 additions & 2 deletions src/material/expansion/expansion-panel-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
MatExpansionPanelDefaultOptions,
MAT_EXPANSION_PANEL_DEFAULT_OPTIONS,
} from './expansion-panel';
import {MatAccordionTogglePosition} from './accordion-base';


/**
Expand Down Expand Up @@ -56,6 +57,8 @@ import {
'[attr.aria-expanded]': '_isExpanded()',
'[attr.aria-disabled]': 'panel.disabled',
'[class.mat-expanded]': '_isExpanded()',
'[class.mat-expansion-toggle-indicator-after]': `_getTogglePosition() === 'after'`,
'[class.mat-expansion-toggle-indicator-before]': `_getTogglePosition() === 'before'`,
'(click)': '_toggle()',
'(keydown)': '_keydown($event)',
'[@expansionHeight]': `{
Expand All @@ -79,7 +82,7 @@ export class MatExpansionPanelHeader implements OnDestroy, FocusableOption {
defaultOptions?: MatExpansionPanelDefaultOptions) {
const accordionHideToggleChange = panel.accordion ?
panel.accordion._stateChanges.pipe(
filter(changes => !!changes['hideToggle'])) :
filter(changes => !!(changes['hideToggle'] || changes['togglePosition']))) :
EMPTY;

// Since the toggle state depends on an @Input on the panel, we
Expand All @@ -88,7 +91,12 @@ export class MatExpansionPanelHeader implements OnDestroy, FocusableOption {
merge(
panel.opened, panel.closed, accordionHideToggleChange,
panel._inputChanges.pipe(filter(
changes => !!(changes['hideToggle'] || changes['disabled']))))
changes => {
return !!(
changes['hideToggle'] ||
changes['disabled'] ||
changes['togglePosition']);
})))
.subscribe(() => this._changeDetectorRef.markForCheck());

// Avoids focus being lost if the panel contained the focused element and was closed.
Expand Down Expand Up @@ -142,6 +150,11 @@ export class MatExpansionPanelHeader implements OnDestroy, FocusableOption {
return this.panel.id;
}

/** Gets the toggle position for the header. */
_getTogglePosition(): MatAccordionTogglePosition {
return this.panel.togglePosition;
}

/** Gets whether the expand indicator should be shown. */
_showToggle(): boolean {
return !this.panel.hideToggle && !this.panel.disabled;
Expand Down
15 changes: 12 additions & 3 deletions src/material/expansion/expansion-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import {Subject} from 'rxjs';
import {filter, startWith, take, distinctUntilChanged} from 'rxjs/operators';
import {matExpansionAnimations} from './expansion-animations';
import {MatExpansionPanelContent} from './expansion-panel-content';
import {MAT_ACCORDION, MatAccordionBase} from './accordion-base';
import {MAT_ACCORDION, MatAccordionBase, MatAccordionTogglePosition} from './accordion-base';

/** MatExpansionPanel's states. */
export type MatExpansionPanelState = 'expanded' | 'collapsed';
Expand Down Expand Up @@ -100,8 +100,9 @@ export const MAT_EXPANSION_PANEL_DEFAULT_OPTIONS =
})
export class MatExpansionPanel extends CdkAccordionItem implements AfterContentInit, OnChanges,
OnDestroy {

private _document: Document;
private _hideToggle = false;
private _togglePosition: MatAccordionTogglePosition;

/** Whether the toggle indicator should be hidden. */
@Input()
Expand All @@ -111,7 +112,15 @@ export class MatExpansionPanel extends CdkAccordionItem implements AfterContentI
set hideToggle(value: boolean) {
this._hideToggle = coerceBooleanProperty(value);
}
private _hideToggle = false;

/** Whether the toggle indicator should be hidden. */
@Input()
get togglePosition(): MatAccordionTogglePosition {
return this._togglePosition || (this.accordion && this.accordion.togglePosition);
}
set togglePosition(value: MatAccordionTogglePosition) {
this._togglePosition = value;
}

/** An event emitted after the body's expansion animation happens. */
@Output() afterExpand = new EventEmitter<void>();
Expand Down
6 changes: 6 additions & 0 deletions tools/public_api_guard/material/expansion.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export declare class MatAccordion extends CdkAccordion implements MatAccordionBa
_headers: QueryList<MatExpansionPanelHeader>;
displayMode: MatAccordionDisplayMode;
hideToggle: boolean;
togglePosition: MatAccordionTogglePosition;
_handleHeaderFocus(header: MatExpansionPanelHeader): void;
_handleHeaderKeydown(event: KeyboardEvent): void;
ngAfterContentInit(): void;
Expand All @@ -18,10 +19,13 @@ export interface MatAccordionBase extends CdkAccordion {
_handleHeaderKeydown: (event: KeyboardEvent) => void;
displayMode: MatAccordionDisplayMode;
hideToggle: boolean;
togglePosition: MatAccordionTogglePosition;
}

export declare type MatAccordionDisplayMode = 'default' | 'flat';

export declare type MatAccordionTogglePosition = 'before' | 'after';

export declare const matExpansionAnimations: {
readonly indicatorRotate: AnimationTriggerMetadata;
readonly expansionHeaderHeight: AnimationTriggerMetadata;
Expand All @@ -43,6 +47,7 @@ export declare class MatExpansionPanel extends CdkAccordionItem implements After
afterCollapse: EventEmitter<void>;
afterExpand: EventEmitter<void>;
hideToggle: boolean;
togglePosition: MatAccordionTogglePosition;
constructor(accordion: MatAccordionBase, _changeDetectorRef: ChangeDetectorRef, _uniqueSelectionDispatcher: UniqueSelectionDispatcher, _viewContainerRef: ViewContainerRef, _document: any, _animationMode: string, defaultOptions?: MatExpansionPanelDefaultOptions);
_containsFocus(): boolean;
_getExpandedState(): MatExpansionPanelState;
Expand Down Expand Up @@ -77,6 +82,7 @@ export declare class MatExpansionPanelHeader implements OnDestroy, FocusableOpti
constructor(panel: MatExpansionPanel, _element: ElementRef, _focusMonitor: FocusMonitor, _changeDetectorRef: ChangeDetectorRef, defaultOptions?: MatExpansionPanelDefaultOptions);
_getExpandedState(): string;
_getPanelId(): string;
_getTogglePosition(): MatAccordionTogglePosition;
_isExpanded(): boolean;
_keydown(event: KeyboardEvent): void;
_showToggle(): boolean;
Expand Down

0 comments on commit 85e0aad

Please sign in to comment.