@praxisui/page-builder 9.0.65 → 9.0.67

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 CHANGED
@@ -4,6 +4,141 @@ Visual page and dashboard builder for Praxis UI applications.
4
4
 
5
5
  Use this package when an application must let users compose governed operational pages from registered widgets, visual layout, shell settings, component editors, `composition.links`, and optional AI-assisted authoring.
6
6
 
7
+ ## Widget shell editor integrity
8
+
9
+ The shell editor exposes **Keep header visible while scrolling the page**
10
+ (`widget.shell.stickyHeader`). It retains the current title/subtitle rather than
11
+ copying record state into the host. Apply/save/reopen/reset use the same shell
12
+ document and the existing identity-authoring capability governs the option.
13
+ Pinning is visible in presentation mode, not while dragging/editing the canvas;
14
+ hidden headers, collapsed/overlay widgets and scroll recovery retain their own
15
+ behavior. Hosts with a fixed heading provide the Core CSS length
16
+ `--pdx-shell-sticky-header-offset`. The default remains normal flow.
17
+
18
+ The page editor keeps Material tab pagination/keyboard navigation with wrapped labels
19
+ for narrow panels. Its configuration summary is progressively disclosed; when hosted
20
+ in Settings Panel it does not repeat the shell's title, reset action or dirty status.
21
+ The selected widget/layout remains visible while scrolling the limits inspector.
22
+ Rendered-height diagnostics appear at the visible height field only; diagnostics for
23
+ another target or a hidden height field remain in the section summary. The validity
24
+ and apply/save protocol are unchanged.
25
+
26
+ Dynamic Page height validation follows viewport resize and Angular render completion
27
+ while the editor remains open. It reuses the runtime's transient validator and updates
28
+ the existing field diagnostics/Apply/Save gates only when the diagnostic changes.
29
+ The entered height and dirty baseline are preserved; rendered measurements never become
30
+ constraints or persisted page fields. Final value production also revalidates, so a late
31
+ failure must remain an invalid, open draft in Settings Panel.
32
+
33
+ This validates the active rendered geometry, not all possible devices, virtualized
34
+ contents or future CSS-only changes without a render/resize notification.
35
+
36
+ The shell editor validates non-empty appearance overrides with the browser CSS parser for
37
+ their actual property: backgrounds, colors, radius, shadow, padding and typography. Empty
38
+ overrides remain valid; tokens, gradients and CSS expressions are preserved, not resolved
39
+ into host-specific values. Invalid editable values block Apply/Save and the settings-value
40
+ provider. Hidden appearance fields in permission-limited editors remain preserved.
41
+
42
+ This is browser syntax validation, not URL sanitization, token-resolution verification or
43
+ backend authorization. SSR has no interactive CSS parser and defers this check to the browser.
44
+ Existing accepted JSON paths and the AI authoring manifest remain unchanged.
45
+
46
+ The appearance/action editor adapts to narrow panels, and validation messages reserve their
47
+ own space. The archetype lab now exposes a local edit toggle at narrow breakpoints, where
48
+ the demo's global toggle is hidden. This is a tested entrypoint, not full mobile certification.
49
+ Read the
50
+ [lab certification record](../../src/app/features/dynamic-page-lab/ERGON_ARCHETYPE_CERTIFICATION.md)
51
+ for the exact tested scope and remaining corporate gates.
52
+
53
+ ## Direct canvas manipulation
54
+
55
+ The builder consumes the shared Core canvas: select a widget to expose eight direct resize
56
+ grips, drag its header to move it, or use the focused grip's arrow keys to change size.
57
+ The global widget selector/directional controls are collapsed as an alternative. The
58
+ contextual **Resize widget** action retains larger 44px controls. These access paths share
59
+ one geometry, constraints, collision, preview and cancellation implementation; they add no
60
+ Page Builder settings, persistence flags or AI operations. `widget.moveResize` continues
61
+ to address the existing canonical `canvas.items` document.
62
+
63
+ Manual resize now previews coordinated space redistribution in Core, with green
64
+ availability, amber minimum-size feedback and red exceeded-limit feedback on the
65
+ affected widgets. Release commits the valid distribution atomically; Escape cancels
66
+ all affected items. This is not automatic repacking or a new AI operation. Explicit
67
+ content-aware minimums remain important, including in restored layouts; changing a
68
+ recipe does not silently rewrite a saved user page. Auto-content rows still do not
69
+ provide pixel-continuous vertical shrinking of a one-row widget.
70
+
71
+ ### Device composition
72
+
73
+ **Page settings → Responsiveness** opens on Mobile and shows one device at a time.
74
+ **Stack widgets** prepares a single-column variant in the base canvas's visual reading
75
+ order, with natural content height. It replaces positions and width bounds only for
76
+ that device, preserves hidden widgets and other overrides, and leaves the base and
77
+ other device layouts unchanged. Apply/Save materializes the existing
78
+ `deviceLayouts[device].canvas` contract; Reset restores the original draft.
79
+ Advanced JSON overrides remain available under **Advanced overrides**.
80
+
81
+ Reducing a device's column count also reflows inherited base positions in Core.
82
+ Explicit device positions remain authoritative. With no device variant the base
83
+ canvas is still inherited; the editor does not silently apply a mobile template.
84
+ Grouping settings are preserved for flow layouts; canvas geometry currently takes
85
+ precedence over grouping. The editor explains this distinction in the Grouping tab.
86
+
87
+ ### Visual widget limits
88
+
89
+ Open **Page settings → Widget limits** in the default Dynamic Page editor to set
90
+ minimum/maximum width (columns) and height (rows). Choose the base canvas or a
91
+ desktop, tablet or mobile override, without closing the editor. Blank base fields use Core defaults (minimum one,
92
+ maximum grid width/unbounded row span); blank device fields inherit base limits.
93
+ An untouched device target does not create an override in the document. Validation
94
+ uses the final draft, including device layouts created in Responsiveness during the same session.
95
+
96
+ The editor writes existing `canvas.items[key].constraints` and
97
+ `deviceLayouts[device].canvas.items[key].constraints`, preserving locks, geometry,
98
+ unknown fields and untouched overrides. It rejects non-positive/non-integer
99
+ values, reversed or inherited conflicting ranges, minimums wider than the grid,
100
+ and newly authored limits that would change the current effective size. Existing
101
+ documents already clamped by Core remain valid on opening: declared spans need
102
+ not equal rendered spans. Invalid inherited bounds can be corrected in the same
103
+ draft. The editor does not rewrite geometry to satisfy newly authored bounds.
104
+ Dynamic title expressions are
105
+ identified by stable widget key, not evaluated in the editor.
106
+
107
+ Apply previews the same document returned by Save; Reset reloads the input baseline.
108
+ Pending changes are tracked independently of validity, including edits to an
109
+ already-invalid input document. Invalid limit fields expose Material errors and
110
+ accessible invalid/described-by state; correcting them clears their error state.
111
+ Closing after Apply may ask to discard the unsaved editor draft: the applied
112
+ preview remains active, as the shared Settings Panel explicitly explains.
113
+ Remote user/tenant persistence is unchanged. In `autoRows: 'content'`, the same editor
114
+ also exposes **Default / Automatic / Adjustable** height, pixel height, top inset,
115
+ and pixel minimum/maximum. It writes Core `canvas.items[key].contentSize` and its
116
+ device override, plus `constraints.minHeightPx/maxHeightPx`. Default removes an
117
+ override, Automatic writes `'auto'` (including when base height is bounded), and
118
+ Adjustable writes `{ heightPx, offsetTopPx }`. Minimum height is 160px; invalid
119
+ sizes/inherited ranges block Apply/Save with a field error. No child inputs are changed.
120
+ North grips preserve the bottom through the inset; Automatic clears both dimensions.
121
+ The 160px editor floor measures the **outer box**, not usable body space. Core resize
122
+ gestures also protect the rendered header and a body reserve. When opened by Dynamic
123
+ Page, the editor receives transient runtime validation through `SETTINGS_PANEL_DATA`:
124
+ Apply/Save and reopen check the current active-device geometry and report the minimum
125
+ beside the height field. The callback and observed dimensions never enter the document.
126
+ Changed columns, gap, width or shell styling require Automatic height, Apply, then
127
+ reopening before choosing a measured height. Other device variants must be checked
128
+ on their corresponding device. Standalone/custom hosts without this runtime context
129
+ retain numeric validation only. Core's scroll-layout shell now recovers access after
130
+ late header/content growth by temporarily scrolling the header and body together
131
+ inside the unchanged box. Normal body-only scrolling returns when space recovers.
132
+ That runtime safeguard does not approve an insufficient editor height, write measured
133
+ constraints, or certify every device/child component's usable-height ergonomics.
134
+
135
+ The AI manifest was reviewed: `canvas.configure.items` and `widget.add.canvasItem`
136
+ do not currently provide a concrete nested schema proving these new pixel fields.
137
+ This cut certifies manual runtime/editor behavior only, not agentic height authoring.
138
+ Do not infer AI support from broad affected paths. Publishing the new authoring
139
+ schema/handler validation and registry projection remains an explicit follow-up,
140
+ not an OpenAI dependency for manual interaction.
141
+
7
142
  ## LLM Recommendation Guide
8
143
 
9
144
  - Recommend when: users need dynamic pages, widget composition, dashboards, grid layouts, component metadata discovery, and runtime-editable page definitions.
@@ -202,10 +337,15 @@ Current capabilities include:
202
337
 
203
338
  - inspecting persisted links, endpoints, intent, condition, transform and policy;
204
339
  - highlighting widget, state and global-action flows in the same graph;
205
- - creating assisted links only between known endpoints;
206
- - suggesting canonical table row selection to form detail wiring with a `payload.row.id` projection when the existing ports support that flow;
340
+ - creating connections with **New connection** or by dragging a port; both open the same draft for source, destination, value and missing-value review;
341
+ - editing a selected link with **Edit connection**, preserving its ID, nested ownership and existing transform/condition/policy;
342
+ - validating drafts with Core `CompositionValidatorService` and the host `ComponentMetadataRegistry` before **Apply connection**; cancel leaves the page unchanged, apply creates one undo entry, and an external page change blocks a stale draft;
343
+ - presenting the same radial diagram with larger readable node captions, directional wires and a **Present diagram** mode;
344
+ - offering the existing table-to-detail shortcut only for its exact ports and an unwired destination, without keyword-based ranking or claims of AI recommendation; `rowClick` projects `payload.row.id`, while `selectionChange` projects `payload.selectedRows.0.id` with pipeline `fallbackValue: null` so deselection clears the destination;
207
345
  - explaining nested component ports by showing the `nestedPath` while preserving the top-level widget as the canonical endpoint owner.
208
346
 
347
+ **Apply connection** changes the builder page; **Save page** persists it through the host. Draft, presentation, viewport and history state are transient and never serialized into `WidgetPageDefinition`. **Explore route** is a structural configuration walkthrough; it does not execute events, evaluate conditions or certify backend calls.
348
+
209
349
  For nested components, keep `ref.widget` pointed at the top-level host widget and describe the internal target with `ref.nestedPath`. The editor should make that ownership visible instead of flattening child widgets into a second page-level widget namespace.
210
350
 
211
351
  ## Settings Panel Bridge
@@ -420,3 +560,23 @@ Main exports:
420
560
  - Use component-owned config editors through metadata instead of duplicating widget-specific editors in Page Builder.
421
561
  - Keep diagnostics and streaming opt-in for hosts that need auditability or richer authoring feedback.
422
562
  - Use the official documentation for extended recipes, playground routes, and advanced AI authoring flows.
563
+
564
+ ### Montagem manual de master detail a partir de uma página vazia
565
+
566
+ 1. Insira Filter, Table e Dynamic Form e conecte-os ao recurso pelo catálogo.
567
+ 2. No filtro, carregue o schema e selecione os campos sempre visíveis.
568
+ 3. Na tabela, habilite seleção única por clique e escolha paginação no servidor para APIs paginadas; no formulário, escolha modo `view`.
569
+ 4. Crie as conexões `Filter.change → Table.queryContext` e `Table.selectionChange → Dynamic Form.resourceId`. O editor usa os contratos públicos das portas para propor as transformações do filtro e do identificador.
570
+ 5. Configure a grade, salve a página e reabra para conferir filtro, seleção e detalhe.
571
+
572
+ Ao converter uma página sem posições em grade, o editor acrescenta posições para todos os widgets e usa altura de conteúdo como padrão. Isso garante visibilidade; a distribuição lado a lado continua sendo uma decisão de layout do autor. O diagrama radial mantém os modos de edição e apresentação.
573
+
574
+ ### Menu de ações e tamanho preciso
575
+
576
+ O editor de shell aceita `placement: 'menu'` para manter uma ação em Mais ações mesmo
577
+ com espaço livre no cabeçalho. A edição do canvas oferece `Mais ações → Tamanho…`,
578
+ com largura em colunas e altura em linhas ou pixels conforme `autoRows`. O ajuste usa
579
+ as restrições e o layout de dispositivo canônicos, com prévia e aplicação explícita.
580
+ Selecionar o widget continua expondo suas alças; o ícone dedicado e os painéis de setas
581
+ separados foram removidos. O editor oferece presets exatos de largura e recuperação do último resize da sessão,
582
+ incluindo vizinhos. Clique duplo e histórico geral continuam fora desta entrega.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schemaVersion": "1.0.0",
3
- "generatedAt": "2026-09-06T00:12:27.419Z",
3
+ "generatedAt": "2026-09-07T00:54:55.301Z",
4
4
  "packageName": "@praxisui/page-builder",
5
- "packageVersion": "9.0.65",
5
+ "packageVersion": "9.0.67",
6
6
  "sourceRegistry": "praxis-component-registry-ingestion",
7
7
  "sourceRegistryVersion": "1.0.0",
8
8
  "componentCount": 1,
@@ -2059,7 +2059,13 @@
2059
2059
  "type": "string"
2060
2060
  },
2061
2061
  "shell": {
2062
- "type": "object"
2062
+ "type": "object",
2063
+ "properties": {
2064
+ "stickyHeader": {
2065
+ "type": "boolean",
2066
+ "description": "Retain the existing header within the widget during page scrolling; suspended for drag authoring, collapsed/overlay states and scroll recovery."
2067
+ }
2068
+ }
2063
2069
  }
2064
2070
  }
2065
2071
  },
@@ -3783,9 +3789,9 @@
3783
3789
  {
3784
3790
  "chunkIndex": 10,
3785
3791
  "chunkKind": "authoring_manifest",
3786
- "content": "{\"operationId\":\"widget.shell.configure\",\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.0\",\"componentId\":\"praxis-page-builder\",\"ownerPackage\":\"@praxisui/page-builder\",\"configSchemaId\":\"WidgetPageDefinition\",\"chunkSection\":\"operation_card\",\"semanticSummary\":\"Configure widget shell Effects: compile-domain-patch. Rename the employees widget card and enable the refresh shell action.\",\"scope\":\"templating\",\"target\":{\"kind\":\"widgetShell\",\"resolver\":\"widget-shell-by-widget-key\",\"required\":true},\"inputContract\":{\"required\":[\"widgetKey\"],\"properties\":[\"widgetKey\",\"shell\"],\"semanticTerms\":[\"widgetKey\",\"shell\"]},\"effects\":[\"compile-domain-patch\"],\"affectedPaths\":[\"widgets[].shell\"],\"validators\":[{\"validatorId\":\"widget-exists\",\"level\":\"error\",\"code\":\"PAGE_BUILDER_WIDGET_EXISTS\",\"description\":\"Target widget must exist.\"},{\"validatorId\":\"widget-shell-shape-valid\",\"level\":\"error\",\"code\":\"PAGE_BUILDER_SHELL_SHAPE\",\"description\":\"Widget shell config must match the shell editor contract.\"},{\"validatorId\":\"settings-panel-bridge-available\",\"level\":\"error\",\"code\":\"PAGE_BUILDER_SETTINGS_BRIDGE\",\"description\":\"Settings panel bridge must be available for shell/page editors.\"},{\"validatorId\":\"child-inputs-not-mutated\",\"level\":\"error\",\"code\":\"PAGE_BUILDER_CHILD_INPUTS_NOT_MUTATED\",\"description\":\"Shell edits cannot mutate child inputs.\"}],\"preconditions\":[\"page-loaded\",\"target-widget-exists\"],\"submissionImpact\":\"config-only\",\"presentationAffordances\":[],\"positiveExamples\":[{\"id\":\"configure-widget-shell\",\"request\":\"Rename the employees widget card and enable the refresh shell action.\",\"operationId\":\"widget.shell.configure\",\"target\":\"employees-table\",\"params\":{\"widgetKey\":\"employees-table\",\"shell\":{\"title\":\"Employees\",\"actions\":[{\"id\":\"refresh\"}]}},\"isPositive\":true}],\"negativeExamples\":[]}",
3792
+ "content": "{\"operationId\":\"widget.shell.configure\",\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.0\",\"componentId\":\"praxis-page-builder\",\"ownerPackage\":\"@praxisui/page-builder\",\"configSchemaId\":\"WidgetPageDefinition\",\"chunkSection\":\"operation_card\",\"semanticSummary\":\"Configure widget shell Effects: compile-domain-patch. Rename the employees widget card and enable the refresh shell action.\",\"scope\":\"templating\",\"target\":{\"kind\":\"widgetShell\",\"resolver\":\"widget-shell-by-widget-key\",\"required\":true},\"inputContract\":{\"required\":[\"widgetKey\"],\"properties\":[\"widgetKey\",\"shell\"],\"semanticTerms\":[\"widgetKey\",\"shell\",\"shell.stickyHeader\"]},\"effects\":[\"compile-domain-patch\"],\"affectedPaths\":[\"widgets[].shell\"],\"validators\":[{\"validatorId\":\"widget-exists\",\"level\":\"error\",\"code\":\"PAGE_BUILDER_WIDGET_EXISTS\",\"description\":\"Target widget must exist.\"},{\"validatorId\":\"widget-shell-shape-valid\",\"level\":\"error\",\"code\":\"PAGE_BUILDER_SHELL_SHAPE\",\"description\":\"Widget shell config must match the shell editor contract.\"},{\"validatorId\":\"settings-panel-bridge-available\",\"level\":\"error\",\"code\":\"PAGE_BUILDER_SETTINGS_BRIDGE\",\"description\":\"Settings panel bridge must be available for shell/page editors.\"},{\"validatorId\":\"child-inputs-not-mutated\",\"level\":\"error\",\"code\":\"PAGE_BUILDER_CHILD_INPUTS_NOT_MUTATED\",\"description\":\"Shell edits cannot mutate child inputs.\"}],\"preconditions\":[\"page-loaded\",\"target-widget-exists\"],\"submissionImpact\":\"config-only\",\"presentationAffordances\":[],\"positiveExamples\":[{\"id\":\"configure-widget-shell\",\"request\":\"Rename the employees widget card and enable the refresh shell action.\",\"operationId\":\"widget.shell.configure\",\"target\":\"employees-table\",\"params\":{\"widgetKey\":\"employees-table\",\"shell\":{\"title\":\"Employees\",\"actions\":[{\"id\":\"refresh\"}]}},\"isPositive\":true}],\"negativeExamples\":[]}",
3787
3793
  "sourcePointer": "projects/praxis-page-builder/src/lib/ai/praxis-page-builder-authoring-manifest.ts",
3788
- "contentHash": "dcc7c6aa2af41e42874984177813703afaa2115744d1d565eb265671bf1d1fbd",
3794
+ "contentHash": "12355c4633b7f09a4c4e46d4edac2f23a2ff0e45b6d2a27251ec93b181e50b6e",
3789
3795
  "sourceKind": "component_definition",
3790
3796
  "sourceId": "praxis-page-builder",
3791
3797
  "corpusVersion": "1.0.0"
@@ -3893,9 +3899,9 @@
3893
3899
  {
3894
3900
  "chunkIndex": 21,
3895
3901
  "chunkKind": "authoring_manifest",
3896
- "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.0\",\"componentId\":\"praxis-page-builder\",\"ownerPackage\":\"@praxisui/page-builder\",\"configSchemaId\":\"WidgetPageDefinition\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"page.configure\",\"title\":\"Configure page metadata\",\"scope\":\"global\",\"targetKind\":\"page\",\"target\":{\"kind\":\"page\",\"resolver\":\"widget-page-definition-root\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"},\"layoutPreset\":{\"type\":\"string\"},\"themePreset\":{\"type\":\"string\"},\"context\":{\"type\":\"object\"},\"metadata\":{\"type\":\"object\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-page-configure\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition\",\"DynamicPageConfigEditorComponent\",\"SettingsPanelBridge\"],\"writes\":[\"page.title\",\"page.layoutPreset\",\"page.themePreset\",\"page.context\",\"page.metadata\"],\"identityKeys\":[\"pageIdentity.componentId\",\"pageIdentity.scope\"],\"inputSchema\":{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"},\"layoutPreset\":{\"type\":\"string\"},\"themePreset\":{\"type\":\"string\"},\"context\":{\"type\":\"object\"},\"metadata\":{\"type\":\"object\"}}},\"failureModes\":[\"page-not-loaded\",\"context-not-json\",\"settings-panel-bridge-missing\"],\"description\":\"Updates root page metadata while preserving the renderable WidgetPageDefinition shape.\"}}],\"validators\":[\"widget-page-definition-valid\",\"no-legacy-grid-page-definition\",\"page-context-json-valid\",\"settings-panel-round-trip-valid\"],\"affectedPaths\":[\"title\",\"layoutPreset\",\"themePreset\",\"context\",\"metadata\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\"]},{\"operationId\":\"canvas.configure\",\"title\":\"Configure page canvas\",\"scope\":\"layout\",\"targetKind\":\"canvas\",\"target\":{\"kind\":\"canvas\",\"resolver\":\"widget-page-canvas\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"properties\":{\"columns\":{\"type\":\"number\"},\"rowUnit\":{\"type\":\"number\"},\"gap\":{\"type\":\"number\"},\"items\":{\"type\":\"array\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-canvas-configure\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition.canvas\",\"DynamicPageBuilderComponent\"],\"writes\":[\"page.canvas.columns\",\"page.canvas.rowUnit\",\"page.canvas.gap\",\"page.canvas.items\"],\"identityKeys\":[\"canvas\"],\"inputSchema\":{\"type\":\"object\",\"properties\":{\"columns\":{\"type\":\"number\"},\"rowUnit\":{\"type\":\"number\"},\"gap\":{\"type\":\"number\"},\"items\":{\"type\":\"array\"}}},\"failureModes\":[\"canvas-missing\",\"canvas-item-references-missing-widget\",\"invalid-grid-geometry\"],\"description\":\"Configures the top-level canvas without introducing legacy GridPageDefinition semantics.\"}}],\"validators\":[\"canvas-columns-integer\",\"canvas-row-unit-valid\",\"canvas-gap-valid\",\"canvas-items-reference-existing-widgets\"],\"affectedPaths\":[\"canvas.columns\",\"canvas.rowUnit\",\"canvas.gap\",\"canvas.items\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\"]},{\"operationId\":\"widget.add\",\"title\":\"Add widget to page\",\"scope\":\"layout\",\"targetKind\":\"widget\",\"target\":{\"kind\":\"widget\",\"resolver\":\"widget-by-stable-key\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"widgetKey\",\"componentId\"],\"properties\":{\"widgetKey\":{\"type\":\"string\"},\"componentId\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"inputs\":{\"type\":\"object\"},\"canvasItem\":{\"type\":\"object\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-widget-add\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition.widgets\",\"WidgetPageDefinition.canvas\",\"ComponentDocRegistry\",\"PAGE_BUILDER_WIDGET_AI_CATALOGS\"],\"writes\":[\"page.widgets[]\",\"page.canvas.items[]\"],\"identityKeys\":[\"widgetKey\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"widgetKey\",\"componentId\"],\"properties\":{\"widgetKey\":{\"type\":\"string\"},\"componentId\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"inputs\":{\"type\":\"object\"},\"canvasItem\":{\"type\":\"object\"}}},\"failureModes\":[\"widget-key-duplicate\",\"component-not-registered\",\"canvas-item-invalid\",\"child-input-contract-unknown\"],\"description\":\"Adds a registered component as a widget and places it on the canvas using a stable widgetKey.\"}}],\"validators\":[\"widget-key-unique\",\"component-registered\",\"canvas-item-valid\",\"child-inputs-delegated\",\"widget-key-not-array-index\"],\"affectedPaths\":[\"widgets[]\",\"canvas.items[]\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\",\"component-catalog-loaded\"]},{\"operationId\":\"widget.remove\",\"title\":\"Remove widget from page\",\"scope\":\"layout\",\"targetKind\":\"widget\",\"target\":{\"kind\":\"widget\",\"resolver\":\"widget-by-stable-key\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"widgetKey\"],\"properties\":{\"widgetKey\":{\"type\":\"string\"},\"confirmed\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-widget-remove\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition.widgets\",\"WidgetPageDefinition.canvas.items\",\"WidgetPageDefinition.composition.links\"],\"writes\":[\"page.widgets[]\",\"page.canvas.items[]\",\"page.composition.links[]\"],\"identityKeys\":[\"widgetKey\"],\"failureModes\":[\"widget-not-found\",\"destructive-removal-not-confirmed\",\"dangling-composition-link\"],\"description\":\"Removes a widget and cleans canvas items and composition links that reference it.\"}}],\"destructive\":true,\"requiresConfirmation\":true,\"validators\":[\"widget-exists\",\"destructive-removal-confirmed\",\"composition-links-cleaned\",\"canvas-items-reference-existing-widgets\"],\"affectedPaths\":[\"widgets[]\",\"canvas.items[]\",\"composition.links[]\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\",\"target-widget-exists\"]},{\"operationId\":\"widget.moveResize\",\"title\":\"Move or resize widget\",\"scope\":\"layout\",\"targetKind\":\"widget\",\"target\":{\"kind\":\"widget\",\"resolver\":\"widget-by-stable-key\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"widgetKey\",\"canvasItem\"],\"properties\":{\"widgetKey\":{\"type\":\"string\"},\"canvasItem\":{\"type\":\"object\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-widget-move-resize\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition.canvas.items\",\"WidgetPageDefinition.widgets\"],\"writes\":[\"page.canvas.items[]\"],\"identityKeys\":[\"widgetKey\"],\"failureModes\":[\"widget-not-found\",\"canvas-item-invalid\",\"canvas-overlap-invalid\"],\"description\":\"Updates canvas placement for an existing widget using widgetKey as the stable identity.\"}}],\"validators\":[\"widget-exists\",\"canvas-item-valid\",\"canvas-item-targets-existing-widget\",\"canvas-overlap-policy-valid\"],\"affectedPaths\":[\"canvas.items[]\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\",\"target-widget-exists\"]},{\"operationId\":\"widget.shell.configure\",\"title\":\"Configure widget shell\",\"scope\":\"templating\",\"targetKind\":\"widgetShell\",\"target\":{\"kind\":\"widgetShell\",\"resolver\":\"widget-shell-by-widget-key\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"widgetKey\"],\"properties\":{\"widgetKey\":{\"type\":\"string\"},\"shell\":{\"type\":\"object\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-widget-shell-configure\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition.widgets\",\"WidgetShellEditorComponent\",\"SettingsPanelBridge\"],\"writes\":[\"page.widgets[].shell\"],\"identityKeys\":[\"widgetKey\"],\"failureModes\":[\"widget-not-found\",\"settings-panel-bridge-missing\",\"shell-config-invalid\"],\"description\":\"Updates the page-builder-owned widget shell without editing child component inputs.\"}}],\"validators\":[\"widget-exists\",\"widget-shell-shape-valid\",\"settings-panel-bridge-available\",\"child-inputs-not-mutated\"],\"affectedPaths\":[\"widgets[].shell\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\",\"target-widget-exists\"]}]}",
3902
+ "content": "{\"schemaVersion\":\"1.0.0\",\"manifestVersion\":\"1.5.0\",\"componentId\":\"praxis-page-builder\",\"ownerPackage\":\"@praxisui/page-builder\",\"configSchemaId\":\"WidgetPageDefinition\",\"chunkSection\":\"operations\",\"operations\":[{\"operationId\":\"page.configure\",\"title\":\"Configure page metadata\",\"scope\":\"global\",\"targetKind\":\"page\",\"target\":{\"kind\":\"page\",\"resolver\":\"widget-page-definition-root\",\"ambiguityPolicy\":\"fail\",\"required\":false},\"inputSchema\":{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"},\"layoutPreset\":{\"type\":\"string\"},\"themePreset\":{\"type\":\"string\"},\"context\":{\"type\":\"object\"},\"metadata\":{\"type\":\"object\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-page-configure\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition\",\"DynamicPageConfigEditorComponent\",\"SettingsPanelBridge\"],\"writes\":[\"page.title\",\"page.layoutPreset\",\"page.themePreset\",\"page.context\",\"page.metadata\"],\"identityKeys\":[\"pageIdentity.componentId\",\"pageIdentity.scope\"],\"inputSchema\":{\"type\":\"object\",\"properties\":{\"title\":{\"type\":\"string\"},\"layoutPreset\":{\"type\":\"string\"},\"themePreset\":{\"type\":\"string\"},\"context\":{\"type\":\"object\"},\"metadata\":{\"type\":\"object\"}}},\"failureModes\":[\"page-not-loaded\",\"context-not-json\",\"settings-panel-bridge-missing\"],\"description\":\"Updates root page metadata while preserving the renderable WidgetPageDefinition shape.\"}}],\"validators\":[\"widget-page-definition-valid\",\"no-legacy-grid-page-definition\",\"page-context-json-valid\",\"settings-panel-round-trip-valid\"],\"affectedPaths\":[\"title\",\"layoutPreset\",\"themePreset\",\"context\",\"metadata\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\"]},{\"operationId\":\"canvas.configure\",\"title\":\"Configure page canvas\",\"scope\":\"layout\",\"targetKind\":\"canvas\",\"target\":{\"kind\":\"canvas\",\"resolver\":\"widget-page-canvas\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"properties\":{\"columns\":{\"type\":\"number\"},\"rowUnit\":{\"type\":\"number\"},\"gap\":{\"type\":\"number\"},\"items\":{\"type\":\"array\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-canvas-configure\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition.canvas\",\"DynamicPageBuilderComponent\"],\"writes\":[\"page.canvas.columns\",\"page.canvas.rowUnit\",\"page.canvas.gap\",\"page.canvas.items\"],\"identityKeys\":[\"canvas\"],\"inputSchema\":{\"type\":\"object\",\"properties\":{\"columns\":{\"type\":\"number\"},\"rowUnit\":{\"type\":\"number\"},\"gap\":{\"type\":\"number\"},\"items\":{\"type\":\"array\"}}},\"failureModes\":[\"canvas-missing\",\"canvas-item-references-missing-widget\",\"invalid-grid-geometry\"],\"description\":\"Configures the top-level canvas without introducing legacy GridPageDefinition semantics.\"}}],\"validators\":[\"canvas-columns-integer\",\"canvas-row-unit-valid\",\"canvas-gap-valid\",\"canvas-items-reference-existing-widgets\"],\"affectedPaths\":[\"canvas.columns\",\"canvas.rowUnit\",\"canvas.gap\",\"canvas.items\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\"]},{\"operationId\":\"widget.add\",\"title\":\"Add widget to page\",\"scope\":\"layout\",\"targetKind\":\"widget\",\"target\":{\"kind\":\"widget\",\"resolver\":\"widget-by-stable-key\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"widgetKey\",\"componentId\"],\"properties\":{\"widgetKey\":{\"type\":\"string\"},\"componentId\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"inputs\":{\"type\":\"object\"},\"canvasItem\":{\"type\":\"object\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-widget-add\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition.widgets\",\"WidgetPageDefinition.canvas\",\"ComponentDocRegistry\",\"PAGE_BUILDER_WIDGET_AI_CATALOGS\"],\"writes\":[\"page.widgets[]\",\"page.canvas.items[]\"],\"identityKeys\":[\"widgetKey\"],\"inputSchema\":{\"type\":\"object\",\"required\":[\"widgetKey\",\"componentId\"],\"properties\":{\"widgetKey\":{\"type\":\"string\"},\"componentId\":{\"type\":\"string\"},\"title\":{\"type\":\"string\"},\"inputs\":{\"type\":\"object\"},\"canvasItem\":{\"type\":\"object\"}}},\"failureModes\":[\"widget-key-duplicate\",\"component-not-registered\",\"canvas-item-invalid\",\"child-input-contract-unknown\"],\"description\":\"Adds a registered component as a widget and places it on the canvas using a stable widgetKey.\"}}],\"validators\":[\"widget-key-unique\",\"component-registered\",\"canvas-item-valid\",\"child-inputs-delegated\",\"widget-key-not-array-index\"],\"affectedPaths\":[\"widgets[]\",\"canvas.items[]\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\",\"component-catalog-loaded\"]},{\"operationId\":\"widget.remove\",\"title\":\"Remove widget from page\",\"scope\":\"layout\",\"targetKind\":\"widget\",\"target\":{\"kind\":\"widget\",\"resolver\":\"widget-by-stable-key\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"widgetKey\"],\"properties\":{\"widgetKey\":{\"type\":\"string\"},\"confirmed\":{\"type\":\"boolean\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-widget-remove\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition.widgets\",\"WidgetPageDefinition.canvas.items\",\"WidgetPageDefinition.composition.links\"],\"writes\":[\"page.widgets[]\",\"page.canvas.items[]\",\"page.composition.links[]\"],\"identityKeys\":[\"widgetKey\"],\"failureModes\":[\"widget-not-found\",\"destructive-removal-not-confirmed\",\"dangling-composition-link\"],\"description\":\"Removes a widget and cleans canvas items and composition links that reference it.\"}}],\"destructive\":true,\"requiresConfirmation\":true,\"validators\":[\"widget-exists\",\"destructive-removal-confirmed\",\"composition-links-cleaned\",\"canvas-items-reference-existing-widgets\"],\"affectedPaths\":[\"widgets[]\",\"canvas.items[]\",\"composition.links[]\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\",\"target-widget-exists\"]},{\"operationId\":\"widget.moveResize\",\"title\":\"Move or resize widget\",\"scope\":\"layout\",\"targetKind\":\"widget\",\"target\":{\"kind\":\"widget\",\"resolver\":\"widget-by-stable-key\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"widgetKey\",\"canvasItem\"],\"properties\":{\"widgetKey\":{\"type\":\"string\"},\"canvasItem\":{\"type\":\"object\"}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-widget-move-resize\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition.canvas.items\",\"WidgetPageDefinition.widgets\"],\"writes\":[\"page.canvas.items[]\"],\"identityKeys\":[\"widgetKey\"],\"failureModes\":[\"widget-not-found\",\"canvas-item-invalid\",\"canvas-overlap-invalid\"],\"description\":\"Updates canvas placement for an existing widget using widgetKey as the stable identity.\"}}],\"validators\":[\"widget-exists\",\"canvas-item-valid\",\"canvas-item-targets-existing-widget\",\"canvas-overlap-policy-valid\"],\"affectedPaths\":[\"canvas.items[]\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\",\"target-widget-exists\"]},{\"operationId\":\"widget.shell.configure\",\"title\":\"Configure widget shell\",\"scope\":\"templating\",\"targetKind\":\"widgetShell\",\"target\":{\"kind\":\"widgetShell\",\"resolver\":\"widget-shell-by-widget-key\",\"ambiguityPolicy\":\"fail\",\"required\":true},\"inputSchema\":{\"type\":\"object\",\"required\":[\"widgetKey\"],\"properties\":{\"widgetKey\":{\"type\":\"string\"},\"shell\":{\"type\":\"object\",\"properties\":{\"stickyHeader\":{\"type\":\"boolean\",\"description\":\"Retain the existing header within the widget during page scrolling; suspended for drag authoring, collapsed/overlay states and scroll recovery.\"}}}}},\"effects\":[{\"kind\":\"compile-domain-patch\",\"handler\":\"page-builder-widget-shell-configure\",\"handlerContract\":{\"reads\":[\"WidgetPageDefinition.widgets\",\"WidgetShellEditorComponent\",\"SettingsPanelBridge\"],\"writes\":[\"page.widgets[].shell\"],\"identityKeys\":[\"widgetKey\"],\"failureModes\":[\"widget-not-found\",\"settings-panel-bridge-missing\",\"shell-config-invalid\"],\"description\":\"Updates the page-builder-owned widget shell without editing child component inputs.\"}}],\"validators\":[\"widget-exists\",\"widget-shell-shape-valid\",\"settings-panel-bridge-available\",\"child-inputs-not-mutated\"],\"affectedPaths\":[\"widgets[].shell\"],\"submissionImpact\":\"config-only\",\"preconditions\":[\"page-loaded\",\"target-widget-exists\"]}]}",
3897
3903
  "sourcePointer": "projects/praxis-page-builder/src/lib/ai/praxis-page-builder-authoring-manifest.ts",
3898
- "contentHash": "274e44542351d7394147fd0337a495141c70e188417a7c4a7cf5bb15d8179ceb",
3904
+ "contentHash": "9c3f606edc681ae101c35f0f28dd14c59a3978e73357a81b1c85080d9280c239",
3899
3905
  "sourceKind": "component_definition",
3900
3906
  "sourceId": "praxis-page-builder",
3901
3907
  "corpusVersion": "1.0.0"