Skip to content

Commit

Permalink
863 feat accordion group (#864)
Browse files Browse the repository at this point in the history
* feat: accordion-group

* docs: accordion group

* refactor: accordion

* docs: refactor storybook accordion

* test: changing safyany import path

* style: add borders

* Update projects/ion/src/lib/accordion/accordion-item/accordion-item.component.html

refator: removing code duplication

Co-authored-by: Iury Nogueira <[email protected]>

* Update projects/ion/src/lib/accordion/accordion.component.ts

refactor: improving code

Co-authored-by: Iury Nogueira <[email protected]>

* refactor: indetation

* test: adjust the error message

---------

Co-authored-by: Iury Nogueira <[email protected]>
Co-authored-by: Alysson Mascarenhas <[email protected]>
  • Loading branch information
3 people authored Oct 26, 2023
1 parent 3e6c4a8 commit ea1ba0a
Show file tree
Hide file tree
Showing 12 changed files with 456 additions and 216 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<section
data-testid="ion-accordion-item"
[class.open]="show"
[class.close]="!show"
tabindex="0"
>
<header (click)="toggle()">
<div data-testid="ion-accordion-item__header">
<ng-container
[ngTemplateOutlet]="templateHeader"
[ngTemplateOutletContext]="{ $implicit: data }"
></ng-container>
</div>
<ion-icon
*ngIf="show"
[type]="show ? 'semi-up' : 'semi-down'"
[size]="iconSize"
></ion-icon>
</header>
<main *ngIf="show" data-testid="ion-accordion-item__main">
<ng-content></ng-content>
</main>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
@import '../../../styles/index.scss';

@mixin accordion-style($bgColor, $color) {
header {
color: $color;
border-bottom: 1px solid $color;
background-color: $bgColor;

ion-icon {
::ng-deep svg {
fill: $color;
}
}
}
}

section {
@include accordion-style($neutral-1, $neutral-7);
header,
main {
padding: 16px 20px;
}

header {
display: flex;
justify-content: space-between;
align-items: center;
min-height: 64px;
box-sizing: border-box;
cursor: pointer;

div {
div {
font-size: 16px;
font-weight: 600;
line-height: 24px;
}
}
}

main {
background-color: $neutral-1;
}

&:hover {
@include accordion-style($neutral-2, $primary-3);
}

&:active {
@include accordion-style($primary-2, $primary-4);
}

&:focus-visible {
outline: 2px solid $primary-4;
}

&.open {
@include accordion-style($primary-1, $primary-4);
}

&.close {
header {
border-bottom: 1px solid $neutral-4;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { screen, fireEvent, render } from '@testing-library/angular';
import { Component, NgModule } from '@angular/core';
import { IonAccordionModule } from '../accordion.module';
import { TestBed, ComponentFixture } from '@angular/core/testing';
import { CommonModule } from '@angular/common';
import { IonIconModule } from '../../icon/icon.module';
import { IonAccordionItemComponent } from './accordion-item.component';
import { IonAccordionItemProps } from '../../core/types';
import { SafeAny } from '../../utils/safe-any';

@Component({
template: `<ion-accordion-item [templateHeader]="customHeader" [data]="data">
<p data-testid="ion-accordion-item__main-paragraph">Context Main</p>
</ion-accordion-item>
<ng-template #customHeader> {{ data.name }}</ng-template>`,
})
class AccordionItemTestComponent {
data = { name: 'Accordion header' };
}

@NgModule({
declarations: [AccordionItemTestComponent],
imports: [CommonModule, IonAccordionModule, IonIconModule],
})
class AccordionTestModule {}

describe('IonAccordionItem', () => {
let accordionTestComponent!: AccordionItemTestComponent;
let fixture!: ComponentFixture<AccordionItemTestComponent>;
beforeEach(async () => {
TestBed.configureTestingModule({
imports: [AccordionTestModule],
}).compileComponents();
fixture = TestBed.createComponent(AccordionItemTestComponent);
accordionTestComponent = fixture.componentInstance;
fixture.detectChanges();
});

afterEach(async () => {
fixture.destroy();
});

it('should render ion-accordion-item', async () => {
expect(screen.getByTestId('ion-accordion-item')).toBeTruthy();
});

it('should render the header with the name Brisanet', async () => {
const accordionHeader = 'Brisanet';
accordionTestComponent.data.name = accordionHeader;
fixture.detectChanges();
expect(screen.getByTestId('ion-accordion-item__header')).toHaveTextContent(
accordionHeader
);
});

it('should render main when clicking on header', async () => {
const header = screen.getByTestId('ion-accordion-item__header');
fireEvent.click(header);
fixture.detectChanges();
expect(screen.getByTestId('ion-accordion-item__main')).toBeTruthy();
expect(
screen.getByTestId('ion-accordion-item__main-paragraph')
).toHaveTextContent('Context Main');
});

it('should not render main when clicking on header twice', async () => {
const header = screen.getByTestId('ion-accordion-item__header');
fireEvent.click(header);
fireEvent.click(header);
fixture.detectChanges();
expect(screen.queryByTestId('ion-accordion-item__main')).not.toBeTruthy();
});
});

describe('IonAccordionItem - throw an error', () => {
const sut = async (
customProps: IonAccordionItemProps = {} as SafeAny
): Promise<void> => {
await render(IonAccordionItemComponent, {
componentProperties: { ...customProps },
imports: [CommonModule, IonIconModule],
});
};

it('should throw an error when templateHeader propertie do not exist', async () => {
try {
await sut();
} catch (error) {
expect(error.message).toBe(
'The templateHeader propertie were not set correctly'
);
}
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import {
Component,
Input,
OnInit,
Output,
EventEmitter,
TemplateRef,
} from '@angular/core';
import { SafeAny } from '../../utils/safe-any';

@Component({
selector: 'ion-accordion-item',
templateUrl: './accordion-item.component.html',
styleUrls: ['./accordion-item.component.scss'],
})
export class IonAccordionItemComponent implements OnInit {
@Input() templateHeader: TemplateRef<HTMLElement>;
@Input() show? = false;
@Input() data?: SafeAny;
@Output() activeChange? = new EventEmitter<void>();

iconSize = 24;

ngOnInit(): void {
if (!this.templateHeader) {
throw new Error('The templateHeader propertie were not set correctly');
}
}

toggle(): void {
this.show = !this.show;

this.activeChange.emit();
}
}
39 changes: 14 additions & 25 deletions projects/ion/src/lib/accordion/accordion.component.html
Original file line number Diff line number Diff line change
@@ -1,26 +1,15 @@
<section
data-testid="ion-accordion"
[class.open]="show"
[class.close]="!show"
tabindex="0"
>
<header (click)="toggle()">
<div>
<div
*ngIf="!templateHeader; else headerCustom"
data-testid="ion-accordion__header-name"
>
{{ name }}
</div>
<ng-template
#headerCustom
[ngTemplateOutlet]="templateHeader"
></ng-template>
</div>
<ion-icon *ngIf="show" type="semi-up" [size]="iconSize"></ion-icon>
<ion-icon *ngIf="!show" type="semi-down" [size]="iconSize"></ion-icon>
</header>
<main *ngIf="show" data-testid="ion-accordion__main">
<ng-content></ng-content>
</main>
<section data-testid="ion-accordion">
<ion-accordion-item
*ngFor="let accordion of accordions; let i = index"
[show]="accordion.show"
[data]="accordion"
[templateHeader]="templateHeader"
(activeChange)="toggle(i)"
>
<ng-container
*ngIf="templateBody"
[ngTemplateOutlet]="templateBody"
[ngTemplateOutletContext]="{ $implicit: accordion }"
></ng-container>
</ion-accordion-item>
</section>
74 changes: 23 additions & 51 deletions projects/ion/src/lib/accordion/accordion.component.scss
Original file line number Diff line number Diff line change
@@ -1,66 +1,38 @@
@import '../../styles/index.scss';

@mixin accordion-style($bgColor, $color) {
header {
color: $color;
border-bottom: 1px solid $color;
background-color: $bgColor;

ion-icon {
::ng-deep svg {
fill: $color;
section {
::ng-deep ion-accordion-item:first-child {
section {
header {
border-radius: 8px 8px 0 0;
}
}
}
}

section {
@include accordion-style($neutral-1, $neutral-7);
header,
main {
padding: 16px 20px;
}

header {
display: flex;
justify-content: space-between;
align-items: center;
min-height: 64px;
box-sizing: border-box;
cursor: pointer;

div {
div {
font-size: 16px;
font-weight: 600;
line-height: 24px;
::ng-deep ion-accordion-item {
section {
header,
main {
border: 1px solid $neutral-4;
}
}
}

main {
background-color: $neutral-1;
}

&:hover {
@include accordion-style($neutral-2, $primary-3);
}

&:active {
@include accordion-style($primary-2, $primary-4);
}

&:focus-visible {
outline: 2px solid $primary-4;
}
::ng-deep ion-accordion-item:last-child {
section {
header {
border-radius: 0 0 8px 8px;
}
}

&.open {
@include accordion-style($primary-1, $primary-4);
}
section.open {
header {
border-radius: 0;
}

&.close {
header {
border-bottom: 1px solid $neutral-4;
main {
border-radius: 0 0 8px 8px;
}
}
}
}
Loading

0 comments on commit ea1ba0a

Please sign in to comment.