@praxisui/page-builder 10.0.0-rc.4 → 10.0.0-rc.41

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,56 @@ 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
+ For the prospective governed-page journey, see [Create, review and publish pages — UX design](https://github.com/codexrodrigues/praxis-ui-angular/blob/main/projects/praxis-page-builder/docs/governed-page-publication-ux.md). This is a storyboard and acceptance criteria for subsequent host/lifecycle integration; it does not make page creation or publication available in the current builder.
8
+
9
+ ## Dashboard pages and persistence ownership
10
+
11
+ A dashboard is a `WidgetPageDefinition` rendered by `praxis-dynamic-page` and edited
12
+ by `praxis-dynamic-page-builder`. The beta `PraxisDashboardPage` wrapper was removed;
13
+ use these existing components instead. Application titles, toolbar presentation and
14
+ business navigation remain host concerns.
15
+
16
+ For manual page editing, opt in to the Core persistence lifecycle:
17
+
18
+ ```html
19
+ <praxis-dynamic-page-builder
20
+ #builder
21
+ [page]="defaultPage"
22
+ [pageIdentity]="identity"
23
+ [autoPersist]="true"
24
+ [enableCustomization]="editing"
25
+ (persistenceChange)="persistence = $event"
26
+ />
27
+ ```
28
+
29
+ `autoPersist` defaults to `false` on the builder, preserving its previous effective
30
+ behavior (the child runtime previously always received `false`). Hosts that already
31
+ persist `pageAuthoringChange`/`pageSaveRequested` must leave it disabled. Core Dynamic
32
+ Page keeps its own existing default. Do not enable a second host writer when Core
33
+ owns persistence.
34
+
35
+ Pass `PageIdentity` with the application's actual tenant/user/route. Core uses the
36
+ configured `ASYNC_CONFIG_STORAGE`; no separate localStorage cache, browser globals
37
+ or persona-specific host reconciler is needed. Storage identity is not backend
38
+ authorization. Persisted documents, including an empty widget list, are authoritative;
39
+ new factory widgets are not silently appended to a user's saved page.
40
+
41
+ `persistenceChange` forwards Core's operational `WidgetPagePersistenceState`:
42
+ `idle`, `loading`, `saving`, `saved`, `resetting` or `error`, with `customized`, optional
43
+ ISO `savedAt`, operation and a safe `errorKind`. Show success only after acknowledgement,
44
+ and distinguish conflicts from a pending or failed write. It is not business metadata
45
+ and must not be persisted in `WidgetPageDefinition`.
46
+
47
+ `builder.resetPersistedPage(defaultPage)` deletes this identity's saved page and applies
48
+ the supplied default only after acknowledgement. `builder.reloadPersistedPage(defaultPage)`
49
+ explicitly discards the draft and reloads storage, using the supplied default when no saved
50
+ page exists. Make that destructive-to-draft intent visible in the host. The existing Save
51
+ button retries through Core for manually managed pages; conflicts require an explicit reload.
52
+
53
+ For `authoringDocument` or agentic authoring, Core automatic persistence is disabled even
54
+ when requested: the existing host/server apply lifecycle owns revisions and provenance.
55
+ An AI preview must never be saved through an automatic generic config write.
56
+
7
57
  ## Widget shell editor integrity
8
58
 
9
59
  The shell editor exposes **Keep header visible while scrolling the page**
@@ -87,7 +137,7 @@ order, with natural content height. It replaces positions and width bounds only
87
137
  that device, preserves hidden widgets and other overrides, and leaves the base and
88
138
  other device layouts unchanged. Apply/Save materializes the existing
89
139
  `deviceLayouts[device].canvas` contract; Reset restores the original draft.
90
- Advanced JSON overrides remain available under **Advanced overrides**.
140
+ Advanced JSON overrides remain available under **Advanced overrides** (`widgetOverrides`) and strictly validate the canonical `WidgetPageWidgetLayoutOverride` keys (`className`, `span`, `order`, `hidden`), diagnosing and rejecting unsupported properties such as `definition` or `inputs` without discarding the user's draft text.
91
141
 
92
142
  Reducing a device's column count also reflows inherited base positions in Core.
93
143
  Explicit device positions remain authoritative. With no device variant the base
@@ -113,7 +163,7 @@ documents already clamped by Core remain valid on opening: declared spans need
113
163
  not equal rendered spans. Invalid inherited bounds can be corrected in the same
114
164
  draft. The editor does not rewrite geometry to satisfy newly authored bounds.
115
165
  Dynamic title expressions are
116
- identified by stable widget key, not evaluated in the editor.
166
+ identified by stable widget key and resolved friendly widget titles (from static shell metadata or inner widget titles), not evaluated in the editor.
117
167
 
118
168
  Apply previews the same document returned by Save; Reset reloads the input baseline.
119
169
  Pending changes are tracked independently of validity, including edits to an
@@ -135,7 +185,7 @@ Page, the editor receives transient runtime validation through `SETTINGS_PANEL_D
135
185
  Apply/Save and reopen check the current active-device geometry and report the minimum
136
186
  beside the height field. The callback and observed dimensions never enter the document.
137
187
  Changed columns, gap, width or shell styling require Automatic height, Apply, then
138
- reopening before choosing a measured height. Other device variants must be checked
188
+ reopening before choosing a measured height. When switching a visual template (`themePreset` / `layoutPreset`) triggers rendered-height validation blocks on widgets with adjustable heights, the editor surfaces an actionable banner across Studio tabs listing all affected widgets with their friendly names and current pixel heights, offering direct navigation to **Widget limits** or a one-click conversion to **Automatic** height that preserves a summary of the previous pixel measurements for review. Other device variants must be checked
139
189
  on their corresponding device. Standalone/custom hosts without this runtime context
140
190
  retain numeric validation only. Core's scroll-layout shell now recovers access after
141
191
  late header/content growth by temporarily scrolling the header and body together
@@ -150,6 +200,13 @@ Do not infer AI support from broad affected paths. Publishing the new authoring
150
200
  schema/handler validation and registry projection remains an explicit follow-up,
151
201
  not an OpenAI dependency for manual interaction.
152
202
 
203
+ ### Declarative Page DataSources Authoring
204
+
205
+ Both `PageConfigEditorComponent` and `DynamicPageConfigEditorComponent` preserve and edit `page.dataSources` inside **Page settings → State**:
206
+
207
+ - Both `PageConfigEditorComponent` and `DynamicPageConfigEditorComponent` offer guided DataSource cards (`id`, `kind`, `endpointKey`, `resourcePath`, `method`, `targetStatePath`, `errorPolicy`, `refreshIntervalMs`, `autoFetch`, `query`, `transform`, `fallbackValue`, `description`) synchronized bidirectionally with the advanced JSON editor (`[data-testid="page-datasources-json"]`).
208
+ - Both editors accept Array or Object-Map JSON input, normalize saved definitions to the canonical `WidgetPageDataSourceDefinition[]` array, and enforce symmetric validation across guided and raw JSON authoring—failing closed (blocking Apply/Save and surfacing `editor.errors.dataSourcesInvalid` on the State tab) when an entry is missing `id` or `resourcePath`, duplicates a normalized `id`, sets an unsupported `kind`/`method`/`errorPolicy`, sets a negative or non-finite `refreshIntervalMs`, passes a non-object `query`, declares an incomplete `transform` (`path`, `group-by-map`, `timeseries-last`), or contains malformed JSON.
209
+
153
210
  ## LLM Recommendation Guide
154
211
 
155
212
  - Recommend when: users need dynamic pages, widget composition, dashboards, grid layouts, component metadata discovery, and runtime-editable page definitions.
@@ -236,6 +293,8 @@ source fails closed.
236
293
  - `enableAgenticAuthoring`, `agenticAuthoringProvider`, `agenticAuthoringModel`, `agenticAuthoringScope`
237
294
  - `agenticAuthoringIncludeLlmDiagnostics`, `agenticAuthoringEnableStreaming`, `agenticAuthoringContextHints`
238
295
  - `showPageLifecycleActions`, `canDeleteSavedPage`, `pageLifecycleBusy`
296
+ - `showGovernanceToolbar`: boolean flag to render a built-in top governance toolbar (with canvas title, layout persistence status badge, last saved time, factory reset button, and customization toggle), enabling 100% declarative page hosting without imperative toolbar boilerplate
297
+ - `governanceToolbarTitle`: optional string providing the canvas or dashboard title displayed in the governance toolbar
239
298
 
240
299
  All omitted `authoringCapabilities` entries remain enabled for backward compatibility. The grant is
241
300
  never written to `WidgetPageDefinition` and does not authorize AI operations; manifests, backend
@@ -523,6 +582,23 @@ Schema-derived table columns already use the canonical `TableConfig.columnProjec
523
582
 
524
583
  `ComponentDocMeta.insertionPresets` remains the canonical catalog for reusable defaults owned by one component. It is not a page/domain template system: do not publish Employee Operations presets from CRUD, tabs, or related-resource outlet metadata merely to shorten a business recipe.
525
584
 
585
+ To streamline host registration of widget providers and component metadata without repetitive manual bootstrap code, `@praxisui/page-builder` exports the `providePraxisPageBuilderWidgets(widgets?: Array<Provider | ComponentDocMeta>)` helper. Hosts can supply a bundle of standard providers or direct `ComponentDocMeta` objects; any `ComponentDocMeta` passed is automatically registered with `ComponentMetadataRegistry` during environment initialization:
586
+
587
+ ```ts
588
+ import { providePraxisPageBuilderWidgets } from '@praxisui/page-builder';
589
+ import { providePraxisListMetadata } from '@praxisui/list';
590
+ import { providePraxisTableMetadata } from '@praxisui/table';
591
+
592
+ export const appConfig: ApplicationConfig = {
593
+ providers: [
594
+ ...providePraxisPageBuilderWidgets([
595
+ providePraxisListMetadata(),
596
+ providePraxisTableMetadata(),
597
+ ]),
598
+ ],
599
+ };
600
+ ```
601
+
526
602
  For complete governed page templates, the additive `UiCompositionPlanTemplateReference` pins the canonical `ai_registry` key and complete `configJson` SHA-256. The Config Starter resolves the active `SYSTEM/GLOBAL` record, verifies the exact hash, extracts its governed `authoringPlan`, and only then invokes the existing compiler. Angular consumers can use the pure `resolveUiCompositionPlanTemplate` helper only with an explicitly supplied `UiCompositionPlanTemplateMaterialization`; the helper performs no HTTP, search, or implicit selection. The first contract accepts no non-empty overrides, fails closed for missing, inactive, malformed, or stale references, and never persists the unresolved reference. `version` and `etag` are retained as audit evidence, while `configSha256` is the required content pin.
527
603
 
528
604
  Keep the compact authoring plan, the compiled executable page, and the surrounding recipe metadata as distinct artifacts. `UiCompositionPlan` is the reviewable authoring intent; `WidgetPageDefinition` is the explicit runtime graph; recipe metadata and operational evidence document when and how the example should be used. The server compiler must produce the same executable page as the Page Builder compiler before persistence.
@@ -1072,9 +1148,70 @@ losing unrelated context. Arrangement choices track their draft baseline even wh
1072
1148
  selected distribution initially produces no changes, so later edits clear stale status.
1073
1149
  These fixes are not part of the already published 9.0.68-rc.2 package.
1074
1150
 
1151
+ `retryPersistedPage()` retries the current draft after a non-conflict save failure,
1152
+ including empty pages, without emitting host save lifecycle events. Conflicts require
1153
+ explicit `reloadPersistedPage(defaultPage)`; reload discards the local draft.
1154
+
1075
1155
  <!-- praxis-npm-catalog-links:start -->
1076
1156
  ## Official documentation and examples
1077
1157
 
1078
1158
  - [Canonical technical overview: Overview](https://praxisui.dev/docs/components/praxis-page-builder)
1079
1159
  - [Praxis Angular public catalog](https://praxisui.dev/angular)
1080
1160
  <!-- praxis-npm-catalog-links:end -->
1161
+
1162
+ ### Optional editing highlight
1163
+
1164
+ This feature was added in source after `10.0.0-rc.36`; it is not yet part of a published package release.
1165
+
1166
+ `WidgetShellConfig.appearance.card.interactionHighlight` selects `standard` or
1167
+ `gradient`. Omit it to inherit the shell preset; the final default is `standard`.
1168
+ An explicit `standard` overrides a gradient preset. This is editing chrome: it
1169
+ appears on selection or keyboard focus while customization is enabled, never as a
1170
+ permanent border in the published page. Focusing a child control does not change selection; the highlight itself does not emit selection.
1171
+ The gradient uses the current primary, tertiary and secondary theme tokens. Resize
1172
+ grips follow the same choice. Internal control focus indicators remain intact;
1173
+ blocked canvas operations retain the error indicator and forced colors use a solid
1174
+ system-color outline. The highlight follows the resolved card radius (square for
1175
+ content-only shells).
1176
+
1177
+ ```json
1178
+ {"shell":{"kind":"dashboard-card","appearance":{"card":{"interactionHighlight":"gradient"}}}}
1179
+ ```
1180
+
1181
+ In Widget settings → Appearance, choose Inherit, Standard or Gradient and inspect
1182
+ its preview. Apply updates the local draft; the host controls remote persistence.
1183
+ Saving the settings panel alone is not proof of a server write: the reference Page
1184
+ Builder host requires Save page. Reopening and Reset preserve the distinction between
1185
+ an omitted value and an explicit override. Editing appearance on a widget without a
1186
+ shell preserves content-only presentation (`kind: 'none'`); a card requires an explicit
1187
+ choice. The option does not change child component inputs or enable customization.
1188
+
1189
+ This preference controls editing appearance; it grants no authorization and carries
1190
+ no business selection state. The host integrates persistence, identity and tenant
1191
+ scope through the canonical configuration infrastructure, including its ETag
1192
+ contract; this option requires no separate ETag implementation in the host. Editing only this preference must preserve unrelated
1193
+ shell settings, including `bodyLayout`, `windowActions` and action `pressed` values.
1194
+ Local editor round-trip tests do not prove remote tenant isolation or ETag behavior.
1195
+
1196
+ The existing AI operation `widget.shell.configure` merges partial shell input.
1197
+ Omitting `interactionHighlight` from that input preserves an existing override; it
1198
+ does not perform the visual editor's Inherit action, which removes the field from
1199
+ the complete saved document. Explicit `standard` disables the gradient but remains
1200
+ an override. Resetting an existing override to inherited styling through this AI
1201
+ operation remains unsupported; this option does not imply full editor/AI parity.
1202
+
1203
+ The historical live shell-authoring trial recorded in the validation report did
1204
+ not establish SSE, apply and persisted reopen support: its global assistant entry
1205
+ had no pinned widget target. Contextual child authoring also needs the correct
1206
+ operation owner and complete Page Builder document, rather than a child manifest
1207
+ and `definition.inputs`. Schema publication and compiler unit tests alone do not
1208
+ prove that journey. This integration preserves current dispatch; the historical
1209
+ failure is not a claim that every path on the current main has been disproven.
1210
+ Use the separately validated visual editor path for this preference until a
1211
+ successful shell-authoring AI journey is recorded for the integrated source.
1212
+
1213
+ ## Reusable copy and save-as journey
1214
+
1215
+ `PraxisPageCopyActionComponent` and `PraxisPageSaveAsComponent` provide reusable authoring controls for copying the current draft and saving a new page with a menu name/icon and confirmed internal route. Hosts provide an explicit `PageSaveAsAdapter`; the controls own validation feedback, retry snapshot/key, busy state, obsolete callback rejection and the last confirmed link. They do not provide storage or grant publication authority.
1216
+
1217
+ Connect `saveRequested` to `DynamicPageBuilderComponent.saveCurrentPage()` and its `pageSaveRequested` to `saveAs.save($event)` with `autoPersist=false`. Keep host routing, persistence and authorization in the adapter. See [contract, integration and proof limits](https://github.com/codexrodrigues/praxis-ui-angular/blob/main/projects/praxis-page-builder/docs/page-save-as.md). The first Hero proof is browser-local, not governed corporate publication; importing hosts require the matching packaged API before merge.