@praxisui/core 9.0.66 → 9.0.68-rc.0
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 +439 -38
- package/ai/component-registry.json +98 -27
- package/fesm2022/praxisui-core.mjs +4805 -931
- package/package.json +2 -1
- package/theme-bridge.css +9 -0
- package/types/praxisui-core.d.ts +704 -174
package/README.md
CHANGED
|
@@ -4,8 +4,59 @@ Shared contracts, tokens, services, metadata models, widget runtime primitives,
|
|
|
4
4
|
|
|
5
5
|
Use this package directly when a host application or library needs Praxis UI types, global actions, metadata registries, schema clients, resource discovery, i18n, theme bridge, dynamic widget contracts, or shared runtime services.
|
|
6
6
|
|
|
7
|
+
## Governed color palettes
|
|
8
|
+
|
|
9
|
+
`materializeGovernedPaletteEntries(palette, purposes)` returns `MaterializedGovernedColorToken[]`, pairing each original `entry` with its resolved `color`. It preserves distinct token IDs even when CSS references/colors match, applies purpose filtering, and resolves fallback dependencies against the complete palette. Use this projection for identified swatches; do not zip color arrays to entries or infer identity from color equality. `materializeGovernedPaletteColors` remains the string-only projection of the same resolver.
|
|
10
|
+
|
|
11
|
+
`GovernedColorPaletteService` is the canonical Angular client for color-palette projections published by Praxis Config. Published palettes carry a stable `familyKey`, an explicit `variant` identity and token-level `displayName`/`aliases`; incomplete legacy projections are rejected before caching. The service supports list/read/capabilities/preview, exact `list(familyKey)` queries, tenant/environment-isolated caching, conditional ETag revalidation and deterministic `version`/`etag` pins. Consumers may use names and aliases for presentation and discovery only: `paletteKey` and `tokenId` remain the persisted identities, and local metadata must not become a second source of governance. `GovernedColorTokenSelection` carries the exact palette/version/ETag/token observation beside the existing CSS-string field value; applications persist it only through an explicit domain field or mapping.
|
|
12
|
+
|
|
7
13
|
## LLM Recommendation Guide
|
|
8
14
|
|
|
15
|
+
- `BUILTIN_WIDGET_SHELL_PRESETS` is the canonical catalog for reusable shell
|
|
16
|
+
treatments. `integrated-card`, `outlined-card`, `elevated-card` and
|
|
17
|
+
`tonal-card` keep header actions and body on one continuous surface;
|
|
18
|
+
`sectioned-card` deliberately separates the header; `frameless` removes the
|
|
19
|
+
containing surface while retaining the standard content inset, aligned with the
|
|
20
|
+
header. For content that owns its own spacing, explicitly set
|
|
21
|
+
`appearance.body.padding: "0"` (and hide the header if the content owns its title).
|
|
22
|
+
Persist the preset `id` in `WidgetShellConfig.preset` and
|
|
23
|
+
use the descriptor for authoring labels and previews. Do not maintain a
|
|
24
|
+
second preset list in consumers.
|
|
25
|
+
- `WidgetShellConfig.stickyHeader: true` retains the existing composition-derived
|
|
26
|
+
header within its widget during page scrolling. Omission/false keeps normal flow.
|
|
27
|
+
This differs from `bodyLayout: 'scroll'`, which governs body scrolling. No second
|
|
28
|
+
selection state, cloned header or page geometry is persisted.
|
|
29
|
+
- Hosts with fixed chrome may set `--pdx-shell-sticky-header-offset` (CSS length,
|
|
30
|
+
default `0px`). Measure responsive chrome; do not assume a desktop-only height.
|
|
31
|
+
The lab uses a lifecycle-owned ResizeObserver for its functional heading.
|
|
32
|
+
- Pinning releases at the widget boundary and is suspended during drag authoring,
|
|
33
|
+
collapse, hidden/disabled headers, expanded/fullscreen windows and scroll recovery.
|
|
34
|
+
This is not a global selected-record bar. Continuous-surface presets repeat
|
|
35
|
+
their opaque card surface on the header so pinned content does not bleed through.
|
|
36
|
+
Transparent/gradient custom headers are painted over an opaque Material surface.
|
|
37
|
+
Keyboard focus is revealed below pinned chrome without changing its target.
|
|
38
|
+
- Dynamic Page publishes its existing `context` input as a `view-context` port.
|
|
39
|
+
Composition links can deliver runtime context to a nested page through Tabs or
|
|
40
|
+
Expansion using stable `nestedPath` segments. The child page owns its internal
|
|
41
|
+
bindings; callers should target its context boundary, not invent paths through
|
|
42
|
+
its widget array. Register the canonical Dynamic Page metadata before preflight.
|
|
43
|
+
Context is runtime data, not a replacement for backend authorization or a saved
|
|
44
|
+
business record. The metadata port is also preserved in the generated AI catalog.
|
|
45
|
+
- Nested sticky shells add the measured height of sticky ancestor headers in the
|
|
46
|
+
same scrollport. This is transient geometry, not a saved offset or another
|
|
47
|
+
selection context. The stack stops at an independent scrolling container;
|
|
48
|
+
hidden/inactive headers cease contributing. Ancestor resize observation is
|
|
49
|
+
disconnected on destruction. Body scrolling/fill and window-layout rules apply
|
|
50
|
+
to the owning shell's direct body, not to every nested widget body.
|
|
51
|
+
For dynamic-height containers that should follow page scrolling, use content
|
|
52
|
+
flow (omit `bodyLayout` or use `content`), not `fill`. An intentional independent
|
|
53
|
+
scrollport remains a boundary for the sticky stack.
|
|
54
|
+
- An invisible shell (`kind: 'none'`) removes padding only from its own body.
|
|
55
|
+
Nested dashboard shells retain their authored body spacing. Hiding a header
|
|
56
|
+
with `showHeader: false` does not hide child headers or reset child spacing.
|
|
57
|
+
- The Page Builder shell editor exposes the option. Existing saved layouts are
|
|
58
|
+
preserved; changing the source recipe does not silently migrate saved pages.
|
|
59
|
+
|
|
9
60
|
- Coordinated manual resize: an unambiguous edge collision yields space from the
|
|
10
61
|
affected neighbors, preserving their opposite edges and respecting `minColSpan`,
|
|
11
62
|
`minRowSpan`, `lockSize` and `lockPosition`. It does not swap widgets or push a
|
|
@@ -18,9 +69,9 @@ Use this package directly when a host application or library needs Praxis UI typ
|
|
|
18
69
|
discards the entire preview. Feedback is transient, never serialized.
|
|
19
70
|
Author useful content-specific minimums and device overrides: the grid default of
|
|
20
71
|
one unit is a geometric limit, not a guarantee of readable enterprise content.
|
|
21
|
-
`autoRows: 'content'`
|
|
22
|
-
|
|
23
|
-
|
|
72
|
+
`autoRows: 'content'` measures content-driven tracks and uses independent pixel
|
|
73
|
+
`contentSize` for vertical resizing; `rowSpan` remains at least one. Resizing does not
|
|
74
|
+
imply automatic packing or moving unrelated widgets to a new row.
|
|
24
75
|
|
|
25
76
|
- Widget Shell sizing: the shell includes its border inside the height reserved by its
|
|
26
77
|
host (`border-box`). Consumers do not need a global CSS reset to prevent a 2px overflow.
|
|
@@ -29,37 +80,38 @@ Use this package directly when a host application or library needs Praxis UI typ
|
|
|
29
80
|
CSS Grid reflow, not automatic compaction of authored fixed coordinates.
|
|
30
81
|
|
|
31
82
|
- Dynamic Page resize presentation: selecting an unlocked widget in an editable grid
|
|
32
|
-
exposes eight
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
a
|
|
83
|
+
exposes eight edge/corner grips with targets up to 24px per axis, themed focus and localized names.
|
|
84
|
+
The widget wrapper is keyboard focusable: focus selects it, Tab reaches its controls,
|
|
85
|
+
arrow keys resize, and Escape from a grip returns focus to the wrapper. Selection alone
|
|
86
|
+
does not change the document. Header drag remains the reorder entrypoint.
|
|
87
|
+
|
|
88
|
+
**Configure widget → Size** offers width in grid columns and height in rows (fixed grid)
|
|
89
|
+
or pixels (content rows). **More actions → Size…** opens this same settings tab.
|
|
90
|
+
Widget and Size share the SettingsPanel footer and preserve drafts when switching tabs.
|
|
91
|
+
Hosts without `SETTINGS_PANEL_BRIDGE` retain the Core-owned size overlay with explicit
|
|
92
|
+
Apply and Cancel actions, so the canvas authoring capability does not depend on an optional host service.
|
|
93
|
+
An optional fixed-corner choice preserves the opposite edges.
|
|
94
|
+
Valid changes preview the same constrained distribution as the grips; Apply commits once,
|
|
95
|
+
Cancel/Escape discard the unapplied draft and restore widget focus; an earlier Apply remains. Out-of-range or blocked sizes
|
|
96
|
+
disable Apply rather than silently changing the requested numbers. The dialog identifies
|
|
97
|
+
whether the edit targets the base layout or a device override. Opening it preserves
|
|
98
|
+
automatic height; changing only width does not create a fixed height.
|
|
99
|
+
|
|
100
|
+
This menu is available with canvas authoring permission, including headerless widgets
|
|
101
|
+
and hosts that disable removal or shell configuration. Size-locked widgets disable it.
|
|
102
|
+
There is no dedicated Resize widget icon, global selector or detached directional panel.
|
|
103
|
+
The size action is transient and never persisted in page JSON. Shell actions can explicitly
|
|
104
|
+
use `placement: 'menu'` to stay in More actions even when header slots are free; the shell
|
|
105
|
+
editor and capability catalog share that value. Existing header/window placements retain
|
|
106
|
+
their behavior. All sizing reuses canonical canvas items, constraints and device targeting.
|
|
107
|
+
The editor offers exact grid-width presets (⅓, ½, ⅔, 100%) when the column count
|
|
108
|
+
can represent them without rounding. They change the width draft, preserve the fixed
|
|
109
|
+
corner and require Apply; an unavailable full width is rejected, never silently clamped.
|
|
110
|
+
After a committed resize, reopen Size… on that widget to undo the last resize in this
|
|
111
|
+
session, including yielded neighbors. Recovery restores prior device inheritance and
|
|
112
|
+
keeps unrelated content edits. It refuses changed affected geometry/limits, new collisions,
|
|
113
|
+
a different device scope or page identity. This is one-operation recovery, not a general
|
|
114
|
+
history or redo stack. Side and corner double-click shortcuts use the same constrained geometry.
|
|
63
115
|
|
|
64
116
|
- Dynamic Page gesture note: drag/resize previews belong to one primary pointer at a time.
|
|
65
117
|
Secondary buttons, non-primary touches and additional pointers do not replace an active
|
|
@@ -71,6 +123,9 @@ Use this package directly when a host application or library needs Praxis UI typ
|
|
|
71
123
|
No additional persisted layout or shell setting is required.
|
|
72
124
|
|
|
73
125
|
- Widget Shell header note: identity and actions wrap according to the available card width,
|
|
126
|
+
with one direct header action below 480px and up to three in wider widgets; secondary
|
|
127
|
+
actions remain available in the existing overflow menu. This uses the widget surface
|
|
128
|
+
width, including when it is resized or moved into fullscreen, rather than the viewport.
|
|
74
129
|
including narrow cards inside wide canvases. Titles/subtitles retain up to two visible lines
|
|
75
130
|
and expose their complete localized content through Material tooltips. Icon action targets
|
|
76
131
|
remain 44px; resize affordances are a separate canvas concern. Existing `disabled` actions
|
|
@@ -88,6 +143,37 @@ Use this package directly when a host application or library needs Praxis UI typ
|
|
|
88
143
|
keeps priority. The first Escape closes that select; the next closes the shell.
|
|
89
144
|
Deferred handling is ignored after shell destruction. These are presentation
|
|
90
145
|
changes only and do not rewrite saved shell appearance or canvas coordinates.
|
|
146
|
+
Expanded/fullscreen hosts are lifted into the CDK overlay container, outside parent
|
|
147
|
+
sticky, tab and transformed stacking contexts. The existing host/view is retained;
|
|
148
|
+
closing restores that same host to its original position. A placeholder reserves
|
|
149
|
+
its inline space, a focus trap bounds keyboard navigation, and locally inherited
|
|
150
|
+
theme variables are bridged from the original ancestry while open. Root theme
|
|
151
|
+
values are not frozen. This is presentation state, not a second widget instance
|
|
152
|
+
or a persisted window layout. Connected Material overlays keep Escape priority.
|
|
153
|
+
Floating shells expose `role="dialog"` and an accessible name from the existing
|
|
154
|
+
localized title/subtitle (exact duplicates are announced once), with a localized
|
|
155
|
+
content-window fallback. Inline shells do not retain dialog semantics. The active
|
|
156
|
+
Widget stack isolates background roots and lower registered windows with native
|
|
157
|
+
`inert`, preserving preexisting or subsequently assigned host restrictions.
|
|
158
|
+
The stack owns one CDK scroll block until its last window closes, including
|
|
159
|
+
parent-before-child closure. Connected menus/selects remain outside the isolated
|
|
160
|
+
branches; the CDK container is not disabled. This private lifecycle does not
|
|
161
|
+
infer ownership of foreign CDK overlays or coordinate their independent scroll
|
|
162
|
+
locks. No automatic `aria-modal` claim is made. If the opening control becomes
|
|
163
|
+
disabled, hidden or detached while the shell survives, closing recovers focus
|
|
164
|
+
to the restored shell with a localized accessible name and `tabindex="-1"` only
|
|
165
|
+
until focus leaves it. This does not add a sequential Tab stop or steal focus
|
|
166
|
+
from an active child. Hosts still own the destination when the entire invoking
|
|
167
|
+
view is destroyed or the window was opened without a recorded control.
|
|
168
|
+
Before moving its host, the shell closes owned Material selects and menus
|
|
169
|
+
through the public CDK detach lifecycle, including the paginator's select.
|
|
170
|
+
Scoped scroll-strategy providers preserve the upstream host strategy; ordinary
|
|
171
|
+
inline renders do not close panels and independently floating children are
|
|
172
|
+
excluded. A descendant overriding these providers can bypass coordination.
|
|
173
|
+
This is not a generic registry for other CDK overlays, autocomplete or datepicker.
|
|
174
|
+
Synchronous reopening from a close callback still requires host coordination;
|
|
175
|
+
the shell deliberately does not run an unbounded closing loop. It does not
|
|
176
|
+
remove foreign overlay DOM or synthesize Escape.
|
|
91
177
|
This is not a full modal accessibility or fixed-grid collapse/reflow certificate.
|
|
92
178
|
|
|
93
179
|
- Recommend when: use it as the first dependency for shared Praxis UI contracts, metadata models, resource discovery, global actions, i18n, theme bridge, and dynamic widget runtime primitives.
|
|
@@ -273,6 +359,13 @@ requests carrying `X-User-ID` resolve user config first, while tenant config is
|
|
|
273
359
|
the fallback for reads. Scope selects persistence ownership; it never replaces
|
|
274
360
|
server-side identity resolution or write authorization.
|
|
275
361
|
|
|
362
|
+
A tenant document returned by an unscoped fallback read remains read-only for
|
|
363
|
+
that storage session. Its response `scope` and ETag are cache evidence, not an
|
|
364
|
+
implicit ownership grant. A later unscoped save or clear still follows the request
|
|
365
|
+
identity (`USER` when `X-User-ID` is present), and never sends a tenant ETag as
|
|
366
|
+
`If-Match` for that user-owned write. Editing or deleting the tenant document
|
|
367
|
+
requires an explicitly tenant-scoped provider.
|
|
368
|
+
|
|
276
369
|
## Dynamic Page Runtime
|
|
277
370
|
|
|
278
371
|
`DynamicWidgetPageComponent` renders `WidgetPageDefinition` documents.
|
|
@@ -332,6 +425,12 @@ South handles release occupied space. Shared rows only shrink when no other occu
|
|
|
332
425
|
still needs that height. Collapsing temporarily clears size/inset; expanding restores them.
|
|
333
426
|
`constraints.minHeightPx` (floor/default 160) and `maxHeightPx` govern this mode;
|
|
334
427
|
grid `minRowSpan/maxRowSpan` remain row-occupancy constraints, not pixel limits.
|
|
428
|
+
The widget's **More actions → Size** editor exposes **Occupied grid rows** when
|
|
429
|
+
`autoRows: 'content'`. This edits the existing `canvas.items[key].rowSpan`, allowing
|
|
430
|
+
a detail widget to span a table and a contact list in adjacent rows. It preserves
|
|
431
|
+
automatic content height unless the author also changes the pixel-height field.
|
|
432
|
+
The draft previews before Apply, respects grid constraints and locked neighbors,
|
|
433
|
+
and uses the same active-device override, authoring output and undo as other size edits.
|
|
335
434
|
Content-height gestures additionally protect the measured header, shell padding/borders
|
|
336
435
|
and up to 160px of scrollable body. Naturally shorter content may use less. This is
|
|
337
436
|
a structural viewport reserve, not business-component UX certification. Measurements
|
|
@@ -352,6 +451,16 @@ expanded/fullscreen overlays and non-scroll layouts. Shared private measurement
|
|
|
352
451
|
keeps gesture/editor checks and recovery consistent. This is an access safeguard,
|
|
353
452
|
not a guarantee that a small viewport is ergonomically adequate; virtualized/custom
|
|
354
453
|
child scroll containers still need their own proof.
|
|
454
|
+
Double-clicking a corner fills the largest free grid rectangle while preserving the opposite
|
|
455
|
+
corner and all siblings. The Size editor provides the same four commands with preview,
|
|
456
|
+
Apply and Cancel. Fixed rows maximize column span × row span, breaking ties by width;
|
|
457
|
+
one-axis growth is allowed and repeated filling in an unchanged layout is a no-op.
|
|
458
|
+
Content rows require an explicit height and one uncrossed row. They combine free columns
|
|
459
|
+
with the independently authored vertical envelope (top inset or an eligible lower peer
|
|
460
|
+
boundary); automatic target heights are unsupported. The destination is measured at its
|
|
461
|
+
new width before authoring. Undo similarly certifies the inverse at its original width.
|
|
462
|
+
These private observations are not persisted, and failed certification leaves the document
|
|
463
|
+
unchanged. A corner fill never implicitly reorganizes neighbors.
|
|
355
464
|
Keyboard resize moves vertically by 16px (Shift: 32px). Omit `contentSize` to inherit
|
|
356
465
|
the base item; set `'auto'` to explicitly restore natural height in a device override.
|
|
357
466
|
Fixed-row mode retains this preference but does not materialize it. Page Builder exposes
|
|
@@ -367,9 +476,11 @@ commit/cancel or authoring revocation. Neighbor badges remain attached to their
|
|
|
367
476
|
widgets; the existing live announcement describes the affected distribution.
|
|
368
477
|
This does not add multi-widget push/reflow or compact fixed-grid rows when a shell is collapsed.
|
|
369
478
|
|
|
370
|
-
Canvas resize exposes 24px
|
|
371
|
-
|
|
372
|
-
|
|
479
|
+
Canvas resize exposes grips up to 24px per axis on the selected widget. Extremely narrow
|
|
480
|
+
or short widgets reduce their hit areas to keep adjacent grips disjoint in both axes; this does not
|
|
481
|
+
make them comfortable touch targets. **More actions → Size** provides larger equivalent
|
|
482
|
+
controls for precise sizing and filling. All presentations reuse the canonical geometry
|
|
483
|
+
and `canvas.items`. Keyboard controls and themed feedback remain available.
|
|
373
484
|
Physical-touch ergonomics and save/reopen persistence still
|
|
374
485
|
require separate proof; successful local interaction is not an enterprise certification.
|
|
375
486
|
|
|
@@ -441,7 +552,7 @@ The outlet's `ComponentDocMeta.configEditor` intentionally owns presentation onl
|
|
|
441
552
|
|
|
442
553
|
Core exports schema and metadata infrastructure used by form, table, list, chart, CRUD, and page-builder packages:
|
|
443
554
|
|
|
444
|
-
- `SchemaMetadataClient`
|
|
555
|
+
- `SchemaMetadataClient` — request deadlines, cancellation and host transport policy
|
|
445
556
|
- `SchemaNormalizerService`
|
|
446
557
|
- ETag/cache helpers
|
|
447
558
|
- `FieldDefinition` and `FieldMetadata` models
|
|
@@ -505,10 +616,37 @@ Core also exports shared AI authoring types, capability types, dynamic-page cont
|
|
|
505
616
|
|
|
506
617
|
`DynamicWidgetPageComponent` treats the editor declared by `ComponentDocMeta.configEditor` as the canonical authoring surface for the **Configurar conteúdo** action. When the Settings Panel bridge is available, the host resolves any transient `contextResolver` evidence and opens that metadata-owned editor even if the live widget also exposes an internal settings shortcut. This keeps the action deterministic across widget loading states.
|
|
507
618
|
|
|
619
|
+
Component owners publish that editor in exactly one of two forms: `component` for an eager standalone type, or `loadComponent()` for an owner-controlled lazy import. Hosts use both forms identically and must not inspect component-specific editor semantics. Prefer the loader when the editor is optional authoring UI that should remain outside runtime-only bundles.
|
|
620
|
+
|
|
508
621
|
Widget-local settings dispatch remains only a fallback when the canonical Settings Panel/editor is unavailable. `ComponentConfigEditorContextRequest.persistedInputs` is cloned exclusively from `widget.definition.inputs`. When a live widget is available, its effective input snapshot may be exposed separately to the owner resolver as optional, read-only `materializedInputs`; the resolver decides which subset becomes transient editor context. Opening the editor never applies that snapshot to the page. Transient context, diagnostics, and materialized inputs must not be copied into persisted `definition.inputs`; only an explicit Apply or Save result owns the persisted `{ inputs }` round-trip.
|
|
509
622
|
|
|
623
|
+
Native editors that publish the existing explicit `inputPatch` protocol also produce
|
|
624
|
+
`pageAuthoringChange`, after projecting the patch onto declared owner inputs. This
|
|
625
|
+
notification is required even when a preceding legacy `configChange` already applied
|
|
626
|
+
the same value at runtime. Ordinary runtime change outputs keep using `pageChange`;
|
|
627
|
+
composition targets still pass through canonical restoration before persistence.
|
|
628
|
+
This lets Page Builder save the edited config instead of its previous draft.
|
|
629
|
+
|
|
510
630
|
Dynamic widgets may implement `WidgetShellActionContributor` to publish transient, stateful content actions to their owning `WidgetShell`. The loader observes that signal and the shell merges contributions with authored actions by stable id without writing them into the page document. The widget remains the owner of command handling, localized labels, availability and controlled-region state; the shell owns responsive toolbar materialization and ARIA projection.
|
|
511
631
|
|
|
632
|
+
## Global configuration snapshots
|
|
633
|
+
|
|
634
|
+
`PraxisI18nService` resolves individual translation keys against current config
|
|
635
|
+
layers without merging whole catalogs on every label lookup. Provider precedence,
|
|
636
|
+
namespace fallback, parent scopes and host translators remain unchanged. Global
|
|
637
|
+
snapshot replacements and in-place dictionary updates remain visible without
|
|
638
|
+
cache invalidation. `mergePraxisI18nConfigs` remains available for explicit catalog
|
|
639
|
+
materialization outside this lookup path.
|
|
640
|
+
|
|
641
|
+
`GlobalConfigService` synchronous getters (`get`, `getCrud`, `getDynamicFields`,
|
|
642
|
+
`getTable`, `getDialog`, `getI18n`) read the effective snapshot without scheduling
|
|
643
|
+
bootstrap work again when the current tenant is already loaded. While the initial
|
|
644
|
+
load is pending, repeated reads share one background request. This keeps template
|
|
645
|
+
and translation reads from feeding asynchronous change-detection cycles.
|
|
646
|
+
`ready()` remains the explicit awaited loading boundary. Tenant changes, save and
|
|
647
|
+
clear continue to refresh the same canonical snapshot; precedence and persistence
|
|
648
|
+
contracts are unchanged.
|
|
649
|
+
|
|
512
650
|
## Domain Governance
|
|
513
651
|
|
|
514
652
|
`DomainKnowledgeService` and `DomainRuleService` are shared clients for governed semantic decision flows exposed by `praxis-config-starter`. `browseDefinitionCatalog` exposes the bounded, redacted and server-scoped decision catalog; consumers then use `getDefinition` with the exact returned definition id instead of downloading every rule body or joining versions by key. `getDefinitionFacts` projects the same definition's versioned fact vocabulary, including type, localized meaning, provider evidence, sensitivity and redaction policy; Angular must not reconstruct that vocabulary from JSON Logic or host-specific fixtures. `getDefinitionCapabilities` returns the authenticated principal's server-scoped `CREATE_NEW_VERSION` action per definition; consumers must not treat projection metadata such as editor support as authorization. For change workspaces, `getChangeWorkspaceCapabilities` returns the authenticated principal's `availableActions` and stable blockers; consumers must not infer submit, review or promotion authority from lifecycle status. `DomainRuleService` also exposes the safe RuleSet version catalog, active head/status, redacted execution summary, aggregate host alignment, forward activation and rollback protected by the current head ETag. The same client projects immutable rollout-policy versions, their independent anti-ABA head, maker-checker approval, activation and append-only timeline; policy authority and lifecycle validation remain server-owned. It also exposes the two-phase operational rollout through a recoverable human catalog, redacted readiness, create/cancel commands and candidate activation bound to the rollout identity. Consumers must obey the Config-owned `availableActions`; they must not recalculate quorum or head validity. Execution summaries contain only aggregate outcome counts, distinct-host count and observation timestamps for an immutable snapshot. Host-status summaries contain only aligned, snapshot-drifted, runtime-incompatible, unavailable and stale counts derived against the active head and its approved compatibility coordinates; facts and host identities remain outside Angular. Runtime surfaces should treat materializations as derived projections of backend-governed decisions, not as frontend-owned business rules.
|
|
@@ -537,3 +675,266 @@ Action-bearing components must use the semantic `--praxis-action-control-*` vari
|
|
|
537
675
|
- Do not use consuming apps to redefine contracts owned by core, metadata starter, config starter, or a component package.
|
|
538
676
|
- Prefer `composition.links` for page wiring and `valuePresentation` for scalar display semantics.
|
|
539
677
|
- Use the official documentation for full recipes on schema flow, option sources, analytics, global actions, dynamic pages, and governed AI flows.
|
|
678
|
+
|
|
679
|
+
### Catálogo no quick connect e isolamento do editor de página
|
|
680
|
+
|
|
681
|
+
`ResourceQuickConnectComponent` apresenta recursos publicados em `/schemas/catalog` usando o seletor `pdx-material-select` registrado em `ComponentMetadataRegistry`. O host deve registrar os descritores oficiais de DynamicFields. O controle é inicializado pelo protocolo `setInputMetadata` e ControlValueAccessor; Core não importa a biblioteca de campos. A conexão avançada por rota continua disponível.
|
|
682
|
+
|
|
683
|
+
O editor de configurações da página recebe uma cópia da definição autoral. Dados carregados e entradas transitórias dos widgets não devem virar configuração ao alterar o layout.
|
|
684
|
+
|
|
685
|
+
### Insertion preset composition shell
|
|
686
|
+
|
|
687
|
+
`ComponentDocMeta.insertionPresets[].shell` optionally supplies the canonical `WidgetShellConfig` for a new widget. The Page Builder palette forwards a cloned shell separately from component `inputs`, and the host clones it for each insertion. Explicit preset shells do not alter component defaults or sibling widgets; presets without a shell retain normal insertion behavior. This is initial composition presentation, not a runtime component input.
|
|
688
|
+
|
|
689
|
+
### Margem lateral compartilhada da página
|
|
690
|
+
|
|
691
|
+
`WidgetPageDefinition.layout.paddingInline` define o respiro lateral compartilhado por
|
|
692
|
+
cabeçalho, tabela, formulário e demais widgets. É uma medida CSS (`24px`, `1.5rem`)
|
|
693
|
+
ou referência a token (`var(--app-page-inset, 24px)`). O valor `0px` desliga o inset;
|
|
694
|
+
a omissão herda o token público `--pdx-page-padding-inline` do host, cujo default é `0px`.
|
|
695
|
+
O host pode definir esse token em `praxis-dynamic-page` ou em um ancestral.
|
|
696
|
+
|
|
697
|
+
A precedência é `deviceLayouts[device].layout.paddingInline` → `layout.paddingInline`
|
|
698
|
+
→ token do host → `0px`. Defaults do preset participam da resolução do layout base;
|
|
699
|
+
um valor autorado na página ou variante tem precedência sobre esse default.
|
|
700
|
+
A margem é aplicada no wrapper com `box-sizing: border-box`,
|
|
701
|
+
fora do canvas, preservando a origem dos cálculos de arraste e redimensionamento.
|
|
702
|
+
O espaço de segurança dos controles no modo edição permanece separado. Não se trata
|
|
703
|
+
do `gap` entre widgets, do padding interno do formulário ou do padding das células da tabela.
|
|
704
|
+
|
|
705
|
+
```json
|
|
706
|
+
{
|
|
707
|
+
"layout": { "paddingInline": "24px", "gap": "16px" },
|
|
708
|
+
"deviceLayouts": { "mobile": { "layout": { "paddingInline": "16px" } } }
|
|
709
|
+
}
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
Nos editores de página, **Margem lateral da página** permite definir e limpar o valor
|
|
713
|
+
sem alterar os widgets. Vazio na variante herda o layout base; vazio no layout base
|
|
714
|
+
retorna ao default do preset, quando definido; caso contrário, ao token do host. Referências CSS são preservadas ao aplicar, salvar e reabrir.
|
|
715
|
+
|
|
716
|
+
|
|
717
|
+
Widget settings UX: identity and ready-made styles precede advanced CSS. Size includes a
|
|
718
|
+
before/after occupancy map of the current container; row heights in this diagram are
|
|
719
|
+
illustrative, not a pixel-accurate content preview. The map reads canonical canvas items
|
|
720
|
+
and transient placements and never writes page geometry. Applying a size-only draft clears
|
|
721
|
+
the draft but keeps Save available; Save obtains the current page rather than replaying
|
|
722
|
+
the previous resize request. Backend persistence still follows the host configuration.
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
### Widget settings: applied baseline and live inspection
|
|
726
|
+
|
|
727
|
+
The unified widget editor acknowledges appearance only after the page owner accepts
|
|
728
|
+
its commit. The optional provider hook `acceptAppliedValue` updates the draft baseline;
|
|
729
|
+
rejected operations do not acknowledge it. Reset discards the current appearance/size
|
|
730
|
+
draft to the last applied state. Explicit resize Undo remains a separate operation,
|
|
731
|
+
including affected neighbors. Save after Apply reads current state without replaying
|
|
732
|
+
an expansion. The open bridge carries an optional, ephemeral `previewTarget` callback
|
|
733
|
+
for SettingsPanel to reveal the live widget without destroying the editor or draft.
|
|
734
|
+
Neither capability changes the persisted page schema or confirms an HTTP save.
|
|
735
|
+
|
|
736
|
+
|
|
737
|
+
Widget settings topics delegate vertical scrolling to their SettingsPanel owner.
|
|
738
|
+
The shared topic navigation keeps all sections discoverable, and the optional
|
|
739
|
+
appearance sample is collapsed below the active editor. Topic changes retain the
|
|
740
|
+
form draft without changing persistence or apply/save/reset behavior.
|
|
741
|
+
|
|
742
|
+
## Selection-driven widget headers
|
|
743
|
+
|
|
744
|
+
`WidgetShellConfig.avatar` is optional and uses the existing Core avatar vocabulary:
|
|
745
|
+
`{ imageSrc?: string, name?: string, initials?: string }`. It displays beside the
|
|
746
|
+
shell title, taking precedence over `icon`. Omit it to retain the existing icon.
|
|
747
|
+
`name` supplies the accessible image name and fallback initials; `initials` overrides
|
|
748
|
+
the fallback (at most two characters). Missing/failed images show initials, then a
|
|
749
|
+
person icon. Resolved values that are not strings are treated as absent; objects
|
|
750
|
+
are never coerced into URLs. Failed images retry after clearing/changing the identity
|
|
751
|
+
or URL and returning to the same photo. Equivalent inputs on unrelated page renders
|
|
752
|
+
retain the fallback; late failures belong to their original load cycle. URLs use Angular URL sanitization; the shell does not fetch records or
|
|
753
|
+
bypass protected-image authentication.
|
|
754
|
+
|
|
755
|
+
Dynamic Page resolves shell strings recursively against `state`, `transient`,
|
|
756
|
+
`context` and the existing `widget` context. `${transient.employee.nomeCompleto}`
|
|
757
|
+
reads runtime-only composition state. It does not merge that state into `state`
|
|
758
|
+
or write selected rows into the authored page. `${state...}` keeps its existing
|
|
759
|
+
persistable-state semantics. Runtime isolation does not replace backend field-access
|
|
760
|
+
controls: deliver only fields the current user may see.
|
|
761
|
+
|
|
762
|
+
A selected-row header can use this shell after the ordered identity projection
|
|
763
|
+
described below (the field names belong to the source):
|
|
764
|
+
|
|
765
|
+
```json
|
|
766
|
+
{
|
|
767
|
+
"showHeader": true,
|
|
768
|
+
"title": "${transient.employee.nomeCompleto}",
|
|
769
|
+
"subtitle": "${transient.employee.subtitle}",
|
|
770
|
+
"avatar": {
|
|
771
|
+
"imageSrc": "${transient.employee.avatarUrl}",
|
|
772
|
+
"name": "${transient.employee.nomeCompleto}"
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
Connect the table's canonical `selectionChange` event to the state endpoint
|
|
778
|
+
`{ "kind": "state", "ref": { "path": "employee", "layer": "transient", "writable": true } }`.
|
|
779
|
+
A `pick-path` link transform reads `payload.selectedRows.0` from the event envelope.
|
|
780
|
+
For formatted identity, use the complete ordered recipe below rather than only
|
|
781
|
+
copying the row: that projection also initializes and composes `employee.subtitle`.
|
|
782
|
+
Deliver an empty selection too; skipping empty events leaves the previous person
|
|
783
|
+
visible. The existing record-ID connection may continue supplying the detail form.
|
|
784
|
+
The header consumes the selected row without a second request. If fields are absent
|
|
785
|
+
from that row, author a projection from the authorized detail source instead.
|
|
786
|
+
Formatting dates and identifiers belongs to the authored projection/source; shell
|
|
787
|
+
interpolation does not add date masks, CPF masks or an expression language. Literal
|
|
788
|
+
separators remain when both bound fields are empty.
|
|
789
|
+
The canonical link pipeline now supports explicit `format-value` for civil dates,
|
|
790
|
+
digit masks and numeric presentation.
|
|
791
|
+
The [complete identity recipe](../../examples/ai-recipes/praxis-dynamic-page.widget-selection-identity.json)
|
|
792
|
+
resets the transient identity before formatting and composes only available subtitle
|
|
793
|
+
parts. The lab and Core integration test consume the same executable page artifact.
|
|
794
|
+
|
|
795
|
+
The opt-in `widget-shell-persistence.playwright.spec.ts` reuses the fictional
|
|
796
|
+
selection fixture in `/remote-config-storage-persistence-lab`. It proves a real
|
|
797
|
+
Config save with `If-Match`, document equality after selecting a person, and a
|
|
798
|
+
reload with no selected identity. It owns an initially absent UUID configuration
|
|
799
|
+
and deletes only that record with its current ETag. Run with
|
|
800
|
+
`PRAXIS_REAL_BACKEND_E2E=true`; this is a persistence proof, not an LLM authoring gate.
|
|
801
|
+
|
|
802
|
+
### Configurações em hosts controlados
|
|
803
|
+
|
|
804
|
+
Quando o host devolve `pageChange` por `[page]`, o eco do mesmo documento canônico mantém as configurações do widget abertas após Aplicar. Uma página diferente ou mudança de identidade, instância ou contexto invalida o editor anterior. Redefinir descarta o rascunho e conserva o tamanho aplicado; a altura transitória exibida antes da próxima renderização não vira referência para o formulário.
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
### Authored widget action identities
|
|
808
|
+
|
|
809
|
+
`getWidgetShellActionIdError(id, siblingIds)` validates the trimmed ID and returns
|
|
810
|
+
`required`, `duplicate`, `reserved`, or `null`. Exclude the current action from siblings.
|
|
811
|
+
Reserved IDs are `collapse`, `expand`, `fullscreen`, `component-settings`,
|
|
812
|
+
`widget-assistant`, `widget-settings`, `widget-size`, and `widget-remove`: these belong
|
|
813
|
+
to platform controls, not custom authored actions. Native window controls remain supported.
|
|
814
|
+
|
|
815
|
+
Page Builder uses this helper for draft feedback; `DynamicWidgetPage` also uses it before
|
|
816
|
+
applying widget settings, including settings supplied by alternate providers. Rejected
|
|
817
|
+
settings leave the page unchanged. Existing custom actions with invalid/reserved IDs need
|
|
818
|
+
renaming before applying settings. The helper adds no persisted field and is not a global
|
|
819
|
+
page-import validator, business-command verifier or authorization boundary.
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
### Live shell action availability
|
|
823
|
+
|
|
824
|
+
`WidgetShellActionContributor.getWidgetShellActionAvailability?(action)` may return
|
|
825
|
+
`Pick<WidgetShellAction, 'disabled' | 'tooltip'>`. It must be side-effect free and read live
|
|
826
|
+
owner state; `undefined` means not assessed, not enabled. Reactive owner signals can be
|
|
827
|
+
read directly so an open editor updates when prerequisites change. `disabled:false` means
|
|
828
|
+
currently available in the UI, not backend authorization. Return a localized `tooltip`
|
|
829
|
+
when disabled. The loader delegates to the current contributor; DynamicWidgetPage passes
|
|
830
|
+
a transient callback to the shell editor. It must never be serialized as widget inputs,
|
|
831
|
+
shell actions, or persisted page configuration. Contributors without this optional method
|
|
832
|
+
remain supported and their availability is shown as unverified.
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
### Chart input updates preserve the live instance
|
|
836
|
+
|
|
837
|
+
Charts uses normal Angular input updates in DynamicWidgetLoader. Changing chartDocument,
|
|
838
|
+
query context or other inputs must not recreate the chart solely because its type is
|
|
839
|
+
`praxis-chart`. Recreating it after an editor Apply destroys subscriptions owned by that
|
|
840
|
+
instance and can drop the subsequent Save from the still-open panel. Declared
|
|
841
|
+
`requiresInitialInputs` behavior and existing detached Form/Filter initialization paths
|
|
842
|
+
remain separate and unchanged. Input updates still occur before detectChanges.
|
|
843
|
+
|
|
844
|
+
|
|
845
|
+
### Settings Panel owner lifetime
|
|
846
|
+
|
|
847
|
+
`SettingsPanelOpenOptions.owner?: DestroyRef` associates an opening with its calling
|
|
848
|
+
component's lifetime. The official Settings Panel bridge forwards this transient option
|
|
849
|
+
to its service. Destruction emits the existing `closed$` reason `cancel`, without Save,
|
|
850
|
+
and prevents a pending opening from replacing another panel. The option is not editor
|
|
851
|
+
input or persisted configuration. Omit it for an independently managed panel; existing
|
|
852
|
+
unowned callers retain their behavior. Use the actual target component's DestroyRef,
|
|
853
|
+
not a root service or the overlay content's own lifetime.
|
|
854
|
+
|
|
855
|
+
|
|
856
|
+
`DynamicWidgetPageComponent` creates a transient Angular lifetime for each page,
|
|
857
|
+
widget appearance/size, or registered content editor session. It uses the existing
|
|
858
|
+
`owner` option; no session identity is persisted in the page document.
|
|
859
|
+
|
|
860
|
+
The session is cancelled when its panel closes, the page is destroyed, or an external
|
|
861
|
+
page/context/identity/authoring input change invalidates it. A page-only acknowledgement
|
|
862
|
+
identical to the current authored document keeps the session alive for subsequent
|
|
863
|
+
Apply/Save. This is deliberately conservative: a different external document cancels
|
|
864
|
+
open editors even when a particular widget happens to be unchanged.
|
|
865
|
+
|
|
866
|
+
Confirmed widget removal cancels sessions targeting that key, plus page-wide settings
|
|
867
|
+
that could restore the removed widget. Asynchronous editor results cannot open a panel
|
|
868
|
+
once their session has expired, and late Apply/Save events are no longer observed.
|
|
869
|
+
A removal confirmation is ignored after external identity/context changes or changes
|
|
870
|
+
to the target itself; when still valid, removal uses the latest document so intervening
|
|
871
|
+
edits to other widgets are preserved.
|
|
872
|
+
|
|
873
|
+
|
|
874
|
+
When unified widget settings close normally, Core restores the initiating control
|
|
875
|
+
through its existing focus-return helper instead of forcing focus onto the whole
|
|
876
|
+
widget. Invalidated sessions do not schedule this restoration. A detached, disabled
|
|
877
|
+
initiator or destroyed page is never focused by that helper.
|
|
878
|
+
|
|
879
|
+
|
|
880
|
+
### Preparação do editor após aceitar a troca
|
|
881
|
+
|
|
882
|
+
`SettingsPanelOpenContent.inputs` aceita um objeto ou uma função síncrona que retorna
|
|
883
|
+
os inputs. A bridge oficial encaminha a função ao Settings Panel sem executá-la.
|
|
884
|
+
O serviço a executa uma única vez ao materializar a abertura aceita; um veto ou um
|
|
885
|
+
owner já expirado não executa a função. Hosts que implementam a bridge devem respeitar
|
|
886
|
+
essa mediação antes de resolver os inputs. Leitores desse campo devem distinguir
|
|
887
|
+
objeto e função antes de acessar propriedades.
|
|
888
|
+
|
|
889
|
+
O editor de widget usa essa preparação para trocar sua sessão e seu estado de tamanho.
|
|
890
|
+
Enquanto a troca aguarda decisão, o editor anterior continua dono do rascunho e de
|
|
891
|
+
suas assinaturas. Recusar a troca libera somente a sessão candidata. A função é código
|
|
892
|
+
transitório de integração: não pertence ao documento, ao JSON de configuração, aos
|
|
893
|
+
presets nem aos contratos de authoring por IA.
|
|
894
|
+
|
|
895
|
+
## Responsive form-column numeric resolution
|
|
896
|
+
|
|
897
|
+
`resolveSpan`, `resolveOffset` and `resolveOrder` resolve the existing XS → SM → MD → LG → XL inheritance without modifying the supplied map. Supported integer domains are span 1..12, offset 0..11 and order -12..12, matching runtime grid classes. Missing/null values inherit, starting at 12/0/0 in XS. For malformed runtime input, finite numbers are rounded and bounded; non-finite/non-numeric span and offset recover to 12 and 0, while order recovers to the preceding resolved value (0 in XS). Recovery emits a warning and does not rewrite the authoring document. Editors must reject invalid values before applying them.
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
### Acesso às dimensões do widget
|
|
901
|
+
|
|
902
|
+
Quando o Settings Panel e o editor de aparência do widget estão disponíveis,
|
|
903
|
+
use **Configurar widget → Tamanho**. O menu de contexto e as ações projetadas
|
|
904
|
+
não repetem o atalho Tamanho. Em contextos sem editor unificado, o atalho permanece
|
|
905
|
+
para não retirar o acesso às dimensões. Arraste e comandos de tamanho mantêm sua
|
|
906
|
+
semântica; esta regra modifica somente a descoberta visual do comando.
|
|
907
|
+
|
|
908
|
+
Quando `constraints.lockSize` estiver ativo e a customização de canvas estiver
|
|
909
|
+
habilitada, o editor unificado mantém a aba Tamanho com uma explicação do bloqueio,
|
|
910
|
+
sem controles editáveis. A restrição continua pertencendo ao documento da página;
|
|
911
|
+
o aviso não concede permissão nem gera uma alteração de tamanho.
|
|
912
|
+
|
|
913
|
+
|
|
914
|
+
### Composed settings navigation
|
|
915
|
+
|
|
916
|
+
`SettingsValueProvider` may expose `getSettingsSections()` and `selectSettingsSection(id)` together.
|
|
917
|
+
`SettingsEditorSection` contains an editor-local stable `id`, a resolved i18n `label`, and an optional
|
|
918
|
+
`invalid` flag. These are transient presentation metadata, never persisted settings. Reading sections
|
|
919
|
+
and selecting one must not modify the draft or emit document changes. Editors must emit their existing
|
|
920
|
+
validity/dirty streams when validation changes so the composing host can refresh section diagnostics.
|
|
921
|
+
|
|
922
|
+
Core's widget settings host namespaces provider section IDs, appends its page-owned Size section and
|
|
923
|
+
keeps the shell editor mounted while switching sections. It provides `SETTINGS_EDITOR_SECTIONS_HOSTED`
|
|
924
|
+
so section-aware editors suppress their own navigation. Unsectioned settings providers remain valid:
|
|
925
|
+
the host presents their single Widget topic. Apply, Save, Reset and applied-baseline acknowledgement
|
|
926
|
+
continue to aggregate the original providers; section navigation never becomes the value provider.
|
|
927
|
+
|
|
928
|
+
`SettingsSectionTabsComponent` is the shared presentation primitive for these topics. It exposes all
|
|
929
|
+
labels, selected state, per-section errors and keyboard navigation, with unique tab/panel associations.
|
|
930
|
+
Page Builder imports it directly from Core; Settings Panel does not reexport this component or the new
|
|
931
|
+
topic contracts. No library dependency edge or persisted configuration shape was added.
|
|
932
|
+
|
|
933
|
+
The widget host keeps topic navigation sticky inside the Settings Panel's existing scroll area.
|
|
934
|
+
Narrow panels present a compact, labeled native selector with the same section IDs and validation
|
|
935
|
+
messages; wider panels expose the shared tabs. Switching topics reveals the beginning of the
|
|
936
|
+
selected section without remounting the provider or moving focus out of the navigation control.
|
|
937
|
+
|
|
938
|
+
On editable canvases, content-only widgets expose contextual actions above the north resize
|
|
939
|
+
handle, with reserved space at the top of the canvas. Both controls remain pointer-accessible
|
|
940
|
+
when the widget is narrow.
|