Skip to content

Commit 4d04472

Browse files
josephperrottandrewseguin
authored andcommitted
chore(accordion): move CdkAccordion to @angular/cdk (#7530)
* Move UniqueSelectionDispatcher to CDK. BREAKING CHANGE: UniqueSelectionDispatcher, UniqueSelectionDispatcherListener and UNIQUE_SELECTION_DISPATCHER_PROVIDER are no longer available from @angular/material and instead must be imported from @angular/cdk/collections * Move UniqueSelectionDispatcher to CDK. BREAKING CHANGE: UniqueSelectionDispatcher, UniqueSelectionDispatcherListener and UNIQUE_SELECTION_DISPATCHER_PROVIDER are no longer available from @angular/material and instead must be imported from @angular/cdk/collections * Move CdkAccordion to @angular/cdk/accordion BREAKING CHANGE: - CdkAccordion is now in @angular/cdk/accordion - AccordionChild is renamed to CdkAccordionChild - CdkAccordion no longer has displayMode and hideToggle @inputs - CdkAccordionItem is now a @directive - CdkAccordion is now exportedAs CdkAccordion for template referencing - CdkAccordionItem is now exported as CdkAccordionItem for template referencing
1 parent 291a87c commit 4d04472

19 files changed

+408
-61
lines changed
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
import {async, TestBed, ComponentFixture} from '@angular/core/testing';
2+
import {Component} from '@angular/core';
3+
import {By} from '@angular/platform-browser';
4+
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
5+
import {CdkAccordionModule, CdkAccordionItem} from './public-api';
6+
7+
describe('CdkAccordionItem', () => {
8+
beforeEach(async(() => {
9+
TestBed.configureTestingModule({
10+
imports: [
11+
BrowserAnimationsModule,
12+
CdkAccordionModule
13+
],
14+
declarations: [
15+
SingleItem,
16+
ItemGroupWithoutAccordion,
17+
ItemGroupWithAccordion
18+
],
19+
});
20+
TestBed.compileComponents();
21+
}));
22+
23+
describe('single item', () => {
24+
let fixture: ComponentFixture<SingleItem>;
25+
let item: CdkAccordionItem;
26+
27+
beforeEach(() => {
28+
fixture = TestBed.createComponent(SingleItem);
29+
item = fixture.debugElement
30+
.query(By.directive(CdkAccordionItem))
31+
.injector.get(CdkAccordionItem);
32+
});
33+
34+
it('should toggle its expanded state', () => {
35+
expect(item.expanded).toBeFalsy();
36+
item.toggle();
37+
expect(item.expanded).toBeTruthy();
38+
item.toggle();
39+
expect(item.expanded).toBeFalsy();
40+
});
41+
42+
it('should set its expanded state to expanded', () => {
43+
item.expanded = false;
44+
item.open();
45+
expect(item.expanded).toBeTruthy();
46+
});
47+
48+
it('should set its expanded state to closed', () => {
49+
item.expanded = true;
50+
item.close();
51+
expect(item.expanded).toBeFalsy();
52+
});
53+
54+
it('should emit a closed event', () => {
55+
spyOn(item.closed, 'emit');
56+
item.close();
57+
fixture.detectChanges();
58+
expect(item.closed.emit).toHaveBeenCalledWith();
59+
});
60+
61+
it('should emit an opened event', () => {
62+
spyOn(item.opened, 'emit');
63+
item.open();
64+
fixture.detectChanges();
65+
expect(item.opened.emit).toHaveBeenCalledWith();
66+
});
67+
68+
it('should emit an destroyed event', () => {
69+
spyOn(item.destroyed, 'emit');
70+
item.ngOnDestroy();
71+
fixture.detectChanges();
72+
expect(item.destroyed.emit).toHaveBeenCalledWith();
73+
});
74+
});
75+
76+
describe('items without accordion', () => {
77+
let fixture: ComponentFixture<SingleItem>;
78+
let firstItem: CdkAccordionItem;
79+
let secondItem: CdkAccordionItem;
80+
81+
beforeEach(() => {
82+
fixture = TestBed.createComponent(ItemGroupWithoutAccordion);
83+
[firstItem, secondItem] = fixture.debugElement
84+
.queryAll(By.directive(CdkAccordionItem))
85+
.map(el => {
86+
return el.injector.get(CdkAccordionItem) as CdkAccordionItem;
87+
});
88+
});
89+
90+
it('should not change expanded state based on unrelated items', () => {
91+
expect(firstItem.expanded).toBeFalsy();
92+
expect(secondItem.expanded).toBeFalsy();
93+
firstItem.open();
94+
fixture.detectChanges();
95+
expect(firstItem.expanded).toBeTruthy();
96+
expect(secondItem.expanded).toBeFalsy();
97+
secondItem.open();
98+
fixture.detectChanges();
99+
expect(firstItem.expanded).toBeTruthy();
100+
expect(secondItem.expanded).toBeTruthy();
101+
});
102+
});
103+
104+
105+
describe('items in accordion', () => {
106+
let fixture: ComponentFixture<SingleItem>;
107+
let firstItem: CdkAccordionItem;
108+
let secondItem: CdkAccordionItem;
109+
110+
beforeEach(() => {
111+
fixture = TestBed.createComponent(ItemGroupWithAccordion);
112+
[firstItem, secondItem] = fixture.debugElement
113+
.queryAll(By.directive(CdkAccordionItem))
114+
.map(el => {
115+
return el.injector.get(CdkAccordionItem) as CdkAccordionItem;
116+
});
117+
});
118+
119+
it('should change expanded state based on related items', () => {
120+
expect(firstItem.expanded).toBeFalsy();
121+
expect(secondItem.expanded).toBeFalsy();
122+
firstItem.open();
123+
fixture.detectChanges();
124+
expect(firstItem.expanded).toBeTruthy();
125+
expect(secondItem.expanded).toBeFalsy();
126+
secondItem.open();
127+
fixture.detectChanges();
128+
expect(firstItem.expanded).toBeFalsy();
129+
expect(secondItem.expanded).toBeTruthy();
130+
});
131+
});
132+
});
133+
134+
@Component({
135+
template: `<cdk-accordion-item #item1></cdk-accordion-item>`
136+
})
137+
class SingleItem {}
138+
139+
@Component({
140+
template: `
141+
<cdk-accordion-item #item1></cdk-accordion-item>
142+
<cdk-accordion-item #item2></cdk-accordion-item>
143+
`
144+
})
145+
class ItemGroupWithoutAccordion {}
146+
147+
@Component({
148+
template: `
149+
<cdk-accordion>
150+
<cdk-accordion-item #item1></cdk-accordion-item>
151+
<cdk-accordion-item #item2></cdk-accordion-item>
152+
</cdk-accordion>
153+
`
154+
})
155+
class ItemGroupWithAccordion {}

src/lib/expansion/accordion-item.ts renamed to src/cdk/accordion/accordion-item.ts

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,28 @@
88

99
import {
1010
Output,
11+
Directive,
1112
EventEmitter,
1213
Input,
13-
Injectable,
1414
OnDestroy,
1515
Optional,
1616
ChangeDetectorRef,
1717
} from '@angular/core';
1818
import {UniqueSelectionDispatcher} from '@angular/cdk/collections';
1919
import {CdkAccordion} from './accordion';
2020

21-
/** Used to generate unique ID for each expansion panel. */
21+
/** Used to generate unique ID for each accordion item. */
2222
let nextId = 0;
2323

2424
/**
25-
* An abstract class to be extended and decorated as a component. Sets up all
25+
* An basic directive expected to be extended and decorated as a component. Sets up all
2626
* events and attributes needed to be managed by a CdkAccordion parent.
2727
*/
28-
@Injectable()
29-
export class AccordionItem implements OnDestroy {
28+
@Directive({
29+
selector: 'cdk-accordion-item',
30+
exportAs: 'cdkAccordionItem',
31+
})
32+
export class CdkAccordionItem implements OnDestroy {
3033
/** Event emitted every time the AccordionItem is closed. */
3134
@Output() closed = new EventEmitter<void>();
3235
/** Event emitted every time the AccordionItem is opened. */
@@ -62,7 +65,7 @@ export class AccordionItem implements OnDestroy {
6265
}
6366
private _expanded: boolean;
6467

65-
/** Unregister function for _expansionDispatcher **/
68+
/** Unregister function for _expansionDispatcher. */
6669
private _removeUniqueSelectionListener: () => void = () => {};
6770

6871
constructor(@Optional() public accordion: CdkAccordion,

src/cdk/accordion/accordion-module.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {NgModule} from '@angular/core';
10+
import {UNIQUE_SELECTION_DISPATCHER_PROVIDER} from '@angular/cdk/collections';
11+
import {CdkAccordion} from './accordion';
12+
import {CdkAccordionItem} from './accordion-item';
13+
14+
@NgModule({
15+
exports: [CdkAccordion, CdkAccordionItem],
16+
declarations: [CdkAccordion, CdkAccordionItem],
17+
providers: [UNIQUE_SELECTION_DISPATCHER_PROVIDER],
18+
})
19+
export class CdkAccordionModule {}

src/cdk/accordion/accordion.spec.ts

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import {async, TestBed} from '@angular/core/testing';
2+
import {Component, ViewChild} from '@angular/core';
3+
import {By} from '@angular/platform-browser';
4+
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
5+
import {CdkAccordionModule, CdkAccordionItem} from './public-api';
6+
7+
describe('CdkAccordion', () => {
8+
beforeEach(async(() => {
9+
TestBed.configureTestingModule({
10+
imports: [
11+
BrowserAnimationsModule,
12+
CdkAccordionModule
13+
],
14+
declarations: [
15+
SetOfItems
16+
],
17+
});
18+
TestBed.compileComponents();
19+
}));
20+
21+
it('should ensure only one item is expanded at a time', () => {
22+
const fixture = TestBed.createComponent(SetOfItems);
23+
const [firstPanel, secondPanel] = fixture.debugElement
24+
.queryAll(By.directive(CdkAccordionItem))
25+
.map(el => {
26+
return el.injector.get(CdkAccordionItem) as CdkAccordionItem;
27+
});
28+
29+
firstPanel.open();
30+
fixture.detectChanges();
31+
expect(firstPanel.expanded).toBeTruthy();
32+
expect(secondPanel.expanded).toBeFalsy();
33+
34+
secondPanel.open();
35+
fixture.detectChanges();
36+
expect(firstPanel.expanded).toBeFalsy();
37+
expect(secondPanel.expanded).toBeTruthy();
38+
});
39+
40+
it('should allow multiple items to be expanded simultaneously', () => {
41+
const fixture = TestBed.createComponent(SetOfItems);
42+
const [firstPanel, secondPanel] = fixture.debugElement
43+
.queryAll(By.directive(CdkAccordionItem))
44+
.map(el => {
45+
return el.injector.get(CdkAccordionItem) as CdkAccordionItem;
46+
});
47+
48+
fixture.componentInstance.multi = true;
49+
fixture.detectChanges();
50+
firstPanel.expanded = true;
51+
secondPanel.expanded = true;
52+
fixture.detectChanges();
53+
expect(firstPanel.expanded).toBeTruthy();
54+
expect(secondPanel.expanded).toBeTruthy();
55+
});
56+
});
57+
58+
@Component({template: `
59+
<cdk-accordion [multi]="multi">
60+
<cdk-accordion-item #item1></cdk-accordion-item>
61+
<cdk-accordion-item #item2></cdk-accordion-item>
62+
</cdk-accordion>`})
63+
class SetOfItems {
64+
@ViewChild('item1') item1;
65+
@ViewChild('item2') item2;
66+
multi: boolean = false;
67+
}

src/cdk/accordion/accordion.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Directive, Input} from '@angular/core';
10+
import {coerceBooleanProperty} from '@angular/cdk/coercion';
11+
12+
/** Used to generate unique ID for each accordion. */
13+
let nextId = 0;
14+
15+
/**
16+
* Directive whose purpose is to manage the expanded state of CdkAccordionItem children.
17+
*/
18+
@Directive({
19+
selector: 'cdk-accordion, [cdk-accordion]',
20+
exportAs: 'cdkAccordion',
21+
})
22+
export class CdkAccordion {
23+
/** A readonly id value to use for unique selection coordination. */
24+
readonly id = `cdk-accordion-${nextId++}`;
25+
26+
/** Whether the accordion should allow multiple expanded accordion items simulateously. */
27+
@Input() get multi(): boolean { return this._multi; }
28+
set multi(multi: boolean) { this._multi = coerceBooleanProperty(multi); }
29+
private _multi: boolean = false;
30+
}

src/cdk/accordion/index.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export * from './public-api';

src/cdk/accordion/public-api.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export {CdkAccordionItem} from './accordion-item';
10+
export {CdkAccordion} from './accordion';
11+
export * from './accordion-module';

src/cdk/accordion/tsconfig-build.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"extends": "../tsconfig-build",
3+
"files": [
4+
"public-api.ts"
5+
],
6+
"angularCompilerOptions": {
7+
"annotateForClosureCompiler": true,
8+
"strictMetadataEmit": true,
9+
"flatModuleOutFile": "index.js",
10+
"flatModuleId": "@angular/cdk/accordion",
11+
"skipTemplateCodegen": true
12+
}
13+
}

src/cdk/accordion/tsconfig-es5.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"extends": "../tsconfig-es5",
3+
"files": [
4+
"public-api.ts"
5+
],
6+
"angularCompilerOptions": {
7+
"annotateForClosureCompiler": true,
8+
"strictMetadataEmit": true,
9+
"flatModuleOutFile": "index.js",
10+
"flatModuleId": "@angular/cdk/accordion",
11+
"skipTemplateCodegen": true
12+
}
13+
}

src/demo-app/demo-material-module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import {
3333
} from '@angular/material';
3434
import {MatNativeDateModule, MatRippleModule} from '@angular/material';
3535
import {CdkTableModule} from '@angular/cdk/table';
36+
import {CdkAccordionModule} from '@angular/cdk/accordion';
3637
import {A11yModule} from '@angular/cdk/a11y';
3738
import {BidiModule} from '@angular/cdk/bidi';
3839
import {OverlayModule} from '@angular/cdk/overlay';
@@ -80,6 +81,7 @@ import {PortalModule} from '@angular/cdk/portal';
8081
CdkTableModule,
8182
A11yModule,
8283
BidiModule,
84+
CdkAccordionModule,
8385
ObserversModule,
8486
OverlayModule,
8587
PlatformModule,

0 commit comments

Comments
 (0)