Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
08e946f
feat(context-menu): implementa componente po-context-menu
anderson-gregorio-totvs Mar 11, 2026
0d55218
fix(context-menu): corrige bugs e aplica melhorias de clean code
anderson-gregorio-totvs Mar 19, 2026
b9eb6df
feat(context-menu): implementa componente po-context-menu
anderson-gregorio-totvs Mar 19, 2026
547163e
feat(context-menu): implementa componente po-context-menu
anderson-gregorio-totvs Mar 19, 2026
05ed32e
feat(context-menu): adiciona exemplos basic e labs do po-context-menu
anderson-gregorio-totvs Mar 19, 2026
b80eb03
feat(context-menu): adiciona exemplos basic e labs do po-context-menu
anderson-gregorio-totvs Mar 23, 2026
0789567
build(docs): ajusta a geração da doc para output em signal
anderson-gregorio-totvs Mar 23, 2026
96d3059
feat(tabs): adiciona novas funcionalidades
anderson-gregorio-totvs Mar 23, 2026
d9030ac
docs(tabs): documenta activatedTab e focusTab, corrige NG0203 no spec
anderson-gregorio-totvs Mar 23, 2026
4f68058
fix(tabs): adiciona guard contra id inexistente em focusTab
anderson-gregorio-totvs Mar 23, 2026
ea91358
fix(docs): corrige inferência de tipo number para signals sem argumento
anderson-gregorio-totvs Mar 23, 2026
09691c2
fix(tabs): adiciona activatedTab nos mocks de teste e corrige typos n…
anderson-gregorio-totvs Mar 23, 2026
2f7c815
fix(context-menu): preventDefault no space e regex input.required
anderson-gregorio-totvs Mar 23, 2026
c562a95
feat(context-menu): implementa componente po-context-menu
anderson-gregorio-totvs Mar 11, 2026
02a467d
feat(tabs): adiciona novas funcionalidades
anderson-gregorio-totvs Mar 23, 2026
2bec47e
build(docs): ajusta a geração da doc para output em signal
anderson-gregorio-totvs Mar 23, 2026
18ec322
fix(context-menu): corrige evento expandedChange e regex generics
anderson-gregorio-totvs Mar 23, 2026
7460498
merge: resolve conflitos mantendo fixes locais
anderson-gregorio-totvs Mar 23, 2026
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
2 changes: 2 additions & 0 deletions projects/ui/src/lib/components/components.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { PoButtonModule } from './po-button/po-button.module';
import { PoCalendarModule } from './po-calendar/po-calendar.module';
import { PoChartModule } from './po-chart/po-chart.module';
import { PoContainerModule } from './po-container/po-container.module';
import { PoContextMenuModule } from './po-context-menu/po-context-menu.module';
import { PoDisclaimerGroupModule } from './po-disclaimer-group/po-disclaimer-group.module';
import { PoDisclaimerModule } from './po-disclaimer/po-disclaimer.module';
import { PoDividerModule } from './po-divider/po-divider.module';
Expand Down Expand Up @@ -61,6 +62,7 @@ const PO_MODULES = [
PoCalendarModule,
PoChartModule,
PoContainerModule,
PoContextMenuModule,
PoDisclaimerGroupModule,
PoDisclaimerModule,
PoDividerModule,
Expand Down
1 change: 1 addition & 0 deletions projects/ui/src/lib/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export * from './po-button/index';
export * from './po-calendar/index';
export * from './po-chart/index';
export * from './po-container/index';
export * from './po-context-menu/index';
export * from './po-disclaimer-group/index';
export * from './po-disclaimer/index';
export * from './po-divider/index';
Expand Down
3 changes: 3 additions & 0 deletions projects/ui/src/lib/components/po-context-menu/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export * from './po-context-menu-item.interface';
export * from './po-context-menu.component';
export * from './po-context-menu.module';
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { Directive, input, model } from '@angular/core';

import { PoContextMenuItem } from './po-context-menu-item.interface';

/**
* @description
*
* O componente `po-context-menu` e uma barra lateral de contexto (sidebar) para navegacao interna de modulos.
* Inspirado visualmente no `po-menu`, porem independente e focado em navegacao contextual.
*
* Quando estiver sendo utilizado o componente po-page-default, ambos devem estar no mesmo nível
* e inseridos em uma div com a classe **po-context-menu-wrapper**.
* Esta classe será responsável por fazer os cálculos necessários de alinhamento dos componentes.
*
* #### Tokens customizaveis
*
* E possivel alterar o estilo do componente usando os seguintes tokens (CSS):
*
* > Para maiores informacoes, acesse o guia [Personalizando o Tema Padrao com Tokens CSS](https://po-ui.io/guides/theme-customization).
*
* | Propriedade | Descricao | Valor Padrao |
* |----------------------------------------|--------------------------------------------------------------|-------------------------------------------------|
* | **Default Values** | | |
* | `--font-family` | Familia tipografica usada | `var(--font-family-theme)` |
* | `--font-size` | Tamanho da fonte dos itens | `var(--font-size-default)` |
* | `--font-size-context-title` | Tamanho da fonte do titulo de contexto | `var(--font-size-sm)` |
* | `--font-size-title` | Tamanho da fonte do titulo principal | `var(--font-size-lg)` |
* | `--line-height` | Altura da linha | `var(--line-height-md)` |
* | `--border-radius` | Raio dos cantos dos itens | `var(--border-radius-md)` |
* | `--border-color` | Cor da borda lateral direita do componente | `var(--color-neutral-light-20)` |
* | `--background-color` | Cor de fundo do componente | `var(--color-neutral-light-05)` |
* | `--color` | Cor do texto dos itens | `var(--color-action-default)` |
* | `--color-context-title` | Cor do texto do titulo de contexto | `var(--color-neutral-mid-40)` |
* | `--color-title` | Cor do texto do titulo principal | `var(--color-neutral-dark-80)` |
* | `--font-weight` | Peso da fonte dos itens | `var(--font-weight-bold)` |
* | `--font-weight-title` | Peso da fonte do titulo principal | `var(--font-weight-bold)` |
* | `--outline-color-focused` | Cor do outline no estado de focus | `var(--color-action-focus)` |
* | **Hover** | | |
* | `--color-hover` | Cor do texto no estado hover | `var(--color-brand-01-darkest)` |
* | `--background-color-hover` | Cor de fundo no estado hover | `var(--color-brand-01-lighter)` |
* | **Pressed** | | |
* | `--background-color-pressed` | Cor de fundo no estado pressed | `var(--color-brand-01-light)` |
* | **Active (Selected)** | | |
* | `--background-color-actived` | Cor de fundo do item selecionado | `var(--color-brand-01-lightest)` |
* | `--color-actived` | Cor do texto do item selecionado | `var(--color-action-pressed)` |
*
*/
@Directive()
export class PoContextMenuBaseComponent {
/** Titulo do contexto superior (ex: "Jornada"). */
contextTitle = input<string>('', { alias: 'p-context-title' });

/** Titulo principal do menu (ex: "Prestador de compra"). */
title = input<string>('', { alias: 'p-title' });

/**
* Lista de itens para renderizacao.
*
* > Ao receber os itens, o componente valida que apenas um item pode ter `selected: true`.
* > Se mais de um item estiver com `selected: true`, apenas o primeiro sera mantido como selecionado.
*/
items = input<Array<PoContextMenuItem>>([], { alias: 'p-items' });

/**
* Define se o menu estar aberto ou fechado.
*
* Suporta two-way binding:
* `[(p-expanded)]="expanded"`
*
* ou
*
* `
* [(p-expanded)]="expanded"
* (p-expandChange)="handlerExpanded($event)
* `
*
* @default `true`
* */
expanded = model<boolean>(true, { alias: 'p-expanded' });
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/**
* @usedBy PoContextMenuComponent
*
* @description
*
* Interface para os itens do componente po-context-menu.
*/
export interface PoContextMenuItem {
/** Texto do item de menu. */
label: string;

/** Acao executada ao clicar no item. */
action?: Function;

/** Estado de selecao do item. */
selected?: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
<div class="po-context-menu" [class.po-context-menu-collapsed]="!expanded()">
<div class="po-context-menu-header">
<button
class="po-context-menu-toggle"
type="button"
[attr.aria-label]="expanded() ? 'Recolher menu' : 'Expandir menu'"
(click)="toggleExpand()"
>
<po-icon [p-icon]="expanded() ? 'ICON_SIDEBAR' : 'ICON_SIDEBAR_SIMPLES'"></po-icon>
</button>

@if (expanded()) {
<div class="po-context-menu-header-content">
@if (contextTitle()) {
<span class="po-context-menu-context-title">{{ contextTitle() }}</span>
}
@if (title()) {
<span class="po-context-menu-title">{{ title() }}</span>
}
</div>
}
</div>

@if (expanded()) {
<nav class="po-context-menu-body">
<ul class="po-context-menu-list" role="menu">
@for (item of _items(); track item.label) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Using item.label as both @for track key and selection identifier breaks with duplicate labels

The template at po-context-menu.component.html:27 uses track item.label in the @for loop, and selectItem at po-context-menu.component.ts:59 matches items by i.label === item.label. If a consumer provides two items with the same label (e.g., [{label: 'Settings', action: fn1}, {label: 'Settings', action: fn2}]), two things break: (1) Angular's @for requires unique track values and will produce incorrect DOM diffing or runtime errors with duplicate keys, and (2) selectItem will mark ALL items sharing that label as selected: true, violating the single-selection invariant the component enforces elsewhere via sanitizeSelection.

Prompt for agents
In projects/ui/src/lib/components/po-context-menu/po-context-menu.component.html line 27, change `track item.label` to `track $index` (or add a unique `id` field to the PoContextMenuItem interface and use `track item.id`). Additionally, in projects/ui/src/lib/components/po-context-menu/po-context-menu.component.ts line 59 inside `selectItem`, change the matching from label-based (`i.label === item.label`) to index-based or identity-based matching to avoid selecting multiple items with the same label.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

<li
#itemRef
class="po-context-menu-list-item"
role="menuitem"
tabindex="0"
[class.po-context-menu-item-selected]="item.selected"
(click)="selectItem(item)"
(keydown.enter)="selectItem(item)"
(keydown.space)="selectItem(item)"
(mouseenter)="handlerTooltip(item, itemRef)"
p-tooltip-position="right"
[p-tooltip]="item.tooltip"
>
<span class="po-context-menu-item-label">{{ item.label }}</span>
</li>
}
</ul>
</nav>
}
</div>
Loading
Loading