@praxisui/tabs 8.0.0-beta.2 → 8.0.0-beta.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -12
- package/fesm2022/praxisui-tabs.mjs +1471 -98
- package/index.d.ts +119 -7
- package/package.json +8 -4
- package/src/lib/praxis-tabs-config-editor.json-api.md +597 -0
- package/src/lib/praxis-tabs.json-api.md +978 -0
- package/src/lib/quick-setup/tabs-quick-setup.json-api.md +491 -0
package/README.md
CHANGED
|
@@ -75,13 +75,46 @@ Inputs
|
|
|
75
75
|
- `componentInstanceId?: string` Opcional para desambiguar múltiplas instâncias com o mesmo `tabsId` na mesma rota.
|
|
76
76
|
- `form?: FormGroup` FormGroup opcional para campos dinâmicos declarados em `content`.
|
|
77
77
|
- `context?: any` Contexto propagado a widgets internos (via `DynamicWidgetLoader`).
|
|
78
|
+
- `selectedIndex?: number` Índice ativo controlado por composição; não reemite `selectedIndexChange`.
|
|
78
79
|
- `enableCustomization?: boolean` Exibe botão de edição quando verdadeiro (abre o editor).
|
|
79
80
|
|
|
80
81
|
Outputs
|
|
81
82
|
- `selectedIndexChange: number` Índice selecionado atualizado (ambos modos).
|
|
82
83
|
- `selectedTabChange: MatTabChangeEvent` Evento nativo do MatTabGroup.
|
|
83
84
|
- `focusChange, animationDone, indexFocused, selectFocusedIndex` Eventos nativos do Angular Material.
|
|
84
|
-
- `widgetEvent:
|
|
85
|
+
- `widgetEvent: WidgetEventEnvelope` Bridge avançada/legado para transporte de eventos dos widgets internos com contexto da aba/link. Para conexões novas de widgets internos, use `composition.links` com `component-port + nestedPath`.
|
|
86
|
+
|
|
87
|
+
## Uso Controlado por Composição
|
|
88
|
+
|
|
89
|
+
`selectedIndex` é a porta pública para controlar a aba ativa a partir de estado externo ou de outro componente. Quando esse input é aplicado, o componente atualiza a aba ativa sem reemitir `selectedIndexChange`, evitando ciclos entre `state -> selectedIndex` e `selectedIndexChange -> state`.
|
|
90
|
+
|
|
91
|
+
Padrão recomendado para páginas dinâmicas:
|
|
92
|
+
|
|
93
|
+
- grave a seleção do usuário com `selectedIndexChange -> state`;
|
|
94
|
+
- projete o estado de volta com `state -> selectedIndex`;
|
|
95
|
+
- declare `selectedIndex` depois de `config` em `bindingOrder`, para que a configuração seja carregada antes da seleção controlada;
|
|
96
|
+
- não persista `inputs.selectedIndex` estático em recipes quando a seleção vem de `composition.links`.
|
|
97
|
+
|
|
98
|
+
Quando existe configuração persistida por `tabsId`, o valor controlado por `selectedIndex` vence a restauração local depois do carregamento da config. Essa projeção controlada não grava uma nova preferência no storage; somente interações diretas do usuário persistem seleção. Isso mantém o estado canônico da composição como fonte de verdade da navegação ativa sem transformar navegação transitória em configuração salva. Em modo `nav`, o índice controla `nav.links`; em modo `group`, controla `tabs`.
|
|
99
|
+
|
|
100
|
+
Exemplo canônico:
|
|
101
|
+
|
|
102
|
+
```json
|
|
103
|
+
{
|
|
104
|
+
"links": [
|
|
105
|
+
{
|
|
106
|
+
"id": "tabs.selectedIndexChange->state.navigation.activeTabIndex",
|
|
107
|
+
"from": { "kind": "component-port", "ref": { "widget": "workspaceTabs", "port": "selectedIndexChange" } },
|
|
108
|
+
"to": { "kind": "state", "ref": { "path": "navigation.activeTabIndex", "layer": "values", "write": true } }
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"id": "state.navigation.activeTabIndex->tabs.selectedIndex",
|
|
112
|
+
"from": { "kind": "state", "ref": { "path": "navigation.activeTabIndex", "layer": "values" } },
|
|
113
|
+
"to": { "kind": "component-port", "ref": { "widget": "workspaceTabs", "port": "selectedIndex" } }
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
}
|
|
117
|
+
```
|
|
85
118
|
|
|
86
119
|
Persistência
|
|
87
120
|
- Quando `tabsId` é fornecido, a configuração é salva/recuperada em `AsyncConfigStorage` na chave `tabs:<component_id>`.
|
|
@@ -110,8 +143,8 @@ export interface TabsMetadata {
|
|
|
110
143
|
behavior?: { lazyLoad?: boolean; closeable?: boolean; reorderable?: boolean };
|
|
111
144
|
accessibility?: { highContrast?: boolean; reduceMotion?: boolean };
|
|
112
145
|
group?: { alignTabs?: 'start' | 'center' | 'end'; headerPosition?: 'above'|'below'; selectedIndex?: number; dynamicHeight?: boolean; disableRipple?: boolean; disablePagination?: boolean; fitInkBarToContent?: boolean; stretchTabs?: boolean; color?: 'primary'|'accent'|'warn'; backgroundColor?: 'primary'|'accent'|'warn'|undefined; animationDuration?: string; ariaLabel?: string; ariaLabelledby?: string; };
|
|
113
|
-
tabs?: Array<{ id?: string; textLabel?: string; disabled?: boolean; labelClass?: string|string[]; bodyClass?: string|string[]; content?: any[]; widgets?: WidgetDefinition[] }>;
|
|
114
|
-
nav?: { links: Array<{ id?: string; label: string; disabled?: boolean; content?: any[]; widgets?: WidgetDefinition[] }>; selectedIndex?: number; disableRipple?: boolean; disablePagination?: boolean; fitInkBarToContent?: boolean; stretchTabs?: boolean; color?: 'primary'|'accent'|'warn'; backgroundColor?: 'primary'|'accent'|'warn'|undefined; animationDuration?: string; ariaLabel?: string; ariaLabelledby?: string };
|
|
146
|
+
tabs?: Array<{ id?: string; textLabel?: string; icon?: string; disabled?: boolean; visible?: boolean; labelClass?: string|string[]; bodyClass?: string|string[]; content?: any[]; widgets?: WidgetDefinition[] }>;
|
|
147
|
+
nav?: { links: Array<{ id?: string; label: string; icon?: string; disabled?: boolean; visible?: boolean; content?: any[]; widgets?: WidgetDefinition[] }>; selectedIndex?: number; disableRipple?: boolean; disablePagination?: boolean; fitInkBarToContent?: boolean; stretchTabs?: boolean; color?: 'primary'|'accent'|'warn'; backgroundColor?: 'primary'|'accent'|'warn'|undefined; animationDuration?: string; ariaLabel?: string; ariaLabelledby?: string };
|
|
115
148
|
}
|
|
116
149
|
```
|
|
117
150
|
|
|
@@ -146,18 +179,58 @@ Quick Setup
|
|
|
146
179
|
- `openQuickSetup()` abre `TabsQuickSetupComponent` para criação rápida de abas/links.
|
|
147
180
|
- `applied$`/`saved$` aplicam a configuração ao componente.
|
|
148
181
|
|
|
182
|
+
## Agentic Authoring
|
|
183
|
+
|
|
184
|
+
`@praxisui/tabs` publica `PRAXIS_TABS_AUTHORING_MANIFEST` para orientar edições assistidas por IA sobre `TabsMetadata`.
|
|
185
|
+
|
|
186
|
+
- **Editable targets:** `tab`, `tabLabel`, `tabIcon`, `tabContent`, `activeTab`, `visibility`, `disabledState` e `layout`.
|
|
187
|
+
- **Operation families:** `tab.add`, `tab.remove`, `tab.label.set`, `tab.icon.set`, `tab.order.set`, `tab.disabled.set`, `tab.visible.set`, `tab.active.set`, `layout.variant.set` e `tab.content.set`.
|
|
188
|
+
- **Validation:** ids de abas/links devem ser estáveis e únicos, remoção destrutiva exige confirmação, `group` e `nav` não devem virar modos primários concorrentes, e o round-trip precisa preservar ordem, ids e selected index.
|
|
189
|
+
- **Runtime/editor parity:** `tabs[].icon`, `tabs[].visible`, `nav.links[].icon` e `nav.links[].visible` são campos canônicos editáveis; itens com `visible: false` não são renderizados na navegação.
|
|
190
|
+
- **Registry projection:** o manifesto é exportado no `public-api` e projetado em `components['praxis-tabs'].authoringManifest` pelo AI Registry.
|
|
191
|
+
|
|
192
|
+
### Praxis Semantic Assistant
|
|
193
|
+
|
|
194
|
+
When `enableCustomization=true`, `praxis-tabs` opens the shared `PraxisAiAssistantShellComponent` and registers a minimized global session instead of embedding the legacy `PraxisAiAssistantComponent`.
|
|
195
|
+
|
|
196
|
+
- The assistant context is safe and semantic: component identity, tabs id, current mode, tab/link counts, field-name digest, manifest reference and governance hints.
|
|
197
|
+
- Business-rule, policy, compliance, publication, materialization or enforcement prompts are routed to governed `domain-rules/intake` handoff and are not applied as local tabs configuration.
|
|
198
|
+
- Free JSON patches from the backend are rejected. Local apply remains blocked until the response is compiled from a manifest-backed `componentEditPlan` validated against `PRAXIS_TABS_AUTHORING_MANIFEST`.
|
|
199
|
+
- `TabsAiAdapter.applyPatch(...)` remains available for legacy/editor internals, but the new assistant turn flow does not use it as an ungoverned patch path.
|
|
200
|
+
|
|
149
201
|
## Eventos e Conexões
|
|
150
202
|
|
|
151
|
-
|
|
203
|
+
Para conexoes canonicas de widgets internos, use `composition.links` com endpoint `component-port + nestedPath`.
|
|
204
|
+
|
|
205
|
+
Exemplo de output de uma lista dentro da primeira tab:
|
|
206
|
+
|
|
207
|
+
```json
|
|
208
|
+
{
|
|
209
|
+
"kind": "component-port",
|
|
210
|
+
"ref": {
|
|
211
|
+
"widget": "tabs-widget",
|
|
212
|
+
"nestedPath": [
|
|
213
|
+
{ "kind": "tab", "id": "employees-list", "index": 0 },
|
|
214
|
+
{ "kind": "widget", "key": "employees-list", "componentType": "praxis-list" }
|
|
215
|
+
],
|
|
216
|
+
"port": "itemClick",
|
|
217
|
+
"direction": "output"
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Regras:
|
|
223
|
+
|
|
224
|
+
- `ref.widget` e a instancia top-level de `praxis-tabs`;
|
|
225
|
+
- `nestedPath` e relativo a essa instancia e deve terminar em `kind: "widget"` com `key` estavel;
|
|
226
|
+
- `ref.port` e a porta real do widget filho;
|
|
227
|
+
- inputs para filhos nested devem atualizar a configuracao declarativa do filho, nao depender de dot-path publico sobre `config`.
|
|
228
|
+
|
|
229
|
+
`widgetEvent` continua existindo como bridge avancada/legado para transporte de eventos internos com contexto da origem:
|
|
152
230
|
|
|
153
231
|
- Forma do evento: `{ tabId?, tabIndex?, linkId?, linkIndex?, sourceId, output?, payload }`.
|
|
154
|
-
-
|
|
155
|
-
|
|
156
|
-
- Map (exemplo tabela interna): `payload.payload.id`
|
|
157
|
-
- To: `<widget externo>.<input>`
|
|
158
|
-
- De fora para um componente interno (dot-path):
|
|
159
|
-
- Grupo: `inputs.config.tabs[<idx>].widgets[<widx>].inputs.<input>`
|
|
160
|
-
- Nav: `inputs.config.nav.links[<idx>].widgets[<widx>].inputs.<input>`
|
|
232
|
+
- Nao use `widgetEvent` como caminho principal para authoring novo de nested ports.
|
|
233
|
+
- Nao use dot-path de `config.tabs[].widgets[]` como contrato publico para novos links nested.
|
|
161
234
|
|
|
162
235
|
## Lazy Load
|
|
163
236
|
|
|
@@ -167,7 +240,7 @@ Quick Setup
|
|
|
167
240
|
## Exemplo Mínimo
|
|
168
241
|
|
|
169
242
|
```html
|
|
170
|
-
<praxis-tabs [config]="tabsCfg" [tabsId]="'cliente-tabs'" [enableCustomization]="true"
|
|
243
|
+
<praxis-tabs [config]="tabsCfg" [tabsId]="'cliente-tabs'" [enableCustomization]="true"></praxis-tabs>
|
|
171
244
|
```
|
|
172
245
|
|
|
173
246
|
```ts
|