Skip to content

Commit d7447e2

Browse files
deboraconstantinofabiana-monteiro
authored andcommitted
feat(progress): implementa variação circular
- Implementa variação circular para o componente po-progress - Cria nova propriedade p-shape para informar o tipo: bar ou circle - Cria nova propriedade p-radius para ser utilizada com conjunto com o tipo circle Fixes DTHFUI-12619
1 parent 3b6b58b commit d7447e2

20 files changed

Lines changed: 2016 additions & 138 deletions
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @usedBy PoProgressComponent
3+
*
4+
* @description
5+
*
6+
* Enum `PoProgressShape` para definir o formato visual do componente de progresso.
7+
*/
8+
export enum PoProgressShape {
9+
/** Formato barra de progresso (padrão). */
10+
bar = 'bar',
11+
/** Formato circular de progresso. */
12+
circle = 'circle'
13+
}

projects/ui/src/lib/components/po-progress/enums/po-progress-status.enum.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
*
44
* @description
55
*
6-
* *Enum* `PoProgressStatus` para os status de barra de progresso.
6+
* Enum `PoProgressStatus` para os status de barra de progresso.
77
*/
88
export enum PoProgressStatus {
99
/** Define o status `default` para a barra de progresso. */

projects/ui/src/lib/components/po-progress/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
export * from './enums/po-progress-shape.enum';
12
export * from './enums/po-progress-status.enum';
23
export * from './enums/po-progress-size.enum';
34

projects/ui/src/lib/components/po-progress/po-progress-bar/po-progress-bar.component.html

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
@if (!indeterminate) {
22
<div
33
role="progressbar"
4+
[attr.aria-label]="ariaLabel"
45
[attr.aria-valuenow]="value"
56
aria-valuemin="0"
67
aria-valuemax="100"
@@ -13,7 +14,14 @@
1314
}
1415

1516
@if (indeterminate) {
16-
<div class="po-progress-bar-indeterminate-track">
17+
<div
18+
class="po-progress-bar-indeterminate-track"
19+
role="progressbar"
20+
[attr.aria-label]="ariaLabel"
21+
aria-valuemin="0"
22+
aria-valuemax="100"
23+
aria-live="polite"
24+
>
1725
<div class="po-progress-bar-indeterminate-track-bar"></div>
1826
</div>
1927
}

projects/ui/src/lib/components/po-progress/po-progress-bar/po-progress-bar.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import { ChangeDetectionStrategy, Component, Input } from '@angular/core';
77
standalone: false
88
})
99
export class PoProgressBarComponent {
10+
@Input('p-aria-label') ariaLabel?: string;
11+
1012
@Input('p-indeterminate') indeterminate: boolean;
1113

1214
@Input('p-value') value: number;

projects/ui/src/lib/components/po-progress/po-progress-base.component.spec.ts

Lines changed: 96 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
1+
import { Component } from '@angular/core';
2+
import { ComponentFixture, TestBed } from '@angular/core/testing';
3+
14
import { PoThemeA11yEnum } from '../../services';
25
import { expectPropertiesValues } from '../../util-test/util-expect.spec';
36
import { convertToBoolean } from '../../utils/util';
47

58
import { PoProgressBaseComponent } from './po-progress-base.component';
69

10+
@Component({
11+
template: '',
12+
standalone: false
13+
})
14+
class TestHostComponent extends PoProgressBaseComponent {}
15+
716
describe('PoProgressBaseComponent:', () => {
8-
let component: PoProgressBaseComponent;
17+
let component: TestHostComponent;
18+
let fixture: ComponentFixture<TestHostComponent>;
919

1020
beforeEach(() => {
11-
component = new PoProgressBaseComponent();
21+
TestBed.configureTestingModule({
22+
declarations: [TestHostComponent]
23+
});
24+
25+
fixture = TestBed.createComponent(TestHostComponent);
26+
component = fixture.componentInstance;
27+
fixture.detectChanges();
1228
});
1329

1430
it('should be created', () => {
@@ -112,6 +128,84 @@ describe('PoProgressBaseComponent:', () => {
112128
expectPropertiesValues(component, 'value', validValues, 0);
113129
});
114130

131+
it('p-shape: should have default value as bar', () => {
132+
expect(component.shape()).toBe('bar');
133+
});
134+
135+
it('p-shape: should update with valid values', () => {
136+
fixture.componentRef.setInput('p-shape', 'bar');
137+
fixture.detectChanges();
138+
expect(component.shape()).toBe('bar');
139+
140+
fixture.componentRef.setInput('p-shape', 'circle');
141+
fixture.detectChanges();
142+
expect(component.shape()).toBe('circle');
143+
});
144+
145+
it('p-shape: should default to bar if has not valid values', () => {
146+
fixture.componentRef.setInput('p-shape', 'square');
147+
fixture.detectChanges();
148+
expect(component.shape()).toBe('bar');
149+
150+
fixture.componentRef.setInput('p-shape', 'triangle');
151+
fixture.detectChanges();
152+
expect(component.shape()).toBe('bar');
153+
154+
fixture.componentRef.setInput('p-shape', 'hexagon');
155+
fixture.detectChanges();
156+
expect(component.shape()).toBe('bar');
157+
});
158+
159+
it('p-radius: should have default value as 0', () => {
160+
expect(component.radius()).toBe(0);
161+
});
162+
163+
it('p-radius: should accept valid positive values', () => {
164+
fixture.componentRef.setInput('p-radius', 30);
165+
fixture.detectChanges();
166+
expect(component.radius()).toBe(30);
167+
168+
fixture.componentRef.setInput('p-radius', 60);
169+
fixture.detectChanges();
170+
expect(component.radius()).toBe(60);
171+
});
172+
173+
it('p-radius: should return 0 (default) for zero or negative values', () => {
174+
fixture.componentRef.setInput('p-radius', 0);
175+
fixture.detectChanges();
176+
expect(component.radius()).toBe(0);
177+
178+
fixture.componentRef.setInput('p-radius', -10);
179+
fixture.detectChanges();
180+
expect(component.radius()).toBe(0);
181+
});
182+
183+
it('p-radius: should apply minimum of 24 when value is positive but less than 24', () => {
184+
fixture.componentRef.setInput('p-radius', 19);
185+
fixture.detectChanges();
186+
expect(component.radius()).toBe(24);
187+
188+
fixture.componentRef.setInput('p-radius', 1);
189+
fixture.detectChanges();
190+
expect(component.radius()).toBe(24);
191+
});
192+
193+
it('p-radius: should convert string values to int', () => {
194+
fixture.componentRef.setInput('p-radius', '50');
195+
fixture.detectChanges();
196+
expect(component.radius()).toBe(50);
197+
});
198+
199+
it('p-radius: should return 0 for undefined or null values', () => {
200+
fixture.componentRef.setInput('p-radius', undefined);
201+
fixture.detectChanges();
202+
expect(component.radius()).toBe(0);
203+
204+
fixture.componentRef.setInput('p-radius', null);
205+
fixture.detectChanges();
206+
expect(component.radius()).toBe(0);
207+
});
208+
115209
it('should update property `p-size` with valid values', () => {
116210
const validValues = ['large', 'medium'];
117211

projects/ui/src/lib/components/po-progress/po-progress-base.component.ts

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
import { Directive, EventEmitter, HostBinding, HostListener, Input, Output, TemplateRef } from '@angular/core';
1+
import { Directive, EventEmitter, HostBinding, HostListener, Input, Output, TemplateRef, input } from '@angular/core';
22

33
import { convertToBoolean, convertToInt, getDefaultSizeFn, validateSizeFn } from '../../utils/util';
44

55
import { PoFieldSize } from '../../enums/po-field-size.enum';
6+
import { PoProgressShape } from './enums/po-progress-shape.enum';
67
import { PoProgressSize } from './enums/po-progress-size.enum';
78
import { PoProgressStatus } from './enums/po-progress-status.enum';
89
import { PoProgressAction } from './interfaces';
910

1011
const poProgressMaxValue = 100;
1112
const poProgressMinValue = 0;
13+
const CIRCLE_DEFAULT_RADIUS = 0;
14+
const CIRCLE_MIN_RADIUS = 24;
1215

1316
/**
1417
* @description
@@ -34,10 +37,24 @@ const poProgressMinValue = 0;
3437
* | **po-progress-bar** | | |
3538
* | `--background-color-tray` | Cor do background | `var(--color-brand-01-lightest)` |
3639
* | `--background-color-indicator` | Cor do background do indicador | `var(--color-action-default)` |
40+
* | **po-progress-circle** | | |
41+
* | `--background-color-tray` | Cor do background | `var(--color-brand-01-lightest)` |
42+
* | `--background-color-indicator` | Cor do background do indicador | `var(--color-action-default)` |
3743
*
3844
*/
3945
@Directive()
4046
export class PoProgressBaseComponent {
47+
/**
48+
* @optional
49+
*
50+
* @description
51+
*
52+
* Define um nome acessível para o elemento com `role="progressbar"`.
53+
*
54+
* Quando não informado, o componente utiliza o valor de `p-text` como alternativa, se disponível.
55+
*/
56+
@Input('p-aria-label') ariaLabel?: string;
57+
4158
/**
4259
* @optional
4360
*
@@ -48,6 +65,8 @@ export class PoProgressBaseComponent {
4865
* > Se nenhuma função for passada para o evento `(p-cancel)` ou a barra de progresso estiver com o status `PoProgressStatus.Success`,
4966
* o ícone de cancelamento não será exibido.
5067
*
68+
* > Não compatível com `p-shape="circle"`.
69+
*
5170
* @default `false`
5271
*/
5372
@Input({ alias: 'p-disabled-cancel', transform: convertToBoolean }) disabledCancel: boolean = false;
@@ -58,6 +77,8 @@ export class PoProgressBaseComponent {
5877
* @description
5978
*
6079
* Informação adicional que aparecerá abaixo da barra de progresso ao lado direito.
80+
*
81+
* > Não compatível com `p-shape="circle"`.
6182
*/
6283
@Input('p-info') info?: string;
6384

@@ -69,6 +90,8 @@ export class PoProgressBaseComponent {
6990
* Ícone que aparecerá ao lado do texto da propriedade `p-info`.
7091
*
7192
* Exemplo: `an an-check`.
93+
*
94+
* > Não compatível com `p-shape="circle"`.
7295
*/
7396
@Input('p-info-icon') infoIcon?: string | TemplateRef<void>;
7497

@@ -90,6 +113,8 @@ export class PoProgressBaseComponent {
90113
* @description
91114
*
92115
* Texto principal que aparecerá abaixo da barra de progresso no lado esquerdo.
116+
*
117+
* > Não compatível com `p-shape="circle"`.
93118
*/
94119
@Input('p-text') text?: string;
95120

@@ -107,6 +132,8 @@ export class PoProgressBaseComponent {
107132
* - **`disabled`**: Indica se o botão deve estar desabilitado (opcional).
108133
* - **`visible`**: Determina se o botão será exibido. Pode ser um valor booleano ou uma função que retorna um booleano (opcional).
109134
*
135+
* > Não compatível com `p-shape="circle"`.
136+
*
110137
* @example
111138
* **Exemplo de uso:**
112139
* ```html
@@ -144,6 +171,8 @@ export class PoProgressBaseComponent {
144171
* Evento emitido quando o botão definido em `p-custom-action` é clicado. Este evento retorna informações
145172
* relacionadas à barra de progresso ou ao arquivo/processo associado, permitindo executar ações específicas.
146173
*
174+
* > Não compatível com `p-shape="circle"`.
175+
*
147176
* @example
148177
* **Exemplo de uso:**
149178
*
@@ -185,6 +214,8 @@ export class PoProgressBaseComponent {
185214
*
186215
* > Se nenhuma função for passada para o evento ou a barra de progresso estiver com o status `PoProgressStatus.Success`,
187216
* o ícone de cancelamento não será exibido.
217+
*
218+
* > Não compatível com `p-shape="circle"`.
188219
*/
189220
@Output('p-cancel') cancel: EventEmitter<any> = new EventEmitter();
190221

@@ -197,6 +228,8 @@ export class PoProgressBaseComponent {
197228
*
198229
* > o ícone será exibido apenas se informar uma função neste evento e o status da barra de progresso for
199230
* `PoProgressStatus.Error`.
231+
*
232+
* > Não compatível com `p-shape="circle"`.
200233
*/
201234
@Output('p-retry') retry: EventEmitter<any> = new EventEmitter();
202235

@@ -206,6 +239,59 @@ export class PoProgressBaseComponent {
206239
private _sizeActions: string = undefined;
207240
private _initialSizeActions: string = undefined;
208241

242+
/**
243+
* @optional
244+
*
245+
* @description
246+
*
247+
* Define o formato visual do componente de progresso.
248+
*
249+
* Valores válidos:
250+
* - `bar`: exibe o progresso em formato de barra.
251+
* - `circle`: exibe o progresso em formato circular.
252+
*
253+
* @example
254+
* ```html
255+
* <po-progress p-shape="circle" [p-value]="50"></po-progress>
256+
* ```
257+
*
258+
* @default `bar`
259+
*/
260+
shape = input<string, string>(PoProgressShape.bar, {
261+
alias: 'p-shape',
262+
transform: (value: string) => (PoProgressShape[value] ? PoProgressShape[value] : PoProgressShape.bar)
263+
});
264+
265+
/**
266+
* @optional
267+
*
268+
* @description
269+
*
270+
* Define o raio do círculo SVG em pixels. Permite ao usuário customizar o tamanho
271+
* do indicador circular ao utilizar `p-shape="circle"`.
272+
*
273+
* > O valor mínimo aceito é **24**.
274+
*
275+
* > Quando não informado, o componente calcula o raio automaticamente a partir do container pai.
276+
* Caso o container pai não possua dimensões definidas, o valor padrão de **45** será utilizado.
277+
*
278+
* > Não compatível com `p-shape="bar"`.
279+
*
280+
* @default `45` (automático)
281+
*/
282+
radius = input<number, number>(CIRCLE_DEFAULT_RADIUS, {
283+
alias: 'p-radius',
284+
transform: (value: number) => {
285+
// Se nenhum valor foi fornecido (undefined/null), retorna 0 para indicar "não informado"
286+
if (value === undefined || value === null) {
287+
return CIRCLE_DEFAULT_RADIUS;
288+
}
289+
const intValue = convertToInt(value, CIRCLE_DEFAULT_RADIUS);
290+
// Quando o usuário informa um valor, aplica o mínimo de CIRCLE_MIN_RADIUS
291+
return intValue > 0 ? Math.max(intValue, CIRCLE_MIN_RADIUS) : CIRCLE_DEFAULT_RADIUS;
292+
}
293+
});
294+
209295
/**
210296
* @optional
211297
*
@@ -282,6 +368,8 @@ export class PoProgressBaseComponent {
282368
* > Caso a acessibilidade AA não esteja configurada, o tamanho `medium` será mantido.
283369
* Para mais detalhes, consulte a documentação do [po-theme](https://po-ui.io/documentation/po-theme).
284370
*
371+
* > Não compatível com `p-shape="circle"`.
372+
*
285373
* @default `medium`
286374
*/
287375
set sizeActions(value: string) {
@@ -302,6 +390,8 @@ export class PoProgressBaseComponent {
302390
*
303391
* Ativa a exibição da porcentagem atual da barra de progresso.
304392
*
393+
* > Se utilizada no `p-shape="circle"` e o status estiver como `error`, a porcentagem não será exibida.
394+
*
305395
* @default `false`
306396
*/
307397
@Input({ alias: 'p-show-percentage', transform: convertToBoolean }) showPercentage: boolean = false;

0 commit comments

Comments
 (0)