Skip to content

Commit f18e38b

Browse files
committed
feat(search): adiciona variação locate com busca controlada
Adiciona a opção `p-filter-locate` para cenários em que o filtro e a navegação entre resultados são controlados externamente. Ao ser ativada, exibe contador e botões de navegação entre os resultados encontrados, que podem ser controlados por propriedades e eventos: `p-locate-summary`, `p-next-occurrence`, `p-previous-occurrence`, além dos eventos `p-keydown` e `p-blur` para controle via teclado. fixex DTHFUI-11133
1 parent 6e90f40 commit f18e38b

20 files changed

+1395
-426
lines changed

projects/ui/src/lib/components/po-listbox/po-item-list/po-item-list.component.spec.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { RouterTestingModule } from '@angular/router/testing';
44

55
import { PoItemListComponent } from './po-item-list.component';
66
import { PoItemListFilterMode } from '../enums/po-item-list-filter-mode.enum';
7+
import { PoFieldSize } from '../../../enums/po-field-size.enum';
78

89
describe('PoItemListComponent', () => {
910
let component: PoItemListComponent;
@@ -269,6 +270,46 @@ describe('PoItemListComponent', () => {
269270
expect(component.getLabelFormatted('values')).toBe('values');
270271
});
271272

273+
it('getLabelFormatted: should apply small size class for startsWith', () => {
274+
component.isFiltering = true;
275+
component.filterMode = PoItemListFilterMode.startsWith;
276+
component.size = PoFieldSize.Small;
277+
component.safeHtml = (value: any) => value;
278+
component.searchValue = 'val';
279+
280+
expect(component.getLabelFormatted('values')).toBe('<span class="po-font-text-bold">val</span>ues');
281+
});
282+
283+
it('getLabelFormatted: should apply small size class for contains', () => {
284+
component.isFiltering = true;
285+
component.filterMode = PoItemListFilterMode.contains;
286+
component.size = PoFieldSize.Small;
287+
component.safeHtml = (value: any) => value;
288+
component.searchValue = 'lue';
289+
290+
expect(component.getLabelFormatted('values')).toBe('va<span class="po-font-text-bold">lue</span>s');
291+
});
292+
293+
it('getLabelFormatted: should apply small size class for endsWith', () => {
294+
component.isFiltering = true;
295+
component.filterMode = PoItemListFilterMode.endsWith;
296+
component.size = PoFieldSize.Small;
297+
component.safeHtml = (value: any) => value;
298+
component.searchValue = 'lues';
299+
300+
expect(component.getLabelFormatted('values')).toBe('va<span class="po-font-text-bold">lues</span>');
301+
});
302+
303+
it('getLabelFormatted: should apply large size class when size is not small', () => {
304+
component.isFiltering = true;
305+
component.filterMode = PoItemListFilterMode.startsWith;
306+
component.size = PoFieldSize.Medium;
307+
component.safeHtml = (value: any) => value;
308+
component.searchValue = 'val';
309+
310+
expect(component.getLabelFormatted('values')).toBe('<span class="po-font-text-large-bold">val</span>ues');
311+
});
312+
272313
it('should format label when conditions are met', () => {
273314
component.isFiltering = true;
274315
component.compareCache = false;

projects/ui/src/lib/components/po-listbox/po-item-list/po-item-list.component.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { Component, ElementRef, OnChanges, SimpleChanges, ViewChild } from '@angular/core';
22
import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
33

4-
import { PoItemListOptionGroup } from './interfaces/po-item-list-option-group.interface';
4+
import { PoFieldSize } from '../../../enums/po-field-size.enum';
5+
import { PoItemListFilterMode } from '../enums/po-item-list-filter-mode.enum';
56
import { PoItemListOption } from './interfaces/po-item-list-option.interface';
67
import { PoItemListBaseComponent } from './po-item-list-base.component';
7-
import { PoItemListFilterMode } from '../enums/po-item-list-filter-mode.enum';
88

99
@Component({
1010
selector: 'po-item-list',
@@ -19,7 +19,7 @@ export class PoItemListComponent extends PoItemListBaseComponent implements OnCh
1919
protected param;
2020
protected clickListener: () => void;
2121

22-
constructor(private sanitized: DomSanitizer) {
22+
constructor(protected sanitized: DomSanitizer) {
2323
super();
2424
}
2525

@@ -70,7 +70,8 @@ export class PoItemListComponent extends PoItemListBaseComponent implements OnCh
7070
const labelInput = this.sanitizeTagHTML(this.searchValue.toString().toLowerCase());
7171
const labelLowerCase = sanitizedLabel.toLowerCase();
7272

73-
const openTagBold = '<span class="po-font-text-large-bold">';
73+
const highlightClass = this.size === PoFieldSize.Small ? 'po-font-text-bold' : 'po-font-text-large-bold';
74+
const openTagBold = `<span class="${highlightClass}">`;
7475
const closeTagBold = '</span>';
7576

7677
let startString;
@@ -79,7 +80,7 @@ export class PoItemListComponent extends PoItemListBaseComponent implements OnCh
7980

8081
switch (this.filterMode) {
8182
case PoItemListFilterMode.startsWith:
82-
case PoItemListFilterMode.contains:
83+
case PoItemListFilterMode.contains: {
8384
const indexOfLabelInput = labelLowerCase.indexOf(labelInput);
8485

8586
if (indexOfLabelInput > -1) {
@@ -92,7 +93,8 @@ export class PoItemListComponent extends PoItemListBaseComponent implements OnCh
9293
}
9394

9495
break;
95-
case PoItemListFilterMode.endsWith:
96+
}
97+
case PoItemListFilterMode.endsWith: {
9698
const lastIndexOfLabelInput = labelLowerCase.lastIndexOf(labelInput);
9799

98100
if (lastIndexOfLabelInput > -1) {
@@ -102,6 +104,7 @@ export class PoItemListComponent extends PoItemListBaseComponent implements OnCh
102104
format = startString + openTagBold + middleString + closeTagBold;
103105
}
104106
break;
107+
}
105108
}
106109
}
107110

@@ -117,6 +120,6 @@ export class PoItemListComponent extends PoItemListBaseComponent implements OnCh
117120
}
118121

119122
private sanitizeTagHTML(value: string = '') {
120-
return value.replace(/\</gm, '&lt;').replace(/\>/g, '&gt;');
123+
return value.replace(/</g, '&lt;').replace(/>/g, '&gt;');
121124
}
122125
}

projects/ui/src/lib/components/po-search/enums/po-search-filter-mode.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-
* Define o tipo de busca usado no po-search.
6+
* Define o tipo de busca usado no `po-search`.
77
*/
88
export enum PoSearchFilterMode {
99
/** Verifica se o texto *inicia* com o valor pesquisado. */

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ export * from './enums/po-search-filter-mode.enum';
66
export * from './interfaces/po-search-filter-select.interface';
77
export * from './interfaces/po-search-option.interface';
88

9-
export * from './literals/po-search-literals';
9+
export * from './literals/po-search-literals.interface';

projects/ui/src/lib/components/po-search/interfaces/po-search-filter-select.interface.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,7 @@
66
* Interface que define as opções que serão exibidas no dropdown do `po-search`, ao usar a propriedade `p-filter-select`.
77
*/
88
export interface PoSearchFilterSelect {
9-
/**
10-
* @description
11-
*
12-
* Descrição exibida nas opções da lista.
13-
*/
9+
/** Descrição exibida nas opções da lista. */
1410
label: string;
1511

1612
/** Valores que serão atribuídos ao `p-filter-keys` */
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @usedBy PoSearchComponent
3+
*
4+
* @description
5+
*
6+
* Interface que define o resumo de localização do filtro `p-filter-locate`.
7+
*/
8+
export interface PoSearchLocateSummary {
9+
/** Índice atual da ocorrência localizada. */
10+
currentIndex: number;
11+
12+
/** Total de ocorrências encontradas. */
13+
total: number;
14+
}
Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,44 @@
1-
import { PoSearchLiterals } from './po-search-literals';
1+
import { PoSearchLiterals } from './po-search-literals.interface';
22

33
export const poSearchLiteralsDefault = {
44
en: <PoSearchLiterals>{
55
search: 'Search',
6-
clean: 'Clean',
7-
all: 'All'
6+
clean: 'Clear search',
7+
all: 'All',
8+
of: 'of',
9+
next: 'Next result',
10+
previous: 'Previous result',
11+
result: 'Result',
12+
none: 'No results found'
813
},
914
es: <PoSearchLiterals>{
1015
search: 'Buscar',
11-
clean: 'limpiar',
12-
all: 'Todo'
16+
clean: 'Borrar búsqueda',
17+
all: 'Todo',
18+
of: 'de',
19+
next: 'Siguiente resultado',
20+
previous: 'Resultado anterior',
21+
result: 'Resultado',
22+
none: 'No hay resultados'
1323
},
1424
pt: <PoSearchLiterals>{
1525
search: 'Pesquisar',
16-
clean: 'Apagar',
17-
all: 'Todos'
26+
clean: 'Limpar busca',
27+
all: 'Todos',
28+
of: 'de',
29+
next: 'Próximo resultado',
30+
previous: 'Resultado anterior',
31+
result: 'Resultado',
32+
none: 'Nenhum resultado encontrado'
1833
},
1934
ru: <PoSearchLiterals>{
2035
search: 'Поиск',
21-
clean: 'чистый',
22-
all: 'Все'
36+
clean: 'Очистить поиск',
37+
all: 'Все',
38+
of: 'из',
39+
next: 'Следующий результат',
40+
previous: 'Предыдущий результат',
41+
result: 'Результат',
42+
none: 'Результаты не найдены'
2343
}
2444
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/**
2+
* @usedBy PoSearchComponent
3+
*
4+
* @description
5+
*
6+
* Interface para definição das literais usadas no `po-search`.
7+
*/
8+
export interface PoSearchLiterals {
9+
/** Texto exibido como *placeholder* no campo de busca. */
10+
search?: string;
11+
12+
/** Texto alternativo (aria-label) para o botão de limpar o campo de busca, usado por leitores de tela. */
13+
clean?: string;
14+
15+
/**
16+
* Texto exibido no dropdown de tipo de filtro, representando todos os tipos disponíveis.
17+
*
18+
* > Exibido apenas quando a propriedade `p-filter-select` estiver habilitada.
19+
*/
20+
all?: string;
21+
22+
/**
23+
* Texto alternativo (aria-label) para a palavra "de" no contador de resultados (ex: "Resultado 1 de 4").
24+
*
25+
* > Exibido apenas quando a propriedade `p-filter-locate` estiver habilitada.
26+
* */
27+
of?: string;
28+
29+
/**
30+
* Texto alternativo (aria-label) para navegação até o próximo resultado da busca.
31+
*
32+
* > Exibido apenas quando a propriedade `p-filter-locate` estiver habilitada.
33+
*/
34+
next?: string;
35+
36+
/** Texto alternativo (aria-label) para quando nenhum resultado for encontrado. */
37+
none?: string;
38+
39+
/**
40+
* Texto alternativo (aria-label) para navegação até o resultado anterior da busca.
41+
*
42+
* > Exibido apenas quando a propriedade `p-filter-locate` estiver habilitada.
43+
*/
44+
previous?: string;
45+
46+
/**
47+
* Texto alternativo (aria-label) para a label "Resultado" que acompanha o contador.
48+
*
49+
* > Exibido apenas quando a propriedade `p-filter-locate` estiver habilitada.
50+
*/
51+
result?: string;
52+
}

projects/ui/src/lib/components/po-search/literals/po-search-literals.ts

Lines changed: 0 additions & 34 deletions
This file was deleted.

0 commit comments

Comments
 (0)