@praxisui/tabs 9.0.0-beta.70 → 9.0.0-beta.72

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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-07-10T23:38:40.443Z",
3
+ "generatedAt": "2026-07-12T00:55:35.176Z",
4
4
  "packageName": "@praxisui/tabs",
5
- "packageVersion": "9.0.0-beta.70",
5
+ "packageVersion": "9.0.0-beta.72",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 1,
@@ -14,59 +14,81 @@
14
14
  {
15
15
  "name": "config",
16
16
  "type": "TabsMetadata",
17
- "required": false
17
+ "required": false,
18
+ "description": "Configuração JSON (tabs/nav, aparência e widgets internos)",
19
+ "label": "Configuração"
18
20
  },
19
21
  {
20
22
  "name": "tabsId",
21
23
  "type": "string",
22
- "required": false
24
+ "required": false,
25
+ "description": "Identificador para persistência (obrigatório)",
26
+ "label": "ID das Tabs"
23
27
  },
24
28
  {
25
29
  "name": "componentInstanceId",
26
30
  "type": "string",
27
- "required": false
31
+ "required": false,
32
+ "description": "Identificador opcional para múltiplas instâncias na mesma rota",
33
+ "label": "ID da instância"
28
34
  },
29
35
  {
30
36
  "name": "configPersistenceStrategy",
31
37
  "type": "\"storage-first\" | \"input-first\"",
32
- "required": false
38
+ "required": false,
39
+ "description": "Define se a configuração persistida ou a configuração de entrada governa a instância.",
40
+ "label": "Estratégia de persistência",
41
+ "default": "storage-first"
33
42
  },
34
43
  {
35
44
  "name": "selectedIndex",
36
45
  "type": "number",
37
- "required": false
46
+ "required": false,
47
+ "description": "Indice ativo de abas/nav controlavel externamente pela composicao. Para usar tabs como header de navegacao com conteudo externo, configure group.renderBody=false ou nav.renderBody=false.",
48
+ "label": "Indice selecionado"
38
49
  },
39
50
  {
40
51
  "name": "enableCustomization",
41
52
  "type": "boolean",
42
- "required": false
53
+ "required": false,
54
+ "description": "Habilita customização runtime via Settings Panel",
55
+ "label": "Modo de customização",
56
+ "default": false
43
57
  },
44
58
  {
45
59
  "name": "form",
46
60
  "type": "FormGroup",
47
- "required": false
61
+ "required": false,
62
+ "description": "FormGroup para conteúdo com campos dinâmicos",
63
+ "label": "FormGroup"
48
64
  },
49
65
  {
50
66
  "name": "context",
51
67
  "type": "Record<string, any>",
52
- "required": false
68
+ "required": false,
69
+ "description": "Contexto entregue aos widgets internos",
70
+ "label": "Contexto"
53
71
  }
54
72
  ],
55
73
  "outputs": [
56
74
  {
57
75
  "name": "selectedIndexChange",
58
76
  "type": "number",
59
- "required": false
77
+ "required": false,
78
+ "label": "Índice selecionado"
60
79
  },
61
80
  {
62
81
  "name": "configChange",
63
82
  "type": "TabsConfigChangeEvent",
64
- "required": false
83
+ "required": false,
84
+ "description": "Emite inputPatch.config quando uma autoria assistida altera TabsMetadata.",
85
+ "label": "Configuração alterada"
65
86
  },
66
87
  {
67
88
  "name": "selectedTabChange",
68
89
  "type": "MatTabChangeEvent",
69
- "required": false
90
+ "required": false,
91
+ "label": "Troca de aba"
70
92
  },
71
93
  {
72
94
  "name": "animationDone",
@@ -76,22 +98,27 @@
76
98
  {
77
99
  "name": "focusChange",
78
100
  "type": "MatTabChangeEvent",
79
- "required": false
101
+ "required": false,
102
+ "label": "Foco alterado"
80
103
  },
81
104
  {
82
105
  "name": "indexFocused",
83
106
  "type": "number",
84
- "required": false
107
+ "required": false,
108
+ "label": "Índice focado"
85
109
  },
86
110
  {
87
111
  "name": "selectFocusedIndex",
88
112
  "type": "number",
89
- "required": false
113
+ "required": false,
114
+ "label": "Selecionar foco"
90
115
  },
91
116
  {
92
117
  "name": "widgetEvent",
93
118
  "type": "WidgetEventEnvelope",
94
- "required": false
119
+ "required": false,
120
+ "description": "Eventos reemitidos de componentes dinâmicos dentro da aba/link, enriquecidos com contexto hierárquico em `path`.",
121
+ "label": "Evento interno"
95
122
  }
96
123
  ],
97
124
  "configSchemaId": null,
@@ -105,6 +132,208 @@
105
132
  "stable"
106
133
  ],
107
134
  "lib": "@praxisui/tabs",
135
+ "actions": [
136
+ {
137
+ "id": "select-tab",
138
+ "label": "Selecionar aba",
139
+ "icon": "tab",
140
+ "description": "Emite alteração do índice selecionado",
141
+ "emit": "selectedIndexChange",
142
+ "payloadSchema": {
143
+ "type": "number",
144
+ "example": 0
145
+ },
146
+ "scope": "any"
147
+ },
148
+ {
149
+ "id": "tab-change",
150
+ "label": "Troca de aba",
151
+ "icon": "swap_horiz",
152
+ "description": "Emite evento de troca de aba",
153
+ "emit": "selectedTabChange",
154
+ "payloadSchema": {
155
+ "type": "object",
156
+ "properties": {
157
+ "index": {
158
+ "type": "number",
159
+ "description": "Índice selecionado"
160
+ },
161
+ "tab": {
162
+ "type": "object",
163
+ "description": "Referência da aba"
164
+ }
165
+ },
166
+ "required": [
167
+ "index"
168
+ ],
169
+ "example": {
170
+ "index": 1
171
+ }
172
+ },
173
+ "scope": "any"
174
+ },
175
+ {
176
+ "id": "focus-change",
177
+ "label": "Foco alterado",
178
+ "icon": "center_focus_strong",
179
+ "description": "Emite evento quando o foco muda",
180
+ "emit": "focusChange",
181
+ "payloadSchema": {
182
+ "type": "object",
183
+ "properties": {
184
+ "index": {
185
+ "type": "number",
186
+ "description": "Índice focado"
187
+ },
188
+ "tab": {
189
+ "type": "object",
190
+ "description": "Referência da aba"
191
+ }
192
+ },
193
+ "required": [
194
+ "index"
195
+ ],
196
+ "example": {
197
+ "index": 1
198
+ }
199
+ },
200
+ "scope": "any"
201
+ },
202
+ {
203
+ "id": "focus-index",
204
+ "label": "Índice focado",
205
+ "icon": "filter_center_focus",
206
+ "description": "Emite o índice focado",
207
+ "emit": "indexFocused",
208
+ "payloadSchema": {
209
+ "type": "number",
210
+ "example": 0
211
+ },
212
+ "scope": "any"
213
+ },
214
+ {
215
+ "id": "select-focus",
216
+ "label": "Selecionar foco",
217
+ "icon": "gps_fixed",
218
+ "description": "Emite seleção do índice focado",
219
+ "emit": "selectFocusedIndex",
220
+ "payloadSchema": {
221
+ "type": "number",
222
+ "example": 0
223
+ },
224
+ "scope": "any"
225
+ }
226
+ ],
227
+ "ports": [
228
+ {
229
+ "id": "context",
230
+ "label": "Contexto",
231
+ "direction": "input",
232
+ "semanticKind": "view-context",
233
+ "schema": {
234
+ "id": "Record<string, unknown>",
235
+ "kind": "ts-type",
236
+ "ref": "Record<string, unknown>"
237
+ },
238
+ "description": "Contexto de visualizacao entregue ao container e aos widgets internos.",
239
+ "exposure": {
240
+ "public": true,
241
+ "group": "context"
242
+ }
243
+ },
244
+ {
245
+ "id": "config",
246
+ "label": "Configuracao",
247
+ "direction": "input",
248
+ "semanticKind": "config-fragment",
249
+ "schema": {
250
+ "id": "TabsMetadata",
251
+ "kind": "ts-type",
252
+ "ref": "TabsMetadata"
253
+ },
254
+ "description": "Fragmento canonico de configuracao das tabs/nav e dos widgets internos.",
255
+ "exposure": {
256
+ "public": true,
257
+ "group": "config"
258
+ }
259
+ },
260
+ {
261
+ "id": "selectedIndex",
262
+ "label": "Indice selecionado",
263
+ "direction": "input",
264
+ "semanticKind": "value",
265
+ "schema": {
266
+ "id": "number",
267
+ "kind": "ts-type",
268
+ "ref": "number"
269
+ },
270
+ "description": "Indice ativo de abas/nav para controle externo por composicao.",
271
+ "exposure": {
272
+ "public": true,
273
+ "group": "state"
274
+ }
275
+ },
276
+ {
277
+ "id": "selectedIndexChange",
278
+ "label": "Troca de indice selecionado",
279
+ "direction": "output",
280
+ "semanticKind": "event",
281
+ "schema": {
282
+ "id": "number",
283
+ "kind": "ts-type",
284
+ "ref": "number"
285
+ },
286
+ "cardinality": "stream",
287
+ "description": "Evento canonico emitido quando a selecao de aba muda.",
288
+ "exposure": {
289
+ "public": true,
290
+ "group": "events"
291
+ }
292
+ },
293
+ {
294
+ "id": "configChange",
295
+ "label": "Configuracao alterada",
296
+ "direction": "output",
297
+ "semanticKind": "event",
298
+ "schema": {
299
+ "id": "TabsConfigChangeEvent",
300
+ "kind": "ts-type",
301
+ "ref": "TabsConfigChangeEvent"
302
+ },
303
+ "cardinality": "stream",
304
+ "description": "Evento canonico emitido quando autoria assistida altera TabsMetadata; carrega inputPatch.config para persistencia pelo host.",
305
+ "exposure": {
306
+ "public": true,
307
+ "group": "config"
308
+ }
309
+ },
310
+ {
311
+ "id": "widgetEvent",
312
+ "label": "Evento interno de widget",
313
+ "direction": "output",
314
+ "semanticKind": "event",
315
+ "schema": {
316
+ "id": "WidgetEventEnvelope",
317
+ "kind": "ts-type",
318
+ "ref": "WidgetEventEnvelope"
319
+ },
320
+ "cardinality": "stream",
321
+ "description": "Bridge composta temporaria para eventos internos de widgets. Nao representa o contrato final de nested ports.",
322
+ "exposure": {
323
+ "public": true,
324
+ "advanced": true,
325
+ "group": "composite"
326
+ }
327
+ }
328
+ ],
329
+ "configEditor": {
330
+ "component": "[ref:PraxisTabsWidgetConfigEditor]",
331
+ "title": "Configure tabs"
332
+ },
333
+ "authoringManifestRef": {
334
+ "componentId": "praxis-tabs",
335
+ "source": "PRAXIS_TABS_AUTHORING_MANIFEST"
336
+ },
108
337
  "source": "projects/praxis-tabs/src/lib/praxis-tabs.metadata.ts",
109
338
  "exportName": "PRAXIS_TABS_COMPONENT_METADATA",
110
339
  "componentCapabilities": [
@@ -2008,7 +2237,7 @@
2008
2237
  "chunkIndex": 0,
2009
2238
  "chunkKind": "summary",
2010
2239
  "content": "Component ID: praxis-tabs\nSelector: praxis-tabs\nFriendly Name: Praxis Tabs\nDescription: Abas dinâmicas baseadas em metadata, com MatTabGroup/TabNav e suporte a tokens M3 via appearance.\nLib/Package: @praxisui/tabs\nTags: widget, tabs, configurable, stable\nInputs:\n - config (TabsMetadata)\n - tabsId (string)\n - componentInstanceId (string)\n - configPersistenceStrategy (\"storage-first\" | \"input-first\")\n - selectedIndex (number)\n - enableCustomization (boolean)\n - form (FormGroup)\n - context (Record<string, any>)\nOutputs:\n - selectedIndexChange (number)\n - configChange (TabsConfigChangeEvent)\n - selectedTabChange (MatTabChangeEvent)\n - animationDone (void)\n - focusChange (MatTabChangeEvent)\n - indexFocused (number)\n - selectFocusedIndex (number)\n - widgetEvent (WidgetEventEnvelope)\n",
2011
- "sourcePointer": "praxis-ui-angular/projects/praxis-tabs/src/lib/praxis-tabs.metadata.ts",
2240
+ "sourcePointer": "projects/praxis-tabs/src/lib/praxis-tabs.metadata.ts",
2012
2241
  "contentHash": "6ac4b5aa11ec48aec174a401af754d8d8efbee3e8e69402342098c6e1b91ce15",
2013
2242
  "sourceKind": "component_definition",
2014
2243
  "sourceId": "praxis-tabs",
@@ -2018,7 +2247,7 @@
2018
2247
  "chunkIndex": 1,
2019
2248
  "chunkKind": "capabilities",
2020
2249
  "content": "Component Capabilities:\n - Path: meta\n Category: meta\n Kind: object\n Description: Metadata bag for tabs.\n - Path: appearance\n Category: appearance\n Kind: object\n Description: Appearance settings.\n - Path: appearance.density\n Category: appearance\n Kind: enum\n Description: Density preset.\n - Path: appearance.themeClass\n Category: appearance\n Kind: string\n Description: Theme CSS class applied to root.\n - Path: appearance.customCss\n Category: appearance\n Kind: string\n Description: Custom CSS injected into component.\n - Path: appearance.tokens\n Category: appearance\n Kind: object\n Description: Style tokens mapped to runtime CSS.\n - Path: behavior\n Category: behavior\n Kind: object\n Description: Behavior settings.\n - Path: behavior.lazyLoad\n Category: behavior\n Kind: boolean\n Description: Lazy load tab content.\n - Path: behavior.closeable\n Category: behavior\n Kind: boolean\n Description: Show close button on tabs.\n - Path: behavior.reorderable\n Category: behavior\n Kind: boolean\n Description: Allow reorder tabs/links.\n - Path: accessibility\n Category: accessibility\n Kind: object\n Description: Accessibility settings.\n - Path: accessibility.highContrast\n Category: accessibility\n Kind: boolean\n Description: High contrast mode.\n - Path: accessibility.reduceMotion\n Category: accessibility\n Kind: boolean\n Description: Reduce motion.\n - Path: group\n Category: group\n Kind: object\n Description: MatTabGroup settings.\n - Path: group.alignTabs\n Category: group\n Kind: enum\n Description: Align tabs in header.\n - Path: group.animationDuration\n Category: group\n Kind: string\n Description: Animation duration (e.g., 500ms).\n - Path: group.ariaLabel\n Category: group\n Kind: string\n Description: aria-label for tab group.\n - Path: group.ariaLabelledby\n Category: group\n Kind: string\n Description: aria-labelledby for tab group.\n - Path: group.color\n Category: group\n Kind: enum\n Description: M2 color.\n - Path: group.backgroundColor\n Category: group\n Kind: enum\n Description: M2 background color.\n - Path: group.disablePagination\n Category: group\n Kind: boolean\n Description: Disable pagination of header.\n - Path: group.disableRipple\n Category: group\n Kind: boolean\n Description: Disable ripple.\n - Path: group.dynamicHeight\n Category: group\n Kind: boolean\n Description: Enable dynamic height.\n - Path: group.fitInkBarToContent\n Category: group\n Kind: boolean\n Description: Fit ink bar to content.\n - Path: group.headerPosition\n Category: group\n Kind: enum\n Description: Header position.\n - Path: group.preserveContent\n Category: group\n Kind: boolean\n Description: Preserve content of inactive tabs.\n - Path: group.selectedIndex\n Category: group\n Kind: number\n Description: Selected tab index.\n - Path: group.stretchTabs\n Category: group\n Kind: boolean\n Description: Stretch tabs.\n - Path: nav\n Category: nav\n Kind: object\n Description: Tab nav settings.\n - Path: nav.animationDuration\n Category: nav\n Kind: string\n Description: Animation duration (e.g., 500ms).\n - Path: nav.ariaLabel\n Category: nav\n Kind: string\n Description: aria-label for nav mode.\n - Path: nav.ariaLabelledby\n Category: nav\n Kind: string\n Description: aria-labelledby for nav mode.\n - Path: nav.color\n Category: nav\n Kind: enum\n Description: M2 color.\n - Path: nav.backgroundColor\n Category: nav\n Kind: enum\n Description: M2 background color.\n - Path: nav.disablePagination\n Category: nav\n Kind: boolean\n Description: Disable pagination of nav.\n - Path: nav.disableRipple\n Category: nav\n Kind: boolean\n Description: Disable ripple.\n - Path: nav.fitInkBarToContent\n Category: nav\n Kind: boolean\n Description: Fit ink bar to content.\n - Path: nav.selectedIndex\n Category: nav\n Kind: number\n Description: Selected nav link index.\n - Path: nav.stretchTabs\n Category: nav\n Kind: boolean\n Description: Stretch nav tabs.\n - Path: nav.links\n Category: nav\n Kind: array\n Description: Nav links array.\n - Path: nav.links[].id\n Category: nav\n Kind: string\n Description: Link id.\n - Path: nav.links[].label\n Category: nav\n Kind: string\n Description: Link label.\n - Path: nav.links[].active\n Category: nav\n Kind: boolean\n Description: Link active flag.\n - Path: nav.links[].disabled\n Category: nav\n Kind: boolean\n Description: Disable link.\n - Path: nav.links[].disableRipple\n Category: nav\n Kind: boolean\n Description: Disable ripple on link.\n - Path: nav.links[].fitInkBarToContent\n Category: nav\n Kind: boolean\n Description: Fit ink bar to link content.\n - Path: nav.links[].content\n Category: nav\n Kind: array\n Description: Dynamic field metadata list.\n - Path: nav.links[].widgets\n Category: nav\n Kind: array\n Description: Widget definitions for link content.\n - Path: tabs\n Category: tabs\n Kind: array\n Description: Tabs array.\n - Path: tabs[].id\n Category: tabs\n Kind: string\n Description: Tab id.\n - Path: tabs[].textLabel\n Category: tabs\n Kind: string\n Description: Tab label.\n - Path: tabs[].labelClass\n Category: tabs\n Kind: string\n Description: Label class (string or string[]).\n - Path: tabs[].bodyClass\n Category: tabs\n Kind: string\n Description: Body class (string or string[]).\n - Path: tabs[].ariaLabel\n Category: tabs\n Kind: string\n Description: aria-label for tab.\n - Path: tabs[].ariaLabelledby\n Category: tabs\n Kind: string\n Description: aria-labelledby for tab.\n - Path: tabs[].disabled\n Category: tabs\n Kind: boolean\n Description: Disable tab.\n - Path: tabs[].content\n Category: tabs\n Kind: array\n Description: Dynamic field metadata list.\n - Path: tabs[].widgets\n Category: tabs\n Kind: array\n Description: Widget definitions for tab content.\n - Path: tabs[].isActive\n Category: tabs\n Kind: boolean\n Description: Active flag (metadata only).\n - Path: tabs[].origin\n Category: tabs\n Kind: number\n Description: Origin index (metadata only).\n - Path: tabs[].position\n Category: tabs\n Kind: number\n Description: Position index (metadata only).\n - Path: events\n Category: events\n Kind: object\n Description: Event config (placeholder).\nCapability Notes:\n - TabsMetadata drives both group and nav modes. Use nav.* when links are present.\n - appearance.customCss is injected into a <style> tag; avoid unsafe CSS from untrusted sources.\n - tabs[].content expects DynamicFieldMetadata[] and widgets[] expects WidgetDefinition[].\n",
2021
- "sourcePointer": "praxis-ui-angular/projects/praxis-tabs/src/lib/ai/tabs-ai-capabilities.ts",
2250
+ "sourcePointer": "projects/praxis-tabs/src/lib/ai/tabs-ai-capabilities.ts",
2022
2251
  "contentHash": "d06a68f06350b762c479c7debd5eb5b844ef46f99f0cecb289ee3a5d65bc7310",
2023
2252
  "sourceKind": "component_definition",
2024
2253
  "sourceId": "praxis-tabs",
@@ -2028,7 +2257,7 @@
2028
2257
  "chunkIndex": 2,
2029
2258
  "chunkKind": "authoring_manifest",
2030
2259
  "content": "{\n \"schemaVersion\": \"1.0.0\",\n \"componentId\": \"praxis-tabs\",\n \"ownerPackage\": \"@praxisui/tabs\",\n \"configSchemaId\": \"TabsMetadata\",\n \"manifestVersion\": \"1.0.0\",\n \"runtimeInputs\": [\n {\n \"name\": \"config\",\n \"type\": \"TabsMetadata\",\n \"description\": \"Canonical tabs/nav configuration.\"\n },\n {\n \"name\": \"tabsId\",\n \"type\": \"string\",\n \"description\": \"Stable id used to derive persistence scope.\"\n },\n {\n \"name\": \"componentInstanceId\",\n \"type\": \"string\",\n \"description\": \"Optional instance discriminator for persistence scope.\"\n },\n {\n \"name\": \"configPersistenceStrategy\",\n \"type\": \"\\\"storage-first\\\" | \\\"input-first\\\"\",\n \"description\": \"Controls whether persisted customization or explicit input config governs the runtime. Governed previews with nested widgets should use input-first.\"\n },\n {\n \"name\": \"form\",\n \"type\": \"FormGroup\",\n \"description\": \"FormGroup consumed by dynamic field content.\"\n },\n {\n \"name\": \"context\",\n \"type\": \"Record<string, any>\",\n \"description\": \"Context passed to nested widgets.\"\n },\n {\n \"name\": \"enableCustomization\",\n \"type\": \"boolean\",\n \"description\": \"Enables Settings Panel authoring surfaces.\"\n }\n ],\n \"editableTargets\": [\n {\n \"kind\": \"tab\",\n \"resolver\": \"tab-by-id-or-label\",\n \"description\": \"A group-mode tab in config.tabs[].\"\n },\n {\n \"kind\": \"tabLabel\",\n \"resolver\": \"tab-by-id-or-label\",\n \"description\": \"The text label of a group-mode tab.\"\n },\n {\n \"kind\": \"tabIcon\",\n \"resolver\": \"tab-by-id-or-label\",\n \"description\": \"Icon metadata rendered in a group tab label.\"\n },\n {\n \"kind\": \"tabContent\",\n \"resolver\": \"tab-or-link-by-id\",\n \"description\": \"Dynamic fields or widgets hosted by a tab or nav link.\"\n },\n {\n \"kind\": \"activeTab\",\n \"resolver\": \"tab-index-or-id\",\n \"description\": \"Selected tab or nav link index.\"\n },\n {\n \"kind\": \"visibility\",\n \"resolver\": \"tab-or-link-by-id\",\n \"description\": \"Runtime visibility flag for a group tab or nav link.\"\n },\n {\n \"kind\": \"disabledState\",\n \"resolver\": \"tab-or-link-by-id\",\n \"description\": \"Disabled state of a tab or nav link.\"\n },\n {\n \"kind\": \"layout\",\n \"resolver\": \"tabs-layout-config\",\n \"description\": \"Group/nav mode, header position, density, stretch and behavior settings.\"\n },\n {\n \"kind\": \"renderBody\",\n \"resolver\": \"tabs-render-body-config\",\n \"description\": \"Config paths group.renderBody and nav.renderBody that let the host own external body content.\"\n }\n ],\n \"operations\": [\n {\n \"operationId\": \"tab.add\",\n \"title\": \"Add tab\",\n \"scope\": \"global\",\n \"targetKind\": \"tab\",\n \"target\": {\n \"kind\": \"tab\",\n \"resolver\": \"tabs-array\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": false\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"id\",\n \"textLabel\"\n ],\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"textLabel\": {\n \"type\": \"string\"\n },\n \"icon\": {\n \"type\": \"string\"\n },\n \"disabled\": {\n \"type\": \"boolean\"\n },\n \"visible\": {\n \"type\": \"boolean\",\n \"default\": true\n },\n \"content\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"widgets\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\"\n }\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"append-unique\",\n \"path\": \"tabs[]\",\n \"key\": \"id\"\n }\n ],\n \"validators\": [\n \"tab-id-unique\",\n \"tabs-mode-compatible\",\n \"tab-content-valid\"\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"affectedPaths\": [\n \"tabs[]\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\"\n ]\n },\n {\n \"operationId\": \"tab.remove\",\n \"title\": \"Remove tab\",\n \"scope\": \"layout\",\n \"targetKind\": \"tab\",\n \"target\": {\n \"kind\": \"tab\",\n \"resolver\": \"tab-by-id-or-label\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"replacementActiveTabId\": {\n \"type\": \"string\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"tabs.remove-tab-and-reselect\",\n \"handlerContract\": {\n \"reads\": [\n \"tabs[]\",\n \"group.selectedIndex\"\n ],\n \"writes\": [\n \"tabs[]\",\n \"group.selectedIndex\"\n ],\n \"identityKeys\": [\n \"tabs[].id\"\n ],\n \"inputSchema\": {\n \"type\": \"object\",\n \"properties\": {\n \"replacementActiveTabId\": {\n \"type\": \"string\"\n }\n }\n },\n \"failureModes\": [\n \"target-tab-missing\",\n \"replacement-tab-missing\",\n \"confirmation-missing\"\n ],\n \"description\": \"Removes the target tab by stable id and reselects a safe replacement when the active/default tab is removed.\"\n }\n }\n ],\n \"destructive\": true,\n \"requiresConfirmation\": true,\n \"validators\": [\n \"tab-exists\",\n \"active-tab-removal-safe\",\n \"tab-content-removal-confirmed\"\n ],\n \"affectedPaths\": [\n \"tabs[]\",\n \"group.selectedIndex\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\",\n \"target-tab-exists\",\n \"confirmation-collected\"\n ]\n },\n {\n \"operationId\": \"tab.label.set\",\n \"title\": \"Set tab label\",\n \"scope\": \"layout\",\n \"targetKind\": \"tabLabel\",\n \"target\": {\n \"kind\": \"tabLabel\",\n \"resolver\": \"tab-by-id-or-label\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"textLabel\"\n ],\n \"properties\": {\n \"textLabel\": {\n \"type\": \"string\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"merge-by-key\",\n \"path\": \"tabs[]\",\n \"key\": \"id\"\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"tab-exists\",\n \"tab-label-valid\"\n ],\n \"affectedPaths\": [\n \"tabs[].textLabel\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\",\n \"target-tab-exists\"\n ]\n },\n {\n \"operationId\": \"tab.icon.set\",\n \"title\": \"Set tab icon\",\n \"scope\": \"layout\",\n \"targetKind\": \"tabIcon\",\n \"target\": {\n \"kind\": \"tabIcon\",\n \"resolver\": \"tab-by-id-or-label\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"icon\"\n ],\n \"properties\": {\n \"icon\": {\n \"type\": \"string\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"merge-by-key\",\n \"path\": \"tabs[]\",\n \"key\": \"id\"\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"tab-exists\",\n \"tab-icon-valid\"\n ],\n \"affectedPaths\": [\n \"tabs[].icon\"\n ],\n \"submissionImpact\": \"visual-only\",\n \"preconditions\": [\n \"config-initialized\",\n \"target-tab-exists\"\n ]\n },\n {\n \"operationId\": \"tab.order.set\",\n \"title\": \"Reorder tabs\",\n \"scope\": \"layout\",\n \"targetKind\": \"tab\",\n \"target\": {\n \"kind\": \"tab\",\n \"resolver\": \"tab-by-id-or-label\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"beforeTabId\"\n ],\n \"properties\": {\n \"beforeTabId\": {\n \"type\": \"string\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"tabs.reorder-tab-and-preserve-selection\",\n \"handlerContract\": {\n \"reads\": [\n \"tabs[]\",\n \"group.selectedIndex\"\n ],\n \"writes\": [\n \"tabs[]\",\n \"group.selectedIndex\"\n ],\n \"identityKeys\": [\n \"tabs[].id\"\n ],\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"beforeTabId\"\n ],\n \"properties\": {\n \"beforeTabId\": {\n \"type\": \"string\"\n }\n }\n },\n \"failureModes\": [\n \"target-tab-missing\",\n \"before-tab-missing\",\n \"unstable-tab-id\"\n ],\n \"description\": \"Reorders tabs by stable id and remaps group.selectedIndex when the selected tab crosses positions.\"\n }\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"tab-exists\",\n \"tab-order-deterministic\"\n ],\n \"affectedPaths\": [\n \"tabs[]\",\n \"group.selectedIndex\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\",\n \"target-tab-exists\"\n ]\n },\n {\n \"operationId\": \"tab.disabled.set\",\n \"title\": \"Set tab disabled state\",\n \"scope\": \"interaction\",\n \"targetKind\": \"disabledState\",\n \"target\": {\n \"kind\": \"disabledState\",\n \"resolver\": \"tab-or-link-by-id\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"disabled\"\n ],\n \"properties\": {\n \"disabled\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"tabs.set-tab-or-link-disabled\",\n \"handlerContract\": {\n \"reads\": [\n \"tabs[]\",\n \"nav.links[]\",\n \"group.selectedIndex\",\n \"nav.selectedIndex\"\n ],\n \"writes\": [\n \"tabs[].disabled\",\n \"nav.links[].disabled\"\n ],\n \"identityKeys\": [\n \"tabs[].id\",\n \"nav.links[].id\"\n ],\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"disabled\"\n ],\n \"properties\": {\n \"disabled\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"failureModes\": [\n \"target-tab-or-link-missing\",\n \"ambiguous-target\",\n \"active-item-disabled-without-reselection\"\n ],\n \"description\": \"Sets disabled on the resolved group tab or nav link without guessing between modes.\"\n }\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"tab-or-link-exists\",\n \"active-tab-disabled-safe\"\n ],\n \"affectedPaths\": [\n \"tabs[].disabled\",\n \"nav.links[].disabled\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\",\n \"target-tab-or-link-exists\"\n ]\n },\n {\n \"operationId\": \"tab.visible.set\",\n \"title\": \"Set tab visibility\",\n \"scope\": \"interaction\",\n \"targetKind\": \"visibility\",\n \"target\": {\n \"kind\": \"visibility\",\n \"resolver\": \"tab-or-link-by-id\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"visible\"\n ],\n \"properties\": {\n \"visible\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"tabs.set-tab-or-link-visible\",\n \"handlerContract\": {\n \"reads\": [\n \"tabs[]\",\n \"nav.links[]\",\n \"group.selectedIndex\",\n \"nav.selectedIndex\"\n ],\n \"writes\": [\n \"tabs[].visible\",\n \"nav.links[].visible\"\n ],\n \"identityKeys\": [\n \"tabs[].id\",\n \"nav.links[].id\"\n ],\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"visible\"\n ],\n \"properties\": {\n \"visible\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"failureModes\": [\n \"target-tab-or-link-missing\",\n \"ambiguous-target\",\n \"active-item-hidden-without-reselection\"\n ],\n \"description\": \"Sets visible on the resolved group tab or nav link and preserves deterministic visible-index mapping.\"\n }\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"tab-or-link-exists\",\n \"active-tab-visibility-safe\"\n ],\n \"affectedPaths\": [\n \"tabs[].visible\",\n \"nav.links[].visible\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\",\n \"target-tab-or-link-exists\"\n ]\n },\n {\n \"operationId\": \"tab.active.set\",\n \"title\": \"Set active tab\",\n \"scope\": \"interaction\",\n \"targetKind\": \"activeTab\",\n \"target\": {\n \"kind\": \"activeTab\",\n \"resolver\": \"tab-index-or-id\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"selectedIndex\"\n ],\n \"properties\": {\n \"selectedIndex\": {\n \"type\": \"number\"\n },\n \"tabId\": {\n \"type\": \"string\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"tabs.set-active-item\",\n \"handlerContract\": {\n \"reads\": [\n \"tabs[]\",\n \"nav.links[]\",\n \"group.selectedIndex\",\n \"nav.selectedIndex\"\n ],\n \"writes\": [\n \"group.selectedIndex\",\n \"nav.selectedIndex\"\n ],\n \"identityKeys\": [\n \"tabs[].id\",\n \"nav.links[].id\"\n ],\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"selectedIndex\"\n ],\n \"properties\": {\n \"selectedIndex\": {\n \"type\": \"number\"\n },\n \"tabId\": {\n \"type\": \"string\"\n }\n }\n },\n \"failureModes\": [\n \"target-tab-or-link-missing\",\n \"selected-index-out-of-range\",\n \"hidden-or-disabled-target\"\n ],\n \"description\": \"Sets the active index for the current primary mode using either selectedIndex or a resolved tab/link id.\"\n }\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"active-tab-exists\",\n \"selected-index-in-range\"\n ],\n \"affectedPaths\": [\n \"group.selectedIndex\",\n \"nav.selectedIndex\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\",\n \"target-tab-or-link-exists\"\n ]\n },\n {\n \"operationId\": \"layout.variant.set\",\n \"title\": \"Set tabs layout variant\",\n \"scope\": \"layout\",\n \"targetKind\": \"layout\",\n \"target\": {\n \"kind\": \"layout\",\n \"resolver\": \"tabs-layout-config\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"required\": [\n \"mode\"\n ],\n \"properties\": {\n \"mode\": {\n \"enum\": [\n \"group\",\n \"nav\"\n ]\n },\n \"density\": {\n \"enum\": [\n \"compact\",\n \"comfortable\",\n \"spacious\"\n ]\n },\n \"headerPosition\": {\n \"enum\": [\n \"above\",\n \"below\"\n ]\n },\n \"alignTabs\": {\n \"enum\": [\n \"start\",\n \"center\",\n \"end\"\n ]\n },\n \"stretchTabs\": {\n \"type\": \"boolean\"\n },\n \"lazyLoad\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"merge-object\",\n \"path\": \"appearance\"\n },\n {\n \"kind\": \"merge-object\",\n \"path\": \"group\"\n },\n {\n \"kind\": \"merge-object\",\n \"path\": \"nav\"\n },\n {\n \"kind\": \"merge-object\",\n \"path\": \"behavior\"\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"tabs-mode-compatible\",\n \"layout-values-valid\",\n \"editor-runtime-round-trip\"\n ],\n \"affectedPaths\": [\n \"appearance.density\",\n \"group.headerPosition\",\n \"group.alignTabs\",\n \"group.stretchTabs\",\n \"nav.stretchTabs\",\n \"behavior.lazyLoad\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\"\n ]\n },\n {\n \"operationId\": \"tab.content.set\",\n \"title\": \"Set tab content\",\n \"scope\": \"layout\",\n \"targetKind\": \"tabContent\",\n \"target\": {\n \"kind\": \"tabContent\",\n \"resolver\": \"tab-or-link-by-id\",\n \"ambiguityPolicy\": \"fail\",\n \"required\": true\n },\n \"inputSchema\": {\n \"type\": \"object\",\n \"minProperties\": 1,\n \"properties\": {\n \"id\": {\n \"type\": \"string\"\n },\n \"textLabel\": {\n \"type\": \"string\"\n },\n \"icon\": {\n \"type\": \"string\"\n },\n \"disabled\": {\n \"type\": \"boolean\"\n },\n \"visible\": {\n \"type\": \"boolean\"\n },\n \"content\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\"\n }\n },\n \"widgets\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\"\n }\n }\n }\n },\n \"effects\": [\n {\n \"kind\": \"compile-domain-patch\",\n \"handler\": \"tabs.set-tab-or-link-content\",\n \"handlerContract\": {\n \"reads\": [\n \"tabs[]\",\n \"nav.links[]\"\n ],\n \"writes\": [\n \"tabs[].content\",\n \"tabs[].widgets\",\n \"nav.links[].content\",\n \"nav.links[].widgets\"\n ],\n \"identityKeys\": [\n \"tabs[].id\",\n \"nav.links[].id\"\n ],\n \"failureModes\": [\n \"target-tab-or-link-missing\",\n \"invalid-dynamic-field-content\",\n \"invalid-widget-definition\"\n ],\n \"description\": \"Updates content/widgets only on the resolved group tab or nav link while preserving nested widget identity.\"\n }\n }\n ],\n \"destructive\": false,\n \"requiresConfirmation\": false,\n \"validators\": [\n \"tab-or-link-exists\",\n \"tab-content-valid\",\n \"widget-event-delegated\"\n ],\n \"affectedPaths\": [\n \"tabs[].content\",\n \"tabs[].widgets\",\n \"nav.links[].content\",\n \"nav.links[].widgets\"\n ],\n \"submissionImpact\": \"config-only\",\n \"preconditions\": [\n \"config-initialized\",\n \"target-tab-or-link-exists\"\n ]\n }\n ],\n \"validators\": [\n {\n \"validatorId\": \"tab-id-unique\",\n \"level\": \"error\",\n \"code\": \"PTABS001\",\n \"description\": \"Tab ids and nav link ids must be unique within their mode.\"\n },\n {\n \"validatorId\": \"tab-exists\",\n \"level\": \"error\",\n \"code\": \"PTABS002\",\n \"description\": \"Target tab must exist before applying the operation.\"\n },\n {\n \"validatorId\": \"tab-or-link-exists\",\n \"level\": \"error\",\n \"code\": \"PTABS003\",\n \"description\": \"Target must resolve to an existing group tab or nav link.\"\n },\n {\n \"validatorId\": \"active-tab-exists\",\n \"level\": \"error\",\n \"code\": \"PTABS004\",\n \"description\": \"Active tab or nav link selection must reference an existing item.\"\n },\n {\n \"validatorId\": \"selected-index-in-range\",\n \"level\": \"error\",\n \"code\": \"PTABS005\",\n \"description\": \"Selected index must be clamped to the target mode item count.\"\n },\n {\n \"validatorId\": \"active-tab-removal-safe\",\n \"level\": \"error\",\n \"code\": \"PTABS006\",\n \"description\": \"Removing the active/default tab requires confirmation or a replacement active tab.\"\n },\n {\n \"validatorId\": \"tab-content-removal-confirmed\",\n \"level\": \"error\",\n \"code\": \"PTABS007\",\n \"description\": \"Removing a tab or link with content/widgets is destructive and requires confirmation.\"\n },\n {\n \"validatorId\": \"tab-label-valid\",\n \"level\": \"error\",\n \"code\": \"PTABS008\",\n \"description\": \"Tab labels must be non-empty text values after localization/domain projection.\"\n },\n {\n \"validatorId\": \"tab-icon-valid\",\n \"level\": \"warning\",\n \"code\": \"PTABS009\",\n \"description\": \"Tab icon metadata must remain compatible with the icon directive and editor round-trip.\"\n },\n {\n \"validatorId\": \"tab-order-deterministic\",\n \"level\": \"error\",\n \"code\": \"PTABS010\",\n \"description\": \"Tab ordering must use stable ids, not transient array index as identity.\"\n },\n {\n \"validatorId\": \"tabs-mode-compatible\",\n \"level\": \"error\",\n \"code\": \"PTABS011\",\n \"description\": \"Authoring must resolve to one primary mode: group tabs or nav links.\"\n },\n {\n \"validatorId\": \"layout-values-valid\",\n \"level\": \"error\",\n \"code\": \"PTABS012\",\n \"description\": \"Layout values must match TabsMetadata enums and runtime bindings.\"\n },\n {\n \"validatorId\": \"editor-runtime-round-trip\",\n \"level\": \"error\",\n \"code\": \"PTABS013\",\n \"description\": \"Settings Panel, quick setup, JSON editor and runtime must preserve ids, order and selected index.\"\n },\n {\n \"validatorId\": \"active-tab-disabled-safe\",\n \"level\": \"warning\",\n \"code\": \"PTABS014\",\n \"description\": \"Disabling the active item should move selection or request explicit confirmation.\"\n },\n {\n \"validatorId\": \"active-tab-visibility-safe\",\n \"level\": \"warning\",\n \"code\": \"PTABS015\",\n \"description\": \"Hiding the active item should move selection or request explicit confirmation.\"\n },\n {\n \"validatorId\": \"tab-content-valid\",\n \"level\": \"error\",\n \"code\": \"PTABS016\",\n \"description\": \"Tab content must be valid DynamicFieldMetadata[] or WidgetDefinition[] and preserve nested widget identity.\"\n },\n {\n \"validatorId\": \"widget-event-delegated\",\n \"level\": \"info\",\n \"code\": \"PTABS017\",\n \"description\": \"Nested widget event paths remain delegated to the tabs runtime contract and are not redefined by authoring.\"\n }\n ],\n \"roundTripRequirements\": [\n \"Operations must preserve stable tab/link ids; array index may be used only as a resolver fallback, never as canonical identity.\",\n \"Settings Panel, quick setup and JSON editor must round-trip through TabsAuthoringDocument without losing config or bindings.\",\n \"Group and nav modes must remain mutually explicit; authoring cannot silently mix config.tabs and nav.links as competing primary modes.\",\n \"Nested widget events remain delegated through widgetEvent path enrichment and component-port nestedPath semantics.\"\n ],\n \"examples\": [\n {\n \"id\": \"add-overview-tab\",\n \"request\": \"Add an Overview tab before the details tab.\",\n \"operationId\": \"tab.add\",\n \"params\": {\n \"id\": \"overview\",\n \"textLabel\": \"Overview\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"add-list-to-current-tab\",\n \"request\": \"Create a list widget inside the current training tab.\",\n \"operationId\": \"tab.content.set\",\n \"target\": \"training\",\n \"params\": {\n \"widgets\": [\n {\n \"id\": \"training-list\",\n \"component\": \"praxis-list\",\n \"title\": \"Training list\"\n }\n ]\n },\n \"isPositive\": true\n },\n {\n \"id\": \"add-form-fields-to-existing-tab\",\n \"request\": \"Add name, date and status fields to the existing onboarding tab.\",\n \"operationId\": \"tab.content.set\",\n \"target\": \"onboarding\",\n \"params\": {\n \"content\": [\n {\n \"name\": \"name\",\n \"label\": \"Name\",\n \"controlType\": \"text\"\n },\n {\n \"name\": \"plannedDate\",\n \"label\": \"Planned date\",\n \"controlType\": \"date\"\n },\n {\n \"name\": \"status\",\n \"label\": \"Status\",\n \"controlType\": \"select\"\n }\n ]\n },\n \"isPositive\": true\n },\n {\n \"id\": \"rename-tab\",\n \"request\": \"Rename the details tab to Account Details.\",\n \"operationId\": \"tab.label.set\",\n \"target\": \"details\",\n \"params\": {\n \"textLabel\": \"Account Details\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"reorder-tabs\",\n \"request\": \"Move billing before overview.\",\n \"operationId\": \"tab.order.set\",\n \"target\": \"billing\",\n \"params\": {\n \"beforeTabId\": \"overview\"\n },\n \"isPositive\": true\n },\n {\n \"id\": \"disable-tab\",\n \"request\": \"Disable the audit tab until the user has permission.\",\n \"operationId\": \"tab.disabled.set\",\n \"target\": \"audit\",\n \"params\": {\n \"disabled\": true\n },\n \"isPositive\": true\n },\n {\n \"id\": \"activate-tab\",\n \"request\": \"Open the documents tab by default.\",\n \"operationId\": \"tab.active.set\",\n \"target\": \"documents\",\n \"params\": {\n \"tabId\": \"documents\",\n \"selectedIndex\": 2\n },\n \"isPositive\": true\n },\n {\n \"id\": \"reject-duplicate-tab-id\",\n \"request\": \"Add another tab with id overview.\",\n \"operationId\": \"tab.add\",\n \"params\": {\n \"id\": \"overview\",\n \"textLabel\": \"Duplicate Overview\"\n },\n \"isPositive\": false\n },\n {\n \"id\": \"reject-current-tab-content-as-tab-add\",\n \"request\": \"Create a list in this tab; do not add a new tab.\",\n \"operationId\": \"tab.add\",\n \"params\": {\n \"id\": \"list-in-this-tab\",\n \"textLabel\": \"List in this tab\"\n },\n \"isPositive\": false\n },\n {\n \"id\": \"confirm-remove-content-tab\",\n \"request\": \"Remove the details tab that contains widgets.\",\n \"operationId\": \"tab.remove\",\n \"target\": \"details\",\n \"params\": {\n \"replacementActiveTabId\": \"overview\"\n },\n \"isPositive\": true\n }\n ]\n}",
2031
- "sourcePointer": "praxis-ui-angular/projects/praxis-tabs/src/lib/ai/praxis-tabs-authoring-manifest.ts",
2260
+ "sourcePointer": "projects/praxis-tabs/src/lib/ai/praxis-tabs-authoring-manifest.ts",
2032
2261
  "contentHash": "e47f82449d83a025be71346a144a6ce74884c2f28326bd415d7cd2b6133c4868",
2033
2262
  "sourceKind": "component_definition",
2034
2263
  "sourceId": "praxis-tabs",
@@ -2038,7 +2267,7 @@
2038
2267
  "chunkIndex": 3,
2039
2268
  "chunkKind": "context_pack",
2040
2269
  "content": "{\n \"componentContext\": {\n \"version\": \"v1\",\n \"optionsByPath\": {\n \"appearance.density\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"compact\",\n \"label\": \"Compact\"\n },\n {\n \"value\": \"comfortable\",\n \"label\": \"Comfortable\"\n },\n {\n \"value\": \"spacious\",\n \"label\": \"Spacious\"\n }\n ]\n },\n \"group.alignTabs\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"start\",\n \"label\": \"Start\"\n },\n {\n \"value\": \"center\",\n \"label\": \"Center\"\n },\n {\n \"value\": \"end\",\n \"label\": \"End\"\n }\n ]\n },\n \"group.headerPosition\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"above\",\n \"label\": \"Above\"\n },\n {\n \"value\": \"below\",\n \"label\": \"Below\"\n }\n ]\n },\n \"group.color\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"primary\",\n \"label\": \"Primary\"\n },\n {\n \"value\": \"accent\",\n \"label\": \"Accent\"\n },\n {\n \"value\": \"warn\",\n \"label\": \"Warn\"\n }\n ]\n },\n \"group.backgroundColor\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"primary\",\n \"label\": \"Primary\"\n },\n {\n \"value\": \"accent\",\n \"label\": \"Accent\"\n },\n {\n \"value\": \"warn\",\n \"label\": \"Warn\"\n }\n ]\n },\n \"nav.color\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"primary\",\n \"label\": \"Primary\"\n },\n {\n \"value\": \"accent\",\n \"label\": \"Accent\"\n },\n {\n \"value\": \"warn\",\n \"label\": \"Warn\"\n }\n ]\n },\n \"nav.backgroundColor\": {\n \"mode\": \"enum\",\n \"options\": [\n {\n \"value\": \"primary\",\n \"label\": \"Primary\"\n },\n {\n \"value\": \"accent\",\n \"label\": \"Accent\"\n },\n {\n \"value\": \"warn\",\n \"label\": \"Warn\"\n }\n ]\n }\n },\n \"actionCatalog\": [\n {\n \"id\": \"appearance.density.set\",\n \"intentExamples\": [\n \"density\",\n \"compact\",\n \"spacious\"\n ],\n \"patchTemplate\": {\n \"appearance\": {\n \"density\": \"{{value}}\"\n }\n }\n },\n {\n \"id\": \"group.alignTabs.set\",\n \"intentExamples\": [\n \"align tabs\",\n \"tab alignment\",\n \"align header\"\n ],\n \"patchTemplate\": {\n \"group\": {\n \"alignTabs\": \"{{value}}\"\n }\n }\n },\n {\n \"id\": \"group.headerPosition.set\",\n \"intentExamples\": [\n \"header position\",\n \"tabs position\"\n ],\n \"patchTemplate\": {\n \"group\": {\n \"headerPosition\": \"{{value}}\"\n }\n }\n },\n {\n \"id\": \"group.selectedIndex.set\",\n \"intentExamples\": [\n \"select tab\",\n \"active tab\",\n \"selected index\"\n ],\n \"patchTemplate\": {\n \"group\": {\n \"selectedIndex\": \"{{value}}\"\n }\n }\n },\n {\n \"id\": \"nav.selectedIndex.set\",\n \"intentExamples\": [\n \"select link\",\n \"active link\",\n \"selected nav\"\n ],\n \"patchTemplate\": {\n \"nav\": {\n \"selectedIndex\": \"{{value}}\"\n }\n }\n },\n {\n \"id\": \"behavior.lazyLoad.enable\",\n \"intentExamples\": [\n \"lazy load\",\n \"load on demand\",\n \"lazy\"\n ],\n \"patchTemplate\": {\n \"behavior\": {\n \"lazyLoad\": true\n }\n }\n },\n {\n \"id\": \"behavior.lazyLoad.disable\",\n \"intentExamples\": [\n \"no lazy\",\n \"eager load\"\n ],\n \"patchTemplate\": {\n \"behavior\": {\n \"lazyLoad\": false\n }\n }\n },\n {\n \"id\": \"group.stretchTabs.enable\",\n \"intentExamples\": [\n \"stretch tabs\",\n \"full width tabs\"\n ],\n \"patchTemplate\": {\n \"group\": {\n \"stretchTabs\": true\n }\n }\n },\n {\n \"id\": \"group.stretchTabs.disable\",\n \"intentExamples\": [\n \"no stretch tabs\",\n \"compact tabs\"\n ],\n \"patchTemplate\": {\n \"group\": {\n \"stretchTabs\": false\n }\n }\n },\n {\n \"id\": \"group.disablePagination.enable\",\n \"intentExamples\": [\n \"disable pagination\",\n \"no pagination\"\n ],\n \"patchTemplate\": {\n \"group\": {\n \"disablePagination\": true\n }\n }\n },\n {\n \"id\": \"group.disablePagination.disable\",\n \"intentExamples\": [\n \"enable pagination\",\n \"allow pagination\"\n ],\n \"patchTemplate\": {\n \"group\": {\n \"disablePagination\": false\n }\n }\n },\n {\n \"id\": \"tab.add\",\n \"intentExamples\": [\n \"add tab\",\n \"new tab\",\n \"create tab\",\n \"nova aba\",\n \"adicionar aba\",\n \"criar aba\"\n ],\n \"patchTemplate\": {\n \"tabs\": [\n {\n \"id\": \"{{target}}\",\n \"textLabel\": \"{{value}}\"\n }\n ]\n }\n },\n {\n \"id\": \"tab.content.set\",\n \"intentExamples\": [\n \"tab content\",\n \"current tab content\",\n \"add widget to tab\",\n \"list in current tab\",\n \"inside tab\",\n \"conteudo da aba\",\n \"nesta aba\",\n \"aba atual\",\n \"componente dentro da aba\"\n ],\n \"patchTemplate\": {\n \"tabs\": [\n {\n \"id\": \"{{target}}\",\n \"content\": \"{{params.content}}\",\n \"widgets\": \"{{params.widgets}}\"\n }\n ]\n }\n },\n {\n \"id\": \"tab.label.set\",\n \"intentExamples\": [\n \"rename tab\",\n \"tab label\",\n \"tab title\"\n ],\n \"patchTemplate\": {\n \"tabs\": [\n {\n \"id\": \"{{target}}\",\n \"textLabel\": \"{{value}}\"\n }\n ]\n }\n },\n {\n \"id\": \"tab.disable\",\n \"intentExamples\": [\n \"disable tab\",\n \"lock tab\"\n ],\n \"patchTemplate\": {\n \"tabs\": [\n {\n \"id\": \"{{target}}\",\n \"disabled\": true\n }\n ]\n }\n },\n {\n \"id\": \"tab.enable\",\n \"intentExamples\": [\n \"enable tab\",\n \"unlock tab\"\n ],\n \"patchTemplate\": {\n \"tabs\": [\n {\n \"id\": \"{{target}}\",\n \"disabled\": false\n }\n ]\n }\n },\n {\n \"id\": \"nav.link.add\",\n \"intentExamples\": [\n \"add link\",\n \"add nav link\",\n \"new link\"\n ],\n \"patchTemplate\": {\n \"nav\": {\n \"links\": [\n {\n \"id\": \"{{target}}\",\n \"label\": \"{{value}}\"\n }\n ]\n }\n }\n },\n {\n \"id\": \"nav.link.label.set\",\n \"intentExamples\": [\n \"rename link\",\n \"link label\"\n ],\n \"patchTemplate\": {\n \"nav\": {\n \"links\": [\n {\n \"id\": \"{{target}}\",\n \"label\": \"{{value}}\"\n }\n ]\n }\n }\n },\n {\n \"id\": \"nav.link.disable\",\n \"intentExamples\": [\n \"disable link\",\n \"lock link\"\n ],\n \"patchTemplate\": {\n \"nav\": {\n \"links\": [\n {\n \"id\": \"{{target}}\",\n \"disabled\": true\n }\n ]\n }\n }\n },\n {\n \"id\": \"nav.link.enable\",\n \"intentExamples\": [\n \"enable link\",\n \"unlock link\"\n ],\n \"patchTemplate\": {\n \"nav\": {\n \"links\": [\n {\n \"id\": \"{{target}}\",\n \"disabled\": false\n }\n ]\n }\n }\n }\n ],\n \"fieldResolvers\": {\n \"tabs[]\": [\n \"id\",\n \"textLabel\"\n ],\n \"nav.links[]\": [\n \"id\",\n \"label\"\n ]\n },\n \"hints\": [\n \"Use tabs[].id or tabs[].textLabel as merge keys; avoid array indexes.\",\n \"When using nav mode, prefer nav.links[]; when using group mode, prefer tabs[].\",\n \"Selected index expects a zero-based number.\",\n \"DOC: Widget purpose: tabs or nav links with dynamic content.\",\n \"DOC: Host inputs: tabsId (required), config (optional), and configPersistenceStrategy. Use input-first for governed previews that must render the explicit nested widget config.\",\n \"DOC: Provide either tabs[] (group mode) or nav.links[] (nav mode).\",\n \"DOC: Each tab/link should define a label (tabs[].textLabel or nav.links[].label).\"\n ]\n }\n}",
2041
- "sourcePointer": "praxis-ui-angular/projects/praxis-tabs/src/lib/ai/tabs-context-pack.ts",
2270
+ "sourcePointer": "projects/praxis-tabs/src/lib/ai/tabs-context-pack.ts",
2042
2271
  "contentHash": "553c32fd70139826d73d295bead2d03c309ce7e3ad91d1d8430e3681defcda19",
2043
2272
  "sourceKind": "component_definition",
2044
2273
  "sourceId": "praxis-tabs",
@@ -2048,7 +2277,7 @@
2048
2277
  "chunkIndex": 4,
2049
2278
  "chunkKind": "recipe",
2050
2279
  "content": "{\n \"_comment\": \"Receita para configuração de Abas (Praxis Tabs).\",\n \"templateMeta\": {\n \"registryKey\": \"praxis-tabs\",\n \"variantId\": \"base\",\n \"useWhen\": \"Base tabs configuration.\",\n \"examplePrompts\": [\n \"create a tabs layout\",\n \"add tabs with icons and routes\"\n ]\n },\n \"config\": {\n \"orientation\": \"horizontal\",\n \"lazyLoad\": true,\n \"animation\": true,\n \"keepAlive\": true,\n \"tabs\": [\n {\n \"id\": \"tab-overview\",\n \"label\": \"Visão Geral\",\n \"icon\": \"dashboard\",\n \"route\": \"./overview\"\n },\n {\n \"id\": \"tab-details\",\n \"label\": \"Detalhes\",\n \"icon\": \"list\",\n \"badge\": {\n \"content\": \"3\",\n \"color\": \"warn\"\n },\n \"route\": \"./details\"\n },\n {\n \"id\": \"tab-settings\",\n \"label\": \"Configurações\",\n \"icon\": \"settings\",\n \"disabled\": false,\n \"content\": {\n \"type\": \"component\",\n \"componentId\": \"settings-panel\"\n }\n }\n ]\n }\n}\n",
2051
- "sourcePointer": "praxis-ui-angular/examples/ai-recipes/praxis-tabs.json",
2280
+ "sourcePointer": "examples/ai-recipes/praxis-tabs.json",
2052
2281
  "contentHash": "82f4328235d1b31cc4d97442abd6e83c59f33b2320360098ca70aca508838d10",
2053
2282
  "sourceKind": "component_definition",
2054
2283
  "sourceId": "praxis-tabs",
package/package.json CHANGED
@@ -1,18 +1,18 @@
1
1
  {
2
2
  "name": "@praxisui/tabs",
3
- "version": "9.0.0-beta.70",
3
+ "version": "9.0.0-beta.72",
4
4
  "description": "Configurable tabs (group and nav) for Praxis UI with metadata-driven content and runtime editor.",
5
5
  "peerDependencies": {
6
6
  "@angular/common": "^21.0.0",
7
7
  "@angular/core": "^21.0.0",
8
8
  "@angular/material": "^21.0.0",
9
9
  "@angular/cdk": "^21.0.0",
10
- "@praxisui/core": "^9.0.0-beta.70",
11
- "@praxisui/dynamic-fields": "^9.0.0-beta.70",
12
- "@praxisui/settings-panel": "^9.0.0-beta.70",
10
+ "@praxisui/core": "^9.0.0-beta.72",
11
+ "@praxisui/dynamic-fields": "^9.0.0-beta.72",
12
+ "@praxisui/settings-panel": "^9.0.0-beta.72",
13
13
  "@angular/forms": "^21.0.0",
14
14
  "@angular/router": "^21.0.0",
15
- "@praxisui/ai": "^9.0.0-beta.70",
15
+ "@praxisui/ai": "^9.0.0-beta.72",
16
16
  "rxjs": "~7.8.0"
17
17
  },
18
18
  "dependencies": {