-
Notifications
You must be signed in to change notification settings - Fork 0
Host UI and Surfaces
Forsetti does not let modules mutate host UI directly. UI and app modules publish structured UIContributions, the runtime validates those contributions against capability and manifest declarations, and the host decides how approved contribution data is rendered.
flowchart LR
Active["Active UI/app module"] --> Contributions["UIContributions"]
Contributions --> Validate["ModuleManager validation"]
Validate --> Sanitize["Runtime sanitization"]
Sanitize --> Surface["UISurfaceManager"]
Surface --> Toolbar["toolbarItems"]
Surface --> Slots["viewInjectionsBySlot"]
Surface --> Overlay["overlaySchema"]
Surface --> Theme["themeMask"]
Toolbar --> Host["Host view"]
Slots --> Host
Overlay --> Router["ForsettiHostOverlayRouter"]
Theme --> Host
The default runtime model applies contributions from the active UI/app module only. Switching UI modules deactivates the previous UI module and clears its contributions before publishing the new surface state.
ModuleManager currently sanitizes themeMask to nil before applying contributions to UISurfaceManager. Theme masks can still be declared and validated through capability and manifest requirements, but default shell theming remains host-controlled.
| Type | Structure | Required Capability | Host Responsibility |
|---|---|---|---|
| Toolbar item | ToolbarItemDescriptor |
toolbar_items |
Render title/icon and invoke ToolbarAction. |
| View injection | ViewInjectionDescriptor |
view_injection |
Resolve viewID through ForsettiViewInjectionRegistry and place it in a known slot. |
| Overlay schema | OverlaySchema |
routing_overlay |
Resolve pointer and route IDs through OverlayRouting. |
| Theme mask | ThemeMask |
ui_theme_mask |
Current default runtime validates then strips before publication; custom hosts may add explicit support later. |
flowchart TD
Manifest["runtimeRequirements.ui"] --> Theme["themeIDs"]
Manifest --> Views["viewIDs"]
Manifest --> Slots["slotIDs"]
Manifest --> Toolbar["toolbarItemIDs"]
Manifest --> Routes["routeIDs"]
Manifest --> Pointers["pointerIDs"]
Contributions["UIContributions"] --> Check["Validate every contributed ID"]
Theme --> Check
Views --> Check
Slots --> Check
Toolbar --> Check
Routes --> Check
Pointers --> Check
Check -- pass --> Publish["Publish sanitized surface state"]
Check -- fail --> Block["unsatisfiedRuntimeRequirement"]
Template 1.1 modules with UI contributions must declare the IDs they will publish. This lets reviewers and hosts understand a module's UI footprint before activation.
sequenceDiagram
participant Module as UI Module
participant Manager as ModuleManager
participant Surface as UISurfaceManager
participant Registry as ViewInjectionRegistry
participant Host as Host View
Module-->>Manager: uiContributions.viewInjections
Manager->>Manager: capability and declaration validation
Manager->>Surface: apply(moduleID, sanitized contributions)
Surface-->>Host: viewInjectionsBySlot
Host->>Registry: resolve(viewID)
Registry-->>Host: AnyView
Host-->>Host: render slot by priority
View injections are sorted by slot, then by descending priority inside each slot. The host must register every resolvable viewID; a valid contribution can still render blank if the host does not provide the matching view builder.
| Action | Runtime Behavior |
|---|---|
navigate(pointerID:) |
Calls runtime.openPointer(pointerID) through the configured router. |
openOverlay(routeID:) |
Calls runtime.openRoute(routeID) through the configured router. |
publishEvent(type:payload:) |
Publishes a ForsettiEvent on the runtime event bus. |
flowchart TD
Click["User clicks toolbar item"] --> Action{"ToolbarAction"}
Action -- navigate --> Pointer["openPointer(pointerID)"]
Action -- openOverlay --> Route["openRoute(routeID)"]
Action -- publishEvent --> Event["eventBus.publish"]
Pointer --> Router["OverlayRouting"]
Route --> Router
Event --> Subscribers["Framework and module subscribers"]
Toolbar action IDs must be declared in runtimeRequirements.ui when they reference routes or pointers.
ForsettiHostOverlayRouter resolves active overlay pointers and routes from UISurfaceManager.overlaySchema.
flowchart TD
Request["Pointer or route request"] --> Schema{"Active overlay schema?"}
Schema -- no --> NoSchema["schemaUnavailable"]
Schema -- yes --> Found{"Reference found?"}
Found -- no --> Missing["missingPointer or missingRoute"]
Found -- yes --> Destination{"Destination type"}
Destination -- base --> Base{"Known base destination?"}
Destination -- moduleOverlay --> Slot{"Known slot?"}
Base -- yes --> BaseOK["pointerResolved or routeResolved"]
Base -- no --> BadBase["invalidBaseDestination"]
Slot -- yes --> SlotOK["routeResolved"]
Slot -- no --> BadSlot["invalidSlot"]
Overlay schemas should reference stable host catalog IDs. The module declares route and pointer IDs; the host decides which base destinations and module overlay slots are allowed.
| Context | Recommended Host Behavior |
|---|---|
| Production Pattern A | Hide shell controls and render the app module's primary view directly after successful boot and activation. |
| Production Pattern B | Render the active UI/app module and keep service module controls out of end-user UI. |
| Developer Pattern C | Show module lists, lock state, compatibility details, selected module, toolbar feedback, and errors. |
| Dashboard Pattern D | Show intentional navigation among app modules and make the dashboard a product surface. |
- Treat
UISurfaceManagerstate as presentation input, not domain truth. - Register every injectable
viewIDwith the host'sForsettiViewInjectionRegistry. - Keep slot names stable and documented in the host app.
- Keep base destination catalogs and module overlay slot catalogs host-owned.
- Avoid embedding host-only assumptions inside reusable modules.
- Prefer toolbar actions and overlay routes over direct host references.
- Declare
toolbar_items,view_injection,routing_overlay, andui_theme_maskcapabilities before contributing those surfaces. - Declare every contributed UI ID under
runtimeRequirements.uifor manifest template1.1. - Do not rely on
themeMaskpublication in the default runtime path; apply host shell theming through host-owned code.