Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(expansion-panel): add the ability to disable an expansion panel #6529

Merged
merged 1 commit into from
Aug 22, 2017
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
5 changes: 3 additions & 2 deletions src/demo-app/expansion/expansion-demo.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ <h1>Accordion</h1>
<div>
<md-slide-toggle [(ngModel)]="multi">Allow Multi Expansion</md-slide-toggle>
<md-slide-toggle [(ngModel)]="hideToggle">Hide Indicators</md-slide-toggle>
<md-slide-toggle [(ngModel)]="disabled">Disable Panel 2</md-slide-toggle>
<md-slide-toggle [(ngModel)]="showPanel3">Show Panel 3</md-slide-toggle>
</div>
<p>Accordion Style</p>
Expand All @@ -37,7 +38,7 @@ <h1>Accordion</h1>
<md-expansion-panel-header>Section 1</md-expansion-panel-header>
<p>This is the content text that makes sense here.</p>
</md-expansion-panel>
<md-expansion-panel #panel2 [hideToggle]="hideToggle">
<md-expansion-panel #panel2 [hideToggle]="hideToggle" [disabled]="disabled">
<md-expansion-panel-header>Section 2</md-expansion-panel-header>
<p>This is the content text that makes sense here.</p>
</md-expansion-panel>
Expand All @@ -49,4 +50,4 @@ <h1>Accordion</h1>
<button md-button (click)="panel3.expanded = false">CLOSE</button>
</md-action-row>
</md-expansion-panel>
</md-accordion>
</md-accordion>
5 changes: 3 additions & 2 deletions src/demo-app/expansion/expansion-demo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ import {Component, ViewEncapsulation} from '@angular/core';
})
export class ExpansionDemo {
displayMode: string = 'default';
multi: boolean = false;
hideToggle: boolean = false;
multi = false;
hideToggle = false;
disabled = false;
showPanel3 = true;
}
11 changes: 10 additions & 1 deletion src/lib/expansion/_expansion-theme.scss
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
border-top-color: mat-color($foreground, divider);
}

.mat-expansion-panel-header {
.mat-expansion-panel-header:not([aria-disabled='true']) {
&.cdk-keyboard-focused,
&.cdk-program-focused,
&:hover {
Expand All @@ -31,6 +31,15 @@
.mat-expansion-indicator::after {
color: mat-color($foreground, secondary-text);
}

.mat-expansion-panel-header[aria-disabled='true'] {
color: mat-color($foreground, disabled-button);

.mat-expansion-panel-header-title,
.mat-expansion-panel-header-description {
color: inherit;
}
}
}

@mixin mat-expansion-panel-typography($config) {
Expand Down
11 changes: 10 additions & 1 deletion src/lib/expansion/accordion-item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,16 +17,22 @@ import {
} from '@angular/core';
import {UniqueSelectionDispatcher} from '../core';
import {CdkAccordion} from './accordion';
import {mixinDisabled, CanDisable} from '../core/common-behaviors/disabled';

/** Used to generate unique ID for each expansion panel. */
let nextId = 0;

// Boilerplate for applying mixins to MdSlider.
/** @docs-private */
export class AccordionItemBase { }
export const _AccordionItemMixinBase = mixinDisabled(AccordionItemBase);

/**
* An abstract class to be extended and decorated as a component. Sets up all
* events and attributes needed to be managed by a CdkAccordion parent.
*/
@Injectable()
export class AccordionItem implements OnDestroy {
export class AccordionItem extends _AccordionItemMixinBase implements OnDestroy, CanDisable {
/** Event emitted every time the MdAccordionChild is closed. */
@Output() closed = new EventEmitter<void>();
/** Event emitted every time the MdAccordionChild is opened. */
Expand Down Expand Up @@ -68,6 +74,9 @@ export class AccordionItem implements OnDestroy {
constructor(@Optional() public accordion: CdkAccordion,
private _changeDetectorRef: ChangeDetectorRef,
protected _expansionDispatcher: UniqueSelectionDispatcher) {

super();

this._removeUniqueSelectionListener =
_expansionDispatcher.listen((id: string, accordionId: string) => {
if (this.accordion && !this.accordion.multi &&
Expand Down
2 changes: 1 addition & 1 deletion src/lib/expansion/expansion-panel-header.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
<ng-content select="md-panel-description, mat-panel-description"></ng-content>
<ng-content></ng-content>
</span>
<span [@indicatorRotate]="_getExpandedState()" *ngIf="!_getHideToggle()"
<span [@indicatorRotate]="_getExpandedState()" *ngIf="_showToggle()"
class="mat-expansion-indicator"></span>
5 changes: 4 additions & 1 deletion src/lib/expansion/expansion-panel-header.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

.mat-expansion-panel-header {
cursor: pointer;
display: flex;
flex-direction: row;
align-items: center;
Expand All @@ -15,6 +14,10 @@
&.mat-expanded:hover, {
background: inherit;
}

&:not([aria-disabled='true']) {
cursor: pointer;
}
}

.mat-content {
Expand Down
15 changes: 9 additions & 6 deletions src/lib/expansion/expansion-panel-header.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ import {Subscription} from 'rxjs/Subscription';
host: {
'class': 'mat-expansion-panel-header',
'role': 'button',
'tabindex': '0',
'[attr.tabindex]': 'panel.disabled ? -1 : 0',
'[attr.aria-controls]': '_getPanelId()',
'[attr.aria-expanded]': '_isExpanded()',
'[attr.aria-disabled]': 'panel.disabled',
'[class.mat-expanded]': '_isExpanded()',
'(click)': '_toggle()',
'(keyup)': '_keyup($event)',
Expand Down Expand Up @@ -85,7 +86,7 @@ export class MdExpansionPanelHeader implements OnDestroy {
this._parentChangeSubscription = merge(
panel.opened,
panel.closed,
filter.call(panel._inputChanges, changes => !!changes.hideToggle)
filter.call(panel._inputChanges, changes => !!(changes.hideToggle || changes.disabled))
)
.subscribe(() => this._changeDetectorRef.markForCheck());

Expand All @@ -94,7 +95,9 @@ export class MdExpansionPanelHeader implements OnDestroy {

/** Toggles the expanded state of the panel. */
_toggle(): void {
this.panel.toggle();
if (!this.panel.disabled) {
this.panel.toggle();
}
}

/** Gets whether the panel is expanded. */
Expand All @@ -112,9 +115,9 @@ export class MdExpansionPanelHeader implements OnDestroy {
return this.panel.id;
}

/** Gets whether the expand indicator is hidden. */
_getHideToggle(): boolean {
return this.panel.hideToggle;
/** Gets whether the expand indicator should be shown. */
_showToggle(): boolean {
return !this.panel.hideToggle && !this.panel.disabled;
}

/** Handle keyup event calling to toggle() if appropriate. */
Expand Down
1 change: 1 addition & 0 deletions src/lib/expansion/expansion-panel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ export const EXPANSION_PANEL_ANIMATION_TIMING = '225ms cubic-bezier(0.4,0.0,0.2,
templateUrl: './expansion-panel.html',
encapsulation: ViewEncapsulation.None,
changeDetection: ChangeDetectionStrategy.OnPush,
inputs: ['disabled'],
host: {
'class': 'mat-expansion-panel',
'[class.mat-expanded]': 'expanded',
Expand Down
35 changes: 26 additions & 9 deletions src/lib/expansion/expansion.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ as the control for expanding and collapsing. This header may optionally contain
header to align with Material Design specifications.

By default, the expansion-panel header includes a toggle icon at the end of the
header to indicate the expansion state. This icon can be hidden via the
header to indicate the expansion state. This icon can be hidden via the
`hideToggle` property.

```html
Expand All @@ -35,8 +35,8 @@ header to indicate the expansion state. This icon can be hidden via the

#### Action bar

Actions may optionally be included at the bottom of the panel, visible only when the expansion is in its
expanded state.
Actions may optionally be included at the bottom of the panel, visible only when the expansion
is in its expanded state.

```html
<md-expansion-panel>
Expand All @@ -52,6 +52,23 @@ expanded state.
</md-expansion-panel>
```

#### Disabling a panel

Expansion panels can be disabled using the `disabled` attribute. A disabled expansion panel can't
be toggled by the user, but can still be manipulated using programmatically.

```html
<md-expansion-panel [disabled]="isDisabled">
<md-expansion-panel-header>
This is the expansion title
</md-expansion-panel-header>
<md-panel-description>
This is a summary of the content
</md-panel-description>
</md-expansion-panel>
```


### Accordion

Multiple expansion-panels can be combined into an accordion. The `multi="true"` input allows the
Expand All @@ -60,23 +77,23 @@ panel can be expanded at a given time:

```html
<md-accordion>

<md-expansion-panel>
<md-expansion-panel-header>
This is the expansion 1 title
</md-expansion-panel-header>

This the expansion 1 content

</md-expansion-panel>

<md-expansion-panel>
<md-expansion-panel-header>
This is the expansion 2 title
</md-expansion-panel-header>

This the expansion 2 content

</md-expansion-panel>

</md-accordion>
Expand Down
73 changes: 68 additions & 5 deletions src/lib/expansion/expansion.spec.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {async, TestBed, fakeAsync, tick} from '@angular/core/testing';
import {Component} from '@angular/core';
import {async, TestBed, fakeAsync, tick, ComponentFixture} from '@angular/core/testing';
import {Component, ViewChild} from '@angular/core';
import {By} from '@angular/platform-browser';
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
import {MdExpansionModule} from './index';
import {MdExpansionModule, MdExpansionPanel} from './index';


describe('MdExpansionPanel', () => {
Expand Down Expand Up @@ -137,13 +137,74 @@ describe('MdExpansionPanel', () => {

expect(arrow.style.transform).toBe('rotate(180deg)', 'Expected 180 degree rotation.');
}));

describe('disabled state', () => {
let fixture: ComponentFixture<PanelWithContent>;
let panel: HTMLElement;
let header: HTMLElement;

beforeEach(() => {
fixture = TestBed.createComponent(PanelWithContent);
fixture.detectChanges();
panel = fixture.debugElement.query(By.css('md-expansion-panel')).nativeElement;
header = fixture.debugElement.query(By.css('md-expansion-panel-header')).nativeElement;
});

it('should toggle the aria-disabled attribute on the header', () => {
expect(header.getAttribute('aria-disabled')).toBe('false');

fixture.componentInstance.disabled = true;
fixture.detectChanges();

expect(header.getAttribute('aria-disabled')).toBe('true');
});

it('should toggle the expansion indicator', () => {
expect(panel.querySelector('.mat-expansion-indicator')).toBeTruthy();

fixture.componentInstance.disabled = true;
fixture.detectChanges();

expect(panel.querySelector('.mat-expansion-indicator')).toBeFalsy();
});

it('should not be able to toggle the panel via a user action if disabled', () => {
expect(fixture.componentInstance.panel.expanded).toBe(false);
expect(header.classList).not.toContain('mat-expanded');

fixture.componentInstance.disabled = true;
fixture.detectChanges();

header.click();
fixture.detectChanges();

expect(fixture.componentInstance.panel.expanded).toBe(false);
expect(header.classList).not.toContain('mat-expanded');
});

it('should be able to toggle a disabled expansion panel programmatically', () => {
expect(fixture.componentInstance.panel.expanded).toBe(false);
expect(header.classList).not.toContain('mat-expanded');

fixture.componentInstance.disabled = true;
fixture.detectChanges();

fixture.componentInstance.expanded = true;
fixture.detectChanges();

expect(fixture.componentInstance.panel.expanded).toBe(true);
expect(header.classList).toContain('mat-expanded');
});

});
});


@Component({
template: `
<md-expansion-panel [expanded]="expanded"
[hideToggle]="hideToggle"
[disabled]="disabled"
(opened)="openCallback()"
(closed)="closeCallback()">
<md-expansion-panel-header>Panel Title</md-expansion-panel-header>
Expand All @@ -152,10 +213,12 @@ describe('MdExpansionPanel', () => {
</md-expansion-panel>`
})
class PanelWithContent {
expanded: boolean = false;
hideToggle: boolean = false;
expanded = false;
hideToggle = false;
disabled = false;
openCallback = jasmine.createSpy('openCallback');
closeCallback = jasmine.createSpy('closeCallback');
@ViewChild(MdExpansionPanel) panel: MdExpansionPanel;
}


Expand Down