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

863 feat accordion group #864

Merged
merged 15 commits into from
Oct 26, 2023
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
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