From 3b482777b406b6c2d242951d3a2b11f05314072f Mon Sep 17 00:00:00 2001 From: CSimoesJr Date: Wed, 20 Sep 2023 22:32:48 -0300 Subject: [PATCH] =?UTF-8?q?feat(accordion):=20implementa=20defini=C3=A7?= =?UTF-8?q?=C3=B5es=20do=20AnimaliaDS?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implementa definições do AnimaliaDS no Accordion fixes DTHFUI-7691 --- .../src/lib/components/po-accordion/index.ts | 1 + .../po-accordion-literals.interface.ts | 14 ++ .../po-accordion-base.component.spec.ts | 97 ++++++++++++- .../po-accordion-base.component.ts | 109 ++++++++++++++- .../po-accordion-item-header.component.html | 19 ++- ...po-accordion-item-header.component.spec.ts | 23 ++-- .../po-accordion-item-header.component.ts | 35 ++++- .../po-accordion-item.component.spec.ts | 30 +++- .../po-accordion-item.component.ts | 51 ++++++- .../po-accordion-manager.component.html | 13 ++ .../po-accordion-manager.component.spec.ts | 40 ++++++ .../po-accordion-manager.component.ts | 18 +++ .../po-accordion/po-accordion.component.html | 40 ++++-- .../po-accordion.component.spec.ts | 128 +++++++++++++++++- .../po-accordion/po-accordion.component.ts | 33 ++++- .../po-accordion/po-accordion.module.ts | 14 +- .../sample-po-accordion-faq.component.html | 8 +- .../sample-po-accordion-labs.component.html | 53 +++++++- .../sample-po-accordion-labs.component.ts | 53 +++++++- 19 files changed, 723 insertions(+), 56 deletions(-) create mode 100644 projects/ui/src/lib/components/po-accordion/interfaces/po-accordion-literals.interface.ts create mode 100644 projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.html create mode 100644 projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.spec.ts create mode 100644 projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.ts diff --git a/projects/ui/src/lib/components/po-accordion/index.ts b/projects/ui/src/lib/components/po-accordion/index.ts index d2bec1513f..a4cc9752a9 100644 --- a/projects/ui/src/lib/components/po-accordion/index.ts +++ b/projects/ui/src/lib/components/po-accordion/index.ts @@ -1,3 +1,4 @@ +export * from './interfaces/po-accordion-literals.interface'; export * from './po-accordion-item/po-accordion-item.component'; export * from './po-accordion.component'; diff --git a/projects/ui/src/lib/components/po-accordion/interfaces/po-accordion-literals.interface.ts b/projects/ui/src/lib/components/po-accordion/interfaces/po-accordion-literals.interface.ts new file mode 100644 index 0000000000..adf4e3bfc4 --- /dev/null +++ b/projects/ui/src/lib/components/po-accordion/interfaces/po-accordion-literals.interface.ts @@ -0,0 +1,14 @@ +/** + * @usedBy PoAccordionComponent + * + * @description + * + * Interface para definição das literais usadas no `po-accordion`. + */ +export interface PoAccordionLiterals { + /** Label do gerenciador de Accordion para expandir todos os itens. */ + expandAllItems?: string; + + /** Label do gerenciador de Accordion para colapsar todos os itens */ + closeAllItems?: string; +} diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-base.component.spec.ts b/projects/ui/src/lib/components/po-accordion/po-accordion-base.component.spec.ts index 15bc97fc71..961877c275 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion-base.component.spec.ts +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-base.component.spec.ts @@ -1,9 +1,102 @@ -import { PoAccordionBaseComponent } from './po-accordion-base.component'; +import { poLocaleDefault } from '../../services'; +import { PoLanguageService } from '../../services/po-language/po-language.service'; +import { expectPropertiesValues } from '../../util-test/util-expect.spec'; +import { convertToBoolean } from '../../utils/util'; +import { PoAccordionBaseComponent, poAccordionLiteralsDefault } from './po-accordion-base.component'; describe('PoAccordionBaseComponent:', () => { - const component = new PoAccordionBaseComponent(); + const languageService: PoLanguageService = new PoLanguageService(); + let component: PoAccordionBaseComponent; + + beforeEach(() => { + component = new PoAccordionBaseComponent(languageService); + }); it('should be created', () => { expect(component instanceof PoAccordionBaseComponent).toBeTruthy(); }); + + it('p-literals: should be in portuguese if browser is setted with an unsupported language', () => { + component['language'] = 'zw'; + + component.literals = {}; + + expect(component.literals).toEqual(poAccordionLiteralsDefault[poLocaleDefault]); + }); + + it('p-literals: should be in portuguese if browser is setted with `pt`', () => { + component['language'] = 'pt'; + + component.literals = {}; + + expect(component.literals).toEqual(poAccordionLiteralsDefault.pt); + }); + + it('p-literals: should be in english if browser is setted with `en`', () => { + component['language'] = 'en'; + + component.literals = {}; + + expect(component.literals).toEqual(poAccordionLiteralsDefault.en); + }); + + it('p-literals: should be in spanish if browser is setted with `es`', () => { + component['language'] = 'es'; + + component.literals = {}; + + expect(component.literals).toEqual(poAccordionLiteralsDefault.es); + }); + + it('p-literals: should be in russian if browser is setted with `ru`', () => { + component['language'] = 'ru'; + + component['_literals'] = undefined; + + expect(component.literals).toEqual(poAccordionLiteralsDefault.ru); + }); + + it('p-literals: should accept custom literals', () => { + component['language'] = poLocaleDefault; + + const customLiterals = Object.assign({}, poAccordionLiteralsDefault[poLocaleDefault]); + + customLiterals.closeAllItems = 'Close'; + + component.literals = customLiterals; + + expect(component.literals).toEqual(customLiterals); + }); + + it('p-literals: should update property with default literals if is setted with invalid values', () => { + const invalidValues = [null, undefined, false, true, '', 'literals', 0, 10, [], [1, 2], () => {}]; + + component['language'] = poLocaleDefault; + + expectPropertiesValues(component, 'literals', invalidValues, poAccordionLiteralsDefault[poLocaleDefault]); + }); + + it('showManagerAccordion: should set property `p-show-manager-accordion` to `false` if invalid value', () => { + component.showManagerAccordion = convertToBoolean(3); + + expect(component.showManagerAccordion).toBe(false); + }); + + it('hideRemoveAllDisclaimer: should update property `p-show-manager-accordion` to `true` with valid values', () => { + component.showManagerAccordion = convertToBoolean(1); + + expect(component.showManagerAccordion).toBe(true); + }); + + it('allowExpandItems: should set property `p-allow-expand-all-items` to `false` if invalid value', () => { + component.allowExpandItems = convertToBoolean(3); + + expect(component.allowExpandItems).toBe(false); + }); + + it('hideRemoveAllDisclaimer: should update property `p-allow-expand-all-items` to `true` with valid values', () => { + component.allowExpandItems = convertToBoolean(1); + + expect(component.allowExpandItems).toBe(true); + }); }); diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-base.component.ts b/projects/ui/src/lib/components/po-accordion/po-accordion-base.component.ts index 5c1b49006b..30b99fd678 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion-base.component.ts +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-base.component.ts @@ -1,3 +1,28 @@ +import { Directive, Input } from '@angular/core'; +import { poLocaleDefault } from '../../services/po-language/po-language.constant'; +import { PoLanguageService } from '../../services/po-language/po-language.service'; +import { convertToBoolean } from '../../utils/util'; +import { PoAccordionLiterals } from './interfaces/po-accordion-literals.interface'; + +export const poAccordionLiteralsDefault = { + en: { + closeAllItems: 'Close all items', + expandAllItems: 'Open all items' + }, + es: { + closeAllItems: 'Cerrar todos los elementos', + expandAllItems: 'Abrir todos los elementos' + }, + pt: { + closeAllItems: 'Fechar todos os itens', + expandAllItems: 'Abrir todos os itens' + }, + ru: { + closeAllItems: 'Закрыть все элементы', + expandAllItems: 'Открыть все элементы' + } +}; + /** * @description * @@ -24,4 +49,86 @@ * Caso houver a necessidade de abrir algum dos `po-accordion-item` via Typescript * acesse a [documentação do PoAccordionItem](/documentation/po-accordion-item). */ -export class PoAccordionBaseComponent {} +@Directive() +export class PoAccordionBaseComponent { + private language: string = poLocaleDefault; + private _literals; + + /** + * @optional + * + * @description + * + * Objeto com as literais usadas no `po-accordion`. + * + * Existem duas maneiras de customizar o componente, passando um objeto com todas as literais disponíveis: + * + * ``` + * const customLiterals: PoAccordionLiterals = { + * closeAllItems: 'Fechar todos os itens', + * expandAllItems: 'Expandir todos os itens' + * }; + * ``` + * + * Ou passando apenas as literais que deseja customizar: + * + * ``` + * const customLiterals: PoAccordionLiterals = { + * expandAllItems: 'Expandir todos os itens' + * }; + * ``` + * + * E para carregar as literais customizadas, basta apenas passar o objeto para o componente. + * + * ``` + * + * + * ``` + * + * > O objeto padrão de literais será traduzido de acordo com o idioma do + * [`PoI18nService`](/documentation/po-i18n) ou do browser. + */ + @Input('p-literals') set literals(value: PoAccordionLiterals) { + if (value instanceof Object && !(value instanceof Array)) { + this._literals = { + ...poAccordionLiteralsDefault[poLocaleDefault], + ...poAccordionLiteralsDefault[this.language], + ...value + }; + } else { + this._literals = poAccordionLiteralsDefault[this.language]; + } + } + + get literals() { + return this._literals || poAccordionLiteralsDefault[this.language]; + } + + /** + * @optional + * + * @description + * + * Exibe o Gerenciador de Accordion. + * + * @default `false` + */ + @Input({ alias: 'p-show-manager-accordion', transform: convertToBoolean }) showManagerAccordion: boolean = false; + + /** + * @optional + * + * @description + * + * Permite expandir mais de um `` ao mesmo tempo. + * Sempre habilitada caso a propriedade `p-show-manager-accordion` esteja como `true`. + * + * @default `false` + */ + @Input({ alias: 'p-allow-expand-all-items', transform: convertToBoolean }) allowExpandItems: boolean = false; + + constructor(languageService: PoLanguageService) { + this.language = languageService.getShortLanguage(); + } +} diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.html b/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.html index 46bf375dc8..f1fd8eddf9 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.html +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.html @@ -1,6 +1,15 @@ -
- -
+ diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.spec.ts b/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.spec.ts index 15bdb014f9..1692752957 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.spec.ts +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.spec.ts @@ -43,12 +43,13 @@ describe('PoAccordionItemHeaderComponent:', () => { describe('Templates:', () => { let header; let button; - let span; + let icon; beforeEach(() => { - header = nativeElement.querySelector('header'); + component.disabledItem = false; + header = nativeElement.querySelector('div'); button = header.querySelector('button'); - span = button.querySelector('span'); + icon = button.querySelector('po-icon'); }); it('should have a header with po-accordion-item-header class', () => { @@ -68,22 +69,22 @@ describe('PoAccordionItemHeaderComponent:', () => { expect(button.classList.contains('po-clickable')).toBeTruthy(); }); - it('should have a button with span (icon)', () => { - expect(button.querySelector('span')).toBeTruthy(); + it('should have a button with icon (icon)', () => { + expect(button.querySelector('po-icon')).toBeTruthy(); }); - it('should have a span with class po-icon', () => { - expect(span.classList.contains('po-icon')).toBeTruthy(); + it('should have a icon with class po-icon', () => { + expect(icon.classList.contains('po-icon')).toBeTruthy(); }); - it('should have a span with class po-accordion-item-header-icon', () => { - expect(span.classList.contains('po-accordion-item-header-icon')).toBeTruthy(); + it('should have a icon with class po-accordion-item-header-icon', () => { + expect(icon.classList.contains('po-accordion-item-header-icon')).toBeTruthy(); }); - it('should have a span with class po-icon-arrow-down by default', () => { + it('should have a icon with class po-accordion-item-header-icon by default', () => { fixture.detectChanges(); - expect(span.classList.contains('po-icon-arrow-down')).toBeTruthy(); + expect(icon.classList.contains('po-accordion-item-header-icon')).toBeTruthy(); }); it(`shouldn't have text in button if label is empty`, () => { diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.ts b/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.ts index aa0a536e3b..7bcaef62e0 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.ts +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-item-header/po-accordion-item-header.component.ts @@ -1,4 +1,6 @@ -import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core'; +import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { PoLanguageService } from '../../../services/po-language'; +import { poLocaleDefault } from '../../../services/po-language/po-language.constant'; @Component({ selector: 'po-accordion-item-header', @@ -6,12 +8,43 @@ import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from changeDetection: ChangeDetectionStrategy.OnPush }) export class PoAccordionItemHeaderComponent { + private language: string = poLocaleDefault; + @Input('p-expanded') expanded: boolean = false; @Input('p-label') label: string; + @Input('p-label-tag') labelTag: string; + + @Input('p-type-tag') typeTag: string; + + @Input('p-disabled') disabledItem: boolean; + @Output('p-toggle') toggle = new EventEmitter(); + poAccordionAriaLiterals = { + en: { + expanded: 'expanded', + reduced: 'Reduced' + }, + es: { + expanded: 'expandido', + reduced: 'reducido' + }, + pt: { + expanded: 'Expandido', + reduced: 'Reduzido' + }, + ru: { + expanded: 'расширенный', + reduced: 'уменьшенный' + } + }; + + constructor(languageService: PoLanguageService) { + this.language = languageService.getShortLanguage(); + } + onClick() { this.expanded = !this.expanded; diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-item/po-accordion-item.component.spec.ts b/projects/ui/src/lib/components/po-accordion/po-accordion-item/po-accordion-item.component.spec.ts index 1f96918371..b9ed1ef091 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion-item/po-accordion-item.component.spec.ts +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-item/po-accordion-item.component.spec.ts @@ -1,7 +1,9 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { PoAccordionItemComponent } from './po-accordion-item.component'; +import { expectPropertiesValues } from '../../../util-test/util-expect.spec'; +import { convertToBoolean } from '../../../utils/util'; import { PoAccordionService } from '../services/po-accordion.service'; +import { PoAccordionItemComponent } from './po-accordion-item.component'; describe('PoAccordionItemComponent:', () => { let component: PoAccordionItemComponent; @@ -43,4 +45,30 @@ describe('PoAccordionItemComponent:', () => { expect(component.expandEvent.emit).toHaveBeenCalled(); }); }); + + describe('Properties:', () => { + it('disabledItem: should set property `p-disabled` to `false` if invalid value', () => { + component.disabledItem = convertToBoolean(3); + + expect(component.disabledItem).toBe(false); + }); + + it('hideRemoveAllDisclaimer: should update property `p-disabled` to `true` with valid values', () => { + component.disabledItem = convertToBoolean(1); + + expect(component.disabledItem).toBe(true); + }); + + it('typeTag: should update property with valid values', () => { + const validValues = ['danger', 'info', 'success', 'warning']; + + expectPropertiesValues(component, 'typeTag', validValues, validValues); + }); + + it('typeTag: should update property with `info` if values are invalid', () => { + const invalidValues = [undefined, null, '', true, false, 0, -1, 12, 15, 'aa', [], {}]; + + expectPropertiesValues(component, 'typeTag', invalidValues, undefined); + }); + }); }); diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-item/po-accordion-item.component.ts b/projects/ui/src/lib/components/po-accordion/po-accordion-item/po-accordion-item.component.ts index 012c6f7f29..fa6d72bb95 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion-item/po-accordion-item.component.ts +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-item/po-accordion-item.component.ts @@ -1,6 +1,8 @@ import { Component, EventEmitter, Input, OnDestroy, Output, TemplateRef, ViewChild } from '@angular/core'; -import { filter, Subscription } from 'rxjs'; +import { Subscription, filter } from 'rxjs'; +import { convertToBoolean } from '../../../utils/util'; +import { PoTagType } from '../../po-tag'; import { PoAccordionService } from '../services/po-accordion.service'; /** @@ -39,9 +41,56 @@ import { PoAccordionService } from '../services/po-accordion.service'; templateUrl: 'po-accordion-item.component.html' }) export class PoAccordionItemComponent implements OnDestroy { + private _type?: PoTagType; + /** Título do item. */ @Input('p-label') label: string; + /** + * @optional + * + * @description + * + * Label da Tag. + * + */ + @Input('p-label-tag') labelTag: string; + + /** + * @optional + * + * @description + * + * Desabilita item. + * + * @default `false` + */ + @Input({ alias: 'p-disabled', transform: convertToBoolean }) disabledItem: boolean = false; + + /** + * @optional + * + * @description + * + * Define o tipo da *tag* caso ela esteja sendo exibida. + * + * Valores válidos: + * - `success`: cor verde utilizada para simbolizar sucesso ou êxito. + * - `warning`: cor amarela que representa aviso ou advertência. + * - `danger`: cor vermelha para erro ou aviso crítico. + * - `info`: cor cinza escuro que caracteriza conteúdo informativo. + * + * + * @default `info` + */ + @Input('p-type-tag') set typeTag(value: PoTagType) { + this._type = (Object).values(PoTagType).includes(value) ? value : undefined; + } + + get typeTag(): PoTagType { + return this._type; + } + /** Evento disparado ao expandir o item, seja manualmente ou programaticamente. */ @Output('p-expand') expandEvent = new EventEmitter(); diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.html b/projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.html new file mode 100644 index 0000000000..72ec207519 --- /dev/null +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.html @@ -0,0 +1,13 @@ +
+ +
diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.spec.ts b/projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.spec.ts new file mode 100644 index 0000000000..5554078a4c --- /dev/null +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.spec.ts @@ -0,0 +1,40 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; + +import { PoAccordionManagerComponent } from './po-accordion-manager.component'; + +describe('PoAccordionManagerComponent:', () => { + let component: PoAccordionManagerComponent; + let fixture: ComponentFixture; + + let nativeElement: any; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [PoAccordionManagerComponent], + imports: [BrowserAnimationsModule] + }).compileComponents(); + + fixture = TestBed.createComponent(PoAccordionManagerComponent); + component = fixture.componentInstance; + + nativeElement = fixture.debugElement.nativeElement; + }); + + it('should be created', () => { + expect(component instanceof PoAccordionManagerComponent).toBeTruthy(); + }); + + describe('Methods:', () => { + it('onClick: should call `clickManager.emit`', () => { + const expectedValue = true; + component.expandedAllItems = expectedValue; + spyOn(component.clickManager, 'emit'); + + component.onClick(); + + expect(component.expandedAllItems).toBe(expectedValue); + expect(component.clickManager.emit).toHaveBeenCalled(); + }); + }); +}); diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.ts b/projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.ts new file mode 100644 index 0000000000..f740b85cfb --- /dev/null +++ b/projects/ui/src/lib/components/po-accordion/po-accordion-manager/po-accordion-manager.component.ts @@ -0,0 +1,18 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { PoAccordionLiterals } from '../interfaces/po-accordion-literals.interface'; + +@Component({ + selector: 'po-accordion-manager', + templateUrl: 'po-accordion-manager.component.html' +}) +export class PoAccordionManagerComponent { + @Input('p-expanded-all-items') expandedAllItems: boolean = false; + + @Input('p-literals') literals: PoAccordionLiterals; + + @Output('p-click') clickManager = new EventEmitter(); + + onClick() { + this.clickManager.emit(); + } +} diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion.component.html b/projects/ui/src/lib/components/po-accordion/po-accordion.component.html index b22378d727..59d8e26f84 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion.component.html +++ b/projects/ui/src/lib/components/po-accordion/po-accordion.component.html @@ -1,18 +1,30 @@
-
- + +
+
    +
  • - + + - - - - + + + +
  • +
diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion.component.spec.ts b/projects/ui/src/lib/components/po-accordion/po-accordion.component.spec.ts index 5df92d8ceb..82c51afb8b 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion.component.spec.ts +++ b/projects/ui/src/lib/components/po-accordion/po-accordion.component.spec.ts @@ -1,5 +1,5 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { Component } from '@angular/core'; +import { Component, QueryList } from '@angular/core'; import { ComponentFixture, TestBed } from '@angular/core/testing'; import { PoAccordionComponent } from './po-accordion.component'; @@ -8,7 +8,7 @@ import { PoAccordionService } from './services/po-accordion.service'; @Component({ template: ` - + Item 1 Item 2 @@ -21,7 +21,7 @@ describe('PoAccordionComponent:', () => { let fixture: ComponentFixture; let componentMock: PoAccordionMockComponent; let fixtureMock: ComponentFixture; - let nativeElement: any; + let debugElement: any; let nativeElementMock: any; beforeEach(async () => { @@ -34,7 +34,7 @@ describe('PoAccordionComponent:', () => { fixture = TestBed.createComponent(PoAccordionComponent); component = fixture.componentInstance; fixture.detectChanges(); - nativeElement = fixture.debugElement.nativeElement; + debugElement = fixture.debugElement.nativeElement; fixtureMock = TestBed.createComponent(PoAccordionMockComponent); componentMock = fixtureMock.componentInstance; @@ -75,6 +75,117 @@ describe('PoAccordionComponent:', () => { expect(component['toggle']).toHaveBeenCalledWith(poAccordionItemExpected); }); + it('headerToggle: should call `toggle` with `poAccordionItem` and set `poAccordionItem.expanded` to true', () => { + spyOn(component, 'toggle'); + + const poAccordionList = [ + { + expanded: false, + label: 'Test Label' + }, + { + expanded: false, + label: 'Test Label' + }, + { + expanded: true, + disabledItem: true, + label: 'Test Label' + } + ]; + + const poAccordionItem = { + expanded: false, + label: 'Test Label' + }; + + const poAccordionItemExpected = { + expanded: true, + label: 'Test Label' + }; + + const event = true; + const queryList = new QueryList(); + queryList.reset(poAccordionList); + component.showManagerAccordion = true; + component.poAccordionItems = queryList as any; + + component.headerToggle(event, poAccordionItem); + + expect(component['toggle']).toHaveBeenCalledWith(poAccordionItemExpected); + expect(component.expandedAllItems).toBe(true); + }); + + it('headerToggle: should call `toggle` with `poAccordionItem` and set `poAccordionItem.expanded` to true', () => { + spyOn(component, 'toggle'); + + const poAccordionList = [ + { + expanded: false, + label: 'Test Label' + }, + { + expanded: true, + label: 'Test Label' + }, + { + expanded: false, + disabledItem: true, + label: 'Test Label' + } + ]; + + const poAccordionItem = { + expanded: false, + label: 'Test Label' + }; + + const poAccordionItemExpected = { + expanded: true, + label: 'Test Label' + }; + + const event = true; + const queryList = new QueryList(); + queryList.reset(poAccordionList); + component.showManagerAccordion = true; + component.poAccordionItems = queryList as any; + + component.headerToggle(event, poAccordionItem); + + expect(component['toggle']).toHaveBeenCalledWith(poAccordionItemExpected); + expect(component.expandedAllItems).toBe(false); + }); + + it('changeVisibleAllItems: should call `toggle` with `poAccordionItem` and expand all items if not disabled', () => { + spyOn(component, 'toggle'); + + const poAccordionList = [ + { + expanded: false, + label: 'Test Label' + }, + { + expanded: false, + label: 'Test Label' + }, + { + expanded: false, + disabledItem: true, + label: 'Test Label' + } + ]; + + component.poAccordionItems = poAccordionList as any; + + component.changeVisibleAllItems(false); + + expect(component['toggle']).toHaveBeenCalled(); + expect(component.expandedAllItems).toBe(true); + expect(component.poAccordionItems[0].expanded).toBe(true); + expect(component.poAccordionItems[2].expanded).toBe(false); + }); + it('receiveFromChildAccordionSubscription: should call `toggle` if `receiveFromChildAccordionClicked` emit for a subscription', () => { const poAccordionItem = { expanded: false, @@ -121,6 +232,8 @@ describe('PoAccordionComponent:', () => { spyOn(expandedActiveAccordionItem, 'collapse'); + component.allowExpandItems = false; + component.showManagerAccordion = false; component['expandedActiveAccordionItem'] = expandedActiveAccordionItem; component['toggle'](currentAccordionItem); @@ -161,5 +274,12 @@ describe('PoAccordionComponent:', () => { expect(activeItem).toBeFalsy(); }); + + it('should contain `po-accordion-manager` if `showManagerAccordion` is active', () => { + fixture.detectChanges(); + const managerAccordion = nativeElementMock.querySelector('.po-accordion-manager'); + + expect(managerAccordion).toBeTruthy(); + }); }); }); diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion.component.ts b/projects/ui/src/lib/components/po-accordion/po-accordion.component.ts index 85fcfe81cd..758e201a9f 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion.component.ts +++ b/projects/ui/src/lib/components/po-accordion/po-accordion.component.ts @@ -5,6 +5,7 @@ import { Subscription } from 'rxjs'; import { PoAccordionBaseComponent } from './po-accordion-base.component'; import { PoAccordionItemComponent } from './po-accordion-item/po-accordion-item.component'; import { PoAccordionService } from './services/po-accordion.service'; +import { PoLanguageService } from '../../services/po-language/po-language.service'; /** * @docsExtends PoAccordionBaseComponent @@ -36,11 +37,13 @@ import { PoAccordionService } from './services/po-accordion.service'; export class PoAccordionComponent extends PoAccordionBaseComponent implements OnDestroy { @ContentChildren(PoAccordionItemComponent) poAccordionItems: QueryList; + expandedAllItems = false; + private accordionServiceSubscription: Subscription; private expandedActiveAccordionItem: PoAccordionItemComponent; - constructor(private accordionService: PoAccordionService) { - super(); + constructor(private accordionService: PoAccordionService, languageService: PoLanguageService) { + super(languageService); this.receiveFromChildAccordionSubscription(); } @@ -48,8 +51,31 @@ export class PoAccordionComponent extends PoAccordionBaseComponent implements On this.accordionServiceSubscription.unsubscribe(); } + changeVisibleAllItems(event: boolean) { + this.expandedAllItems = !event; + + this.poAccordionItems.forEach(item => { + if (!item.disabledItem) { + item.expanded = this.expandedAllItems; + this.toggle(item); + } + }); + } + headerToggle(event: boolean, poAccordionItem: PoAccordionItemComponent) { poAccordionItem.expanded = event; + if (this.showManagerAccordion) { + const accordionList = this.poAccordionItems.toArray(); + const accordionsValids = accordionList.filter(item => !item.disabledItem); + const allItemsExpanded = accordionsValids.every(item => item.expanded === true); + const allItemsCollapsed = accordionsValids.every(item => item.expanded === false); + + if (allItemsExpanded || allItemsCollapsed) { + this.expandedAllItems = event; + } else { + this.expandedAllItems = false; + } + } this.accordionService.sendToParentAccordionItemClicked(poAccordionItem); } @@ -62,13 +88,12 @@ export class PoAccordionComponent extends PoAccordionBaseComponent implements On private toggle(poAccordionItem: PoAccordionItemComponent) { const isCurrentAccordionCollapsed = !poAccordionItem.expanded; - if (isCurrentAccordionCollapsed) { this.expandedActiveAccordionItem = null; return; } - if (this.expandedActiveAccordionItem) { + if (!this.showManagerAccordion && !this.allowExpandItems && this.expandedActiveAccordionItem) { this.expandedActiveAccordionItem.collapse(); } diff --git a/projects/ui/src/lib/components/po-accordion/po-accordion.module.ts b/projects/ui/src/lib/components/po-accordion/po-accordion.module.ts index 884cd8d78a..354142ea6b 100644 --- a/projects/ui/src/lib/components/po-accordion/po-accordion.module.ts +++ b/projects/ui/src/lib/components/po-accordion/po-accordion.module.ts @@ -1,10 +1,15 @@ import { CommonModule } from '@angular/common'; import { NgModule } from '@angular/core'; -import { PoAccordionComponent } from './po-accordion.component'; +import { PoDividerModule } from '../po-divider'; +import { PoIconModule } from '../po-icon'; +import { PoTagModule } from '../po-tag'; + import { PoAccordionItemBodyComponent } from './po-accordion-item-body/po-accordion-item-body.component'; -import { PoAccordionItemComponent } from './po-accordion-item/po-accordion-item.component'; import { PoAccordionItemHeaderComponent } from './po-accordion-item-header/po-accordion-item-header.component'; +import { PoAccordionItemComponent } from './po-accordion-item/po-accordion-item.component'; +import { PoAccordionManagerComponent } from './po-accordion-manager/po-accordion-manager.component'; +import { PoAccordionComponent } from './po-accordion.component'; /** * @description @@ -38,12 +43,13 @@ import { PoAccordionItemHeaderComponent } from './po-accordion-item-header/po-ac * ``` */ @NgModule({ - imports: [CommonModule], + imports: [CommonModule, PoTagModule, PoIconModule, PoDividerModule], declarations: [ PoAccordionComponent, PoAccordionItemBodyComponent, PoAccordionItemComponent, - PoAccordionItemHeaderComponent + PoAccordionItemHeaderComponent, + PoAccordionManagerComponent ], exports: [PoAccordionComponent, PoAccordionItemComponent] }) diff --git a/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-faq/sample-po-accordion-faq.component.html b/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-faq/sample-po-accordion-faq.component.html index b88c5588bb..0a9623e7af 100644 --- a/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-faq/sample-po-accordion-faq.component.html +++ b/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-faq/sample-po-accordion-faq.component.html @@ -1,14 +1,18 @@

You don't have to be afraid of being a blood donor!

- + In principle, we can say that we can all apply for blood donation. However, our acceptance depends on compliance with current legislation and a number of factors that take into account the risk that such a donation may pose to the health of the candidate himself and to the health of the individual receiving the donated blood. - + Blood is processed as soon as collected, preferably within 6 hours of donation. diff --git a/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-labs/sample-po-accordion-labs.component.html b/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-labs/sample-po-accordion-labs.component.html index 8ced1d8321..00c24a745b 100644 --- a/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-labs/sample-po-accordion-labs.component.html +++ b/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-labs/sample-po-accordion-labs.component.html @@ -1,14 +1,59 @@ - - + + Accordion Item Content {{ i }} + +
+ + + + +
+ + +
+ + + + +
+
-
+
diff --git a/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-labs/sample-po-accordion-labs.component.ts b/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-labs/sample-po-accordion-labs.component.ts index 3b96f693d4..615f141624 100644 --- a/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-labs/sample-po-accordion-labs.component.ts +++ b/projects/ui/src/lib/components/po-accordion/samples/sample-po-accordion-labs/sample-po-accordion-labs.component.ts @@ -1,6 +1,13 @@ import { Component, OnInit } from '@angular/core'; -import { PoAccordionItemComponent, PoDynamicFormField } from '@po-ui/ng-components'; +import { + PoAccordionItemComponent, + PoAccordionLiterals, + PoCheckboxGroupOption, + PoDynamicFormField, + PoRadioGroupOption, + PoTagType +} from '@po-ui/ng-components'; @Component({ selector: 'sample-po-accordion-labs', @@ -8,10 +15,32 @@ import { PoAccordionItemComponent, PoDynamicFormField } from '@po-ui/ng-componen }) export class SamplePoAccordionLabsComponent implements OnInit { accordionFieldsForm: Array = [ - { property: 'label', divider: 'ACCORDION ITEM', required: true, gridColumns: 6 } + { property: 'label', required: true, gridColumns: 6 }, + { property: 'labelTag', label: 'Label Tag', gridColumns: 6 } ]; + propertiesAccordionOptions: Array = [ + { value: 'showManager', label: 'Show Accordion Manager' }, + { value: 'expandItems', label: 'Expand Many Items' } + ]; + + typeTagOptions: Array = [ + { value: 'success', label: 'Success' }, + { value: 'warning', label: 'Warning' }, + { value: 'danger', label: 'Danger' }, + { value: 'info', label: 'Info' } + ]; + + disabledOption: Array = [{ value: 'disabled', label: 'Disabled' }]; + + properties: Array = []; + propertiesAccordion: Array = []; + disabledItem: Array = []; + accordionItemIndex: number; + customLiterals: PoAccordionLiterals; + literals: string; + typeTag: PoTagType; accordionItems: Array = []; ngOnInit() { @@ -19,12 +48,32 @@ export class SamplePoAccordionLabsComponent implements OnInit { } addAccordionItem(accordionItem: PoAccordionItemComponent) { + accordionItem.disabledItem = this.disabledItem.includes('disabled'); + if (accordionItem.labelTag) { + accordionItem.typeTag = this.typeTag; + } const newAccordionItem = Object.assign({}, accordionItem, { value: this.accordionItems.length }); this.accordionItems = [...this.accordionItems, newAccordionItem]; + this.disabledItem = []; + this.typeTag = undefined; + } + + changeLiterals() { + try { + this.customLiterals = JSON.parse(this.literals); + } catch { + this.customLiterals = undefined; + } } restore() { this.accordionItems = []; + this.customLiterals = undefined; + this.disabledItem = []; + this.literals = ''; + this.properties = []; + this.propertiesAccordion = []; + this.typeTag = undefined; } }