Skip to content

Commit d124f81

Browse files
arthur-polidoriopedrodominguesp
authored andcommitted
feat(dropdown): implementa criação de subníveis
Implementa criação de subníveis. Fixes: DTHFUI-12057
1 parent c7fda20 commit d124f81

21 files changed

+676
-61
lines changed

projects/ui/src/lib/components/po-dropdown/po-dropdown-action.interface.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,15 @@ import { PoPopupAction } from '../po-popup/po-popup-action.interface';
88
*
99
* @usedBy PoDropdownComponent
1010
*/
11-
export interface PoDropdownAction extends PoPopupAction {}
11+
export interface PoDropdownAction extends PoPopupAction {
12+
/**
13+
* Array de ações (`PoDropdownAction`) usado para criar agrupadores de subitens.
14+
*
15+
* - Permite a criação de menus aninhados (submenus).
16+
*
17+
* > Boas práticas de desenvolvimento:
18+
* Recomenda-se limitar a navegação a, no máximo, três níveis hierárquicos.
19+
* Isso evita sobrecarga cognitiva, facilita a memorização da estrutura e garante uma melhor experiência de uso.
20+
*/
21+
subItems?: Array<PoDropdownAction>;
22+
}

projects/ui/src/lib/components/po-dropdown/po-dropdown.component.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,6 @@
2626
[p-custom-positions]="['bottom-left', 'top-left']"
2727
[p-size]="size"
2828
[p-target]="dropdownRef"
29+
[p-listbox-subitems]="true"
2930
>
3031
</po-popup>

projects/ui/src/lib/components/po-dropdown/po-dropdown.component.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ import { PoDropdownBaseComponent } from './po-dropdown-base.component';
2222
* <file name="sample-po-dropdown-basic/sample-po-dropdown-basic.component.ts"> </file>
2323
* </example>
2424
*
25+
* <example name="po-dropdown-subitems" title="PO Dropdown Subitems" >
26+
* <file name="sample-po-dropdown-subitems/sample-po-dropdown-subitems.component.html"> </file>
27+
* <file name="sample-po-dropdown-subitems/sample-po-dropdown-subitems.component.ts"> </file>
28+
* </example>
29+
*
2530
* <example name="po-dropdown-labs" title="PO Dropdown Labs" >
2631
* <file name="sample-po-dropdown-labs/sample-po-dropdown-labs.component.html"> </file>
2732
* <file name="sample-po-dropdown-labs/sample-po-dropdown-labs.component.ts"> </file>
@@ -59,7 +64,7 @@ export class PoDropdownComponent extends PoDropdownBaseComponent {
5964
}
6065

6166
private checkClickArea(event: MouseEvent) {
62-
return this.dropdownRef && this.dropdownRef.nativeElement.contains(event.target);
67+
return this.dropdownRef?.nativeElement.contains(event.target);
6368
}
6469

6570
private hideDropdown() {

projects/ui/src/lib/components/po-dropdown/samples/sample-po-dropdown-labs/sample-po-dropdown-labs.component.html

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,28 @@
1212
<po-divider />
1313

1414
<form #formAction="ngForm">
15-
<po-input class="po-md-6 po-lg-4" name="actionAction" [(ngModel)]="action.action" p-clean p-label="Action">
15+
<po-input class="po-md-6 po-lg-4" name="actionLabel" [(ngModel)]="action.label" p-label="Label" p-required>
1616
</po-input>
1717

18-
<po-input class="po-md-6 po-lg-4" name="actionLabel" [(ngModel)]="action.label" p-label="Label" p-required>
18+
<po-input class="po-md-6 po-lg-4" name="actionAction" [(ngModel)]="action.action" p-clean p-label="Action">
1919
</po-input>
2020

2121
<po-input class="po-md-6 po-lg-4" name="actionURL" [(ngModel)]="action.url" p-label="URL"> </po-input>
2222

23-
<po-select class="po-md-6 po-lg-3" name="type" [(ngModel)]="action.type" p-label="Type" [p-options]="typeOptions">
23+
<po-select class="po-md-6 po-lg-4" name="type" [(ngModel)]="action.type" p-label="Type" [p-options]="typeOptions">
2424
</po-select>
2525

26-
<po-select class="po-md-6 po-lg-3" name="icon" [(ngModel)]="action.icon" p-label="Icon" [p-options]="iconOptions">
26+
<po-select class="po-md-6 po-lg-4" name="icon" [(ngModel)]="action.icon" p-label="Icon" [p-options]="iconOptions">
27+
</po-select>
28+
29+
<po-select
30+
class="po-md-6 po-lg-4"
31+
name="parent"
32+
[(ngModel)]="action.parent"
33+
p-label="Subitems"
34+
p-placeholder="Add subitems"
35+
[p-options]="parentList"
36+
>
2737
</po-select>
2838

2939
<po-checkbox-group

projects/ui/src/lib/components/po-dropdown/samples/sample-po-dropdown-labs/sample-po-dropdown-labs.component.ts

Lines changed: 64 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,9 @@ import {
1616
export class SamplePoDropdownLabsComponent implements OnInit {
1717
private poNotification = inject(PoNotificationService);
1818

19-
action: PoDropdownAction;
19+
action: PoDropdownAction & { parent?: string };
2020
actions: Array<PoDropdownAction>;
21+
parentList: Array<PoSelectOption>;
2122
label: string;
2223
properties: Array<string>;
2324
size: string;
@@ -52,16 +53,72 @@ export class SamplePoDropdownLabsComponent implements OnInit {
5253
this.restore();
5354
}
5455

55-
addAction(action: PoDropdownAction) {
56-
const newAction = Object.assign({}, action);
56+
addAction(action: PoDropdownAction & { parent?: string }) {
57+
const newAction: PoDropdownAction = { ...action };
5758
newAction.action = newAction.action ? this.showAction.bind(this, newAction.action) : undefined;
58-
this.actions.push(newAction);
59+
60+
if (!action.parent) {
61+
this.actions = [...this.actions, newAction];
62+
} else {
63+
const parentNode = this.getActionNode(this.actions, action.parent);
64+
if (parentNode) {
65+
parentNode.subItems = [...(parentNode.subItems || []), newAction];
66+
} else {
67+
this.actions = [...this.actions, newAction];
68+
}
69+
}
70+
71+
this.actions = [].concat(this.actions);
72+
this.parentList = this.updateParentList(this.actions);
5973

6074
this.restoreActionForm();
6175
}
6276

77+
private getActionNode(items: Array<PoDropdownAction>, value: string): PoDropdownAction | undefined {
78+
if (!items || !Array.isArray(items) || !value) {
79+
return undefined;
80+
}
81+
82+
for (const item of items) {
83+
if (item.label === value || (item as any).value === value) {
84+
return item;
85+
}
86+
87+
if (item.subItems && Array.isArray(item.subItems)) {
88+
const found = this.getActionNode(item.subItems, value);
89+
if (found) {
90+
return found;
91+
}
92+
}
93+
}
94+
95+
return undefined;
96+
}
97+
98+
private updateParentList(
99+
items: Array<PoDropdownAction>,
100+
level = 0,
101+
parentList: Array<PoSelectOption> = []
102+
): Array<PoSelectOption> {
103+
if (!items || !Array.isArray(items)) {
104+
return parentList;
105+
}
106+
107+
items.forEach(item => {
108+
const { label } = item;
109+
parentList.push({ label: `${'-'.repeat(level)} ${label}`, value: label });
110+
111+
if (item.subItems && Array.isArray(item.subItems)) {
112+
this.updateParentList(item.subItems, level + 1, parentList);
113+
}
114+
});
115+
116+
return parentList;
117+
}
118+
63119
restore() {
64120
this.actions = [];
121+
this.parentList = [];
65122
this.label = 'PO Dropdown';
66123
this.size = 'medium';
67124
this.properties = [];
@@ -71,8 +128,9 @@ export class SamplePoDropdownLabsComponent implements OnInit {
71128
restoreActionForm() {
72129
this.action = {
73130
label: undefined,
74-
visible: null
75-
};
131+
visible: null,
132+
parent: undefined
133+
} as any;
76134
}
77135

78136
showAction(label: string): void {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<po-dropdown p-label="PO Dropdown" [p-actions]="actions"> </po-dropdown>
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import { Component } from '@angular/core';
2+
import { PoDropdownAction } from '@po-ui/ng-components';
3+
4+
@Component({
5+
selector: 'sample-po-dropdown-subitems',
6+
templateUrl: './sample-po-dropdown-subitems.component.html',
7+
standalone: false
8+
})
9+
export class SamplePoDropdownSubitemsComponent {
10+
actions: Array<PoDropdownAction> = [
11+
{ label: 'New Sale', action: () => console.log('New Sale') },
12+
{ label: 'New Cancellation', action: () => console.log('New Cancellation'), type: 'danger' },
13+
{
14+
label: 'Reports',
15+
subItems: [
16+
{ label: 'Monthly Sales', action: () => console.log('Monthly Sales'), icon: 'an an-chart-line-up' },
17+
{ label: 'Annual Sales', action: () => console.log('Annual Sales'), icon: 'an an-chart-line-up' }
18+
]
19+
},
20+
{
21+
label: 'Settings',
22+
subItems: [
23+
{ label: 'Users', action: () => console.log('Users') },
24+
{
25+
label: 'System',
26+
subItems: [
27+
{ label: 'Backup', action: () => console.log('Backup') },
28+
{ label: 'Logs', action: () => console.log('Logs') }
29+
]
30+
}
31+
]
32+
}
33+
];
34+
}

projects/ui/src/lib/components/po-listbox/interfaces/po-listbox-literals.interface.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
* Interface para definição de literais utilizadas no `po-listbox`
77
*/
88
export interface PoListBoxLiterals {
9+
/** Texto do botão para voltar ao agrupador anterior. */
10+
backToPreviousGroup?: string;
11+
912
/** Texto exibido quando não houver itens na lista */
1013
noItems?: string;
1114

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ export class PoItemListBaseComponent {
5858
@Input('p-label') label: string;
5959

6060
/** Tamanho do texto exibido. */
61-
@Input('p-size') size: string;
61+
@HostBinding('attr.p-size')
62+
@Input('p-size')
63+
size: string;
6264

6365
/** Valor do item. */
6466
@Input('p-value') value: string;
@@ -118,6 +120,9 @@ export class PoItemListBaseComponent {
118120
*/
119121
@Input('p-icon') icon: string | TemplateRef<void>;
120122

123+
// Define a posição do ícone: 'left' (padrão) ou 'right'.
124+
@Input('p-icon-position') iconPosition: 'left' | 'right' = 'left';
125+
121126
/**
122127
* @optional
123128
*

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

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,18 @@
1212
[class.po-item-list__danger]="danger"
1313
class="po-item-list po-item-list__action"
1414
>
15-
@if (icon) {
16-
<po-icon class="po-popup-icon-item" [p-icon]="icon"></po-icon>
15+
@if (icon && iconPosition === 'left') {
16+
<po-icon
17+
class="po-popup-icon-item po-field-icon"
18+
[class.po-field-icon-aa]="size === 'small'"
19+
[p-icon]="icon"
20+
></po-icon>
1721
}
1822
<span class="po-item-list-label">{{ label }}</span>
23+
24+
@if (icon && iconPosition === 'right') {
25+
<po-icon class="po-popup-icon-item-right po-field-icon" [p-icon]="icon"></po-icon>
26+
}
1927
</div>
2028
}
2129
@case ('option') {

0 commit comments

Comments
 (0)