-
Notifications
You must be signed in to change notification settings - Fork 232
feat(context-menu): implementa po-context-menu, adiciona activatedTab/focusTab ao po-tabs #2780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
08e946f
0d55218
b9eb6df
547163e
05ed32e
b80eb03
0789567
96d3059
d9030ac
4f68058
ea91358
09691c2
2f7c815
c562a95
02a467d
2bec47e
18ec322
7460498
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -41,7 +41,7 @@ module.exports = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Resolve all methods and properties from the classDoc. Includes inherited docs. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| classDoc.methods = classDoc.methods.concat(this.resolveMethods(classDoc)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Concatena propriedades da classe atual | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentProperties = this.resolveProperties(classDoc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| classDoc.properties = classDoc.properties.concat(currentProperties); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -55,14 +55,14 @@ module.exports = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyMap.set(prop.name, prop); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| continue; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const hasOverrideTag = (prop.tags?.tags || []).some(tag => tag.tagName === 'override'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (hasOverrideTag) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyMap.set(prop.name, prop); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Converte o Map de volta para array e ordena | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| classDoc.properties = Array.from(propertyMap.values()).sort((a, b) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return a.name > b.name ? 1 : -1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -95,21 +95,11 @@ module.exports = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| processPropertyDoc: function (propertyDoc) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| this.processPublicDoc(propertyDoc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (propertyDoc.Input != undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.isDirectiveInput = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.directiveInputAlias = propertyDoc.directiveInputAlias || propertyDoc.Input; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.isDirectiveInput = this.isDirectiveInput(propertyDoc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.directiveInputAlias = this.getDirectiveInputAlias(propertyDoc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.isDirectiveInput = this.isDirectiveInput(propertyDoc) || propertyDoc.isDirectiveInput; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.directiveInputAlias = this.getDirectiveInputAlias(propertyDoc) || propertyDoc.directiveInputAlias; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (propertyDoc.Output != undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.isDirectiveOutput = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.directiveOutputAlias = propertyDoc.Output; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.isDirectiveOutput = this.isDirectiveOutput(propertyDoc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.directiveOutputAlias = this.getDirectiveOutputAlias(propertyDoc); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.isDirectiveOutput = this.isDirectiveOutput(propertyDoc) || propertyDoc.isDirectiveOutput; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| propertyDoc.directiveOutputAlias = this.getDirectiveOutputAlias(propertyDoc) || propertyDoc.directiveOutputAlias; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -130,13 +120,13 @@ module.exports = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| resolveProperties: function (classDoc) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| let properties = classDoc.members.filter(member => !member.hasOwnProperty('parameters')); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const inferTypeFromInput = codeLine => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const inferTypeFromCode = codeLine => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Extrai tipo genérico | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const genericMatch = codeLine.match(/input<([^>]+)>/); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const genericMatch = codeLine.match(/(?:input(?:\.required)?|output|model)<(.+)>(?=\s*\()/); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const genericRaw = genericMatch ? genericMatch[1].trim() : null; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Extrai valor passado como primeiro argumento | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const valueMatch = codeLine.match(/input(?:<[^>]+>)?\(\s*([^,)]*)/); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const valueMatch = codeLine.match(/(?:input(?:\.required)?|output|model)(?:<.+>)?\(\s*([^,)]*)/); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const value = valueMatch ? valueMatch[1].trim() : ''; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Extrai alias (entre aspas simples ou duplas) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -152,7 +142,7 @@ module.exports = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Tipo inferido por valor literal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (value === 'true' || value === 'false') return { type: 'boolean', alias }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (value.startsWith('"') || value.startsWith("'")) return { type: 'string', alias }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isNaN(Number(value))) return { type: 'number', alias }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (value !== '' && !isNaN(Number(value))) return { type: 'number', alias }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Fallback | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { type: 'unknown', alias }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -167,10 +157,20 @@ module.exports = { | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| property.isOptional = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (property.type.includes('input') && property.Input !== undefined) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { type, alias } = inferTypeFromInput(property.type); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Tratamento input e model no Signal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if ((property.type.includes('input') || property.type.includes('model'))) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { type, alias } = inferTypeFromCode(property.type); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| properties[index].type = type; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| properties[index].directiveInputAlias = alias; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| properties[index].isDirectiveInput = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
157
to
+166
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Docs processor does not classify model() signal properties as outputs Angular's
Suggested change
Was this helpful? React with 👍 or 👎 to provide feedback. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Tratamento output no Signal | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (property.type.includes('output')) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { type, alias } = inferTypeFromCode(property.type); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| properties[index].type = 'EventEmitter'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| properties[index].directiveOutputAlias = alias; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| properties[index].isDirectiveOutput = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 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,96 @@ | ||
| import { Directive, input, model, output } 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 | ||
| */ | ||
| contextTitle = input<string>('', { alias: 'p-context-title' }); | ||
|
|
||
| /** | ||
| * Titulo principal do menu | ||
| */ | ||
| 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: | ||
| * | ||
| * ```html | ||
| * <po-context-menu | ||
| * [(p-expanded)]="expanded" | ||
| * /> | ||
| * ``` | ||
| * | ||
| * ou | ||
| * | ||
| * ```html | ||
| * <po-context-menu | ||
| * [(p-expanded)]="expanded" | ||
| * (p-expandedChange)="handlerExpanded($event)" | ||
| * /> | ||
| * ``` | ||
| * | ||
| * @default `true` | ||
| */ | ||
| expanded = model<boolean>(true, { alias: 'p-expanded' }); | ||
|
|
||
| /** | ||
| * Evento emitido ao selecionar um item. Emite o item selecionado. | ||
| */ | ||
| itemSelected = output<PoContextMenuItem>({ alias: 'p-item-selected' }); | ||
| } |
| 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) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Using The template at Prompt for agentsWas 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)="$event.preventDefault(); 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> | ||
Uh oh!
There was an error while loading. Please reload this page.