Skip to content

Commit ca05d1b

Browse files
committed
feat(accordion): cria o componente
Cria o novo componente `po-accordion`, para o usuário poder agrupar visualmente uma lista de conteúdos, mostrando-os individualmente ao clicar no título de cada item. Fixes DTHFUI-798
1 parent 13587a4 commit ca05d1b

26 files changed

+941
-0
lines changed

projects/ui/src/lib/components/components.module.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { NgModule } from '@angular/core';
22

3+
import { PoAccordionModule } from './po-accordion/po-accordion.module';
34
import { PoAvatarModule } from './po-avatar/po-avatar.module';
45
import { PoBreadcrumbModule } from './po-breadcrumb/po-breadcrumb.module';
56
import { PoButtonModule } from './po-button/po-button.module';
@@ -36,6 +37,7 @@ import { PoWidgetModule } from './po-widget/po-widget.module';
3637
@NgModule({
3738
declarations: [],
3839
imports: [
40+
PoAccordionModule,
3941
PoAvatarModule,
4042
PoBreadcrumbModule,
4143
PoButtonModule,
@@ -70,6 +72,7 @@ import { PoWidgetModule } from './po-widget/po-widget.module';
7072
PoWidgetModule
7173
],
7274
exports: [
75+
PoAccordionModule,
7376
PoAvatarModule,
7477
PoBreadcrumbModule,
7578
PoButtonModule,

projects/ui/src/lib/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
export * from './components.module';
22

3+
export * from './po-accordion/index';
34
export * from './po-avatar/index';
45
export * from './po-breadcrumb/index';
56
export * from './po-button-group/index';
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
export * from './po-accordion-item/po-accordion-item.component';
2+
export * from './po-accordion.component';
3+
4+
export * from './po-accordion.module';
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { PoAccordionBaseComponent } from './po-accordion-base.component';
2+
3+
describe('PoAccordionBaseComponent:', () => {
4+
const component = new PoAccordionBaseComponent();
5+
6+
it('should be created', () => {
7+
expect(component instanceof PoAccordionBaseComponent).toBeTruthy();
8+
});
9+
10+
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @description
3+
*
4+
* Componente utilizado para agrupar visualmente uma lista de conteúdos, mostrando-os individualmente
5+
* ao clicar no título de cada item.
6+
*
7+
* Para utilizá-lo, é necessário envolver cada item no componente [`po-accordion-item`](/documentation/po-accordion-item),
8+
* como no exemplo abaixo:
9+
*
10+
* ```
11+
* <po-accordion>
12+
* <po-accordion-item p-label="Portinari Accordion 1">
13+
* Accordion 1
14+
* </po-accordion-item>
15+
*
16+
* <po-accordion-item p-label="Portinari Accordion 2">
17+
* Accordion 2
18+
* </po-accordion-item>
19+
* </po-accordion>
20+
* ```
21+
*
22+
* O componente já faz o controle de abertura e fechamento dos itens automaticamente.
23+
*
24+
* Caso houver a necessidade de abrir algum dos `po-accordion-item` via Typescript
25+
* acesse a [documentamentação do PoAccordionItem](/documentation/po-accordion-item).
26+
*/
27+
export class PoAccordionBaseComponent {}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<div class="po-accordion-item-body" *ngIf="expanded" @toggleBody>
2+
<div class="po-accordion-item-body-content">
3+
<ng-content></ng-content>
4+
</div>
5+
</div>
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
2+
3+
import { ComponentFixture, TestBed } from '@angular/core/testing';
4+
5+
import { configureTestSuite } from './../../../util-test/util-expect.spec';
6+
7+
import { PoAccordionItemBodyComponent } from './po-accordion-item-body.component';
8+
9+
describe('PoAccordionItemBodyComponent:', () => {
10+
let component: PoAccordionItemBodyComponent;
11+
let fixture: ComponentFixture<PoAccordionItemBodyComponent>;
12+
13+
let nativeElement: any;
14+
15+
configureTestSuite(() => {
16+
TestBed.configureTestingModule({
17+
declarations: [ PoAccordionItemBodyComponent ],
18+
imports: [ BrowserAnimationsModule ]
19+
});
20+
});
21+
22+
beforeEach(() => {
23+
fixture = TestBed.createComponent(PoAccordionItemBodyComponent);
24+
component = fixture.componentInstance;
25+
26+
nativeElement = fixture.debugElement.nativeElement;
27+
});
28+
29+
it('should be created', () => {
30+
expect(component instanceof PoAccordionItemBodyComponent).toBeTruthy();
31+
});
32+
33+
describe('Templates:', () => {
34+
it('shouldn`t have `po-accordion-item-body` by default', () => {
35+
36+
fixture.detectChanges();
37+
38+
const body = nativeElement.querySelector('.po-accordion-item-body');
39+
expect(body).toBeFalsy();
40+
});
41+
42+
it('should have `po-accordion-item-body` class if `expanded` is `true`', () => {
43+
component.expanded = true;
44+
45+
fixture.detectChanges();
46+
47+
const body = nativeElement.querySelector('.po-accordion-item-body');
48+
expect(body).toBeTruthy();
49+
});
50+
51+
it('shouldn`t have `po-accordion-item-body` class if `expanded` is `false`', () => {
52+
component.expanded = false;
53+
54+
fixture.detectChanges();
55+
56+
const body = nativeElement.querySelector('.po-accordion-item-body');
57+
expect(body).toBeFalsy();
58+
});
59+
});
60+
61+
});
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { Component, Input } from '@angular/core';
2+
import { animate, style, transition, trigger } from '@angular/animations';
3+
4+
@Component({
5+
selector: 'po-accordion-item-body',
6+
templateUrl: 'po-accordion-item-body.component.html',
7+
animations: [
8+
trigger('toggleBody', [
9+
transition('* => void', [
10+
style({ height: '*'}),
11+
animate(200, style({ height: 0 }))
12+
]),
13+
transition('void => *', [
14+
style({ height: '0'}),
15+
animate(200, style({ height: '*' }))
16+
])
17+
])
18+
]
19+
})
20+
export class PoAccordionItemBodyComponent {
21+
22+
@Input('p-expanded') expanded: boolean = false;
23+
24+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<header class="po-accordion-item-header">
2+
<button class="po-accordion-item-header-button po-clickable" (click)="onClick()">
3+
<div class="po-text-ellipsis po-accordion-item-header-title">{{ label }}</div>
4+
<span #icon class="po-icon po-accordion-item-header-icon po-icon-arrow-down">
5+
</span>
6+
</button>
7+
</header>
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { configureTestSuite } from './../../../util-test/util-expect.spec';
4+
5+
import { PoAccordionItemHeaderComponent } from './po-accordion-item-header.component';
6+
7+
describe('PoAccordionItemHeaderComponent:', () => {
8+
let component: PoAccordionItemHeaderComponent;
9+
let fixture: ComponentFixture<PoAccordionItemHeaderComponent>;
10+
11+
let nativeElement: any;
12+
13+
configureTestSuite(() => {
14+
TestBed.configureTestingModule({
15+
declarations: [ PoAccordionItemHeaderComponent ]
16+
});
17+
});
18+
19+
beforeEach(() => {
20+
fixture = TestBed.createComponent(PoAccordionItemHeaderComponent);
21+
component = fixture.componentInstance;
22+
23+
nativeElement = fixture.debugElement.nativeElement;
24+
});
25+
26+
it('should be created', () => {
27+
expect(component instanceof PoAccordionItemHeaderComponent).toBeTruthy();
28+
});
29+
30+
describe('Methods:', () => {
31+
32+
it('onClick: should toggle `expanded` and call `toggle.emit` with `expanded`', () => {
33+
const expectedValue = false;
34+
component.expanded = !expectedValue;
35+
spyOn(component.toggle, 'emit');
36+
37+
component.onClick();
38+
39+
expect(component.expanded).toBe(expectedValue);
40+
expect(component.toggle.emit).toHaveBeenCalledWith(expectedValue);
41+
});
42+
43+
});
44+
45+
describe('Templates:', () => {
46+
47+
let header;
48+
let button;
49+
let span;
50+
51+
beforeEach(() => {
52+
header = nativeElement.querySelector('header');
53+
button = header.querySelector('button');
54+
span = button.querySelector('span');
55+
});
56+
57+
it('should have a header with po-accordion-item-header class', () => {
58+
expect(header).toBeTruthy();
59+
expect(header.classList.contains('po-accordion-item-header')).toBeTruthy();
60+
});
61+
62+
it('should have a header with button', () => {
63+
expect(header.querySelector('button')).toBeTruthy();
64+
});
65+
66+
it('should have a button with class po-accordion-item-header-button', () => {
67+
expect(button.classList.contains('po-accordion-item-header-button')).toBeTruthy();
68+
});
69+
70+
it('should have a button with class po-clickable', () => {
71+
expect(button.classList.contains('po-clickable')).toBeTruthy();
72+
});
73+
74+
it('should have a button with span (icon)', () => {
75+
expect(button.querySelector('span')).toBeTruthy();
76+
});
77+
78+
it('should have a span with class po-icon', () => {
79+
expect(span.classList.contains('po-icon')).toBeTruthy();
80+
});
81+
82+
it('should have a span with class po-accordion-item-header-icon', () => {
83+
expect(span.classList.contains('po-accordion-item-header-icon')).toBeTruthy();
84+
});
85+
86+
it('should have a span with class po-icon-arrow-down by default', () => {
87+
fixture.detectChanges();
88+
89+
expect(span.classList.contains('po-icon-arrow-down')).toBeTruthy();
90+
});
91+
92+
it(`shouldn't have text in button if label is empty`, () => {
93+
component.label = '';
94+
95+
fixture.detectChanges();
96+
97+
expect(button.innerText).toBe('');
98+
});
99+
100+
it('should update button text from property label', () => {
101+
const expectedValue = 'header';
102+
103+
component.label = expectedValue;
104+
105+
fixture.detectChanges();
106+
107+
expect(button.innerText).toBe(expectedValue);
108+
});
109+
110+
it('should call `onClick` on button click', () => {
111+
112+
spyOn(component, 'onClick');
113+
114+
button.click();
115+
116+
expect(component.onClick).toHaveBeenCalled();
117+
});
118+
119+
});
120+
121+
});

0 commit comments

Comments
 (0)