Context
Studio's app template can hold a NavBar (or similar widget) whose content
is assembled from navigation entries declared deep inside modules and
features — a many-contributors-to-one-consumer shape the language doesn't
have a construct for yet. layout slots are the wrong tool: they express
one parent placing one block of content into one region, not many children
contributing into a collection.
Proposal
Generic mechanism: contribute to <Name>
A widget declares it accepts contributions under a name (no generic
"channel" noun needed — the contribution point is just named like any
other construct, e.g. Navigation):
layout AppShell
template
navbar contributes Navigation
main
Anything anywhere in the module/feature tree can contribute to it, without
knowing or caring who's listening:
navigation-item
contribute to Navigation
navigate to InvoiceDetails by invoiceId // implicit default property
label NavLabel
order 10
contribute to X opens a property bag shaped by whatever X declares it
needs. For Navigation, navigate to <Screen> [by <param>] is the
implicit default property (reusing the exact syntax on row-click already
uses) — a bare navigate to X with no block still works and targets the
nearest-enclosing contribution point. Other contribution points (e.g. a
future Notifications point) would declare a different required shape
entirely — the mechanism is generic, Navigation is just its first user.
Resolution rule
A contribution attaches to the nearest enclosing template that declares
a matching contribution point, walking outward the same way bare name
references already resolve inside-out. A module with its own
contributes Navigation subnav stops features inside it from bubbling to
the app shell; without one, contributions keep walking out. This gives
unlimited nesting (app nav, module subnav, feature sub-subnav) for free,
with no new resolution algorithm.
An optional explicit override (navigation-item ... in <ContributionPoint>)
should exist for the rare case where nearest-enclosing isn't wanted —
mirrors explicit query qualification (Queue.All) being the override to
the bare-name default.
Route arguments
Arguments (e.g. an id flowing into a URL) are not string
interpolation. They reuse the existing typed navigate ... by <param>
binding, checked by the compiler the same way any other bare-name
reference is. How that becomes a URL/query-string/native deep link is a
rendering concern owned by the NavBar widget implementation, not the
model.
Open questions
- Ambiguity handling when a bare contribution matches two equally-near
contribution points — should mirror the existing "ambiguous query"
warning (named candidates, not a silent pick).
- Ordering/grouping properties (
order, group) needed for anything
beyond a flat nav list — worth scoping now vs. later.
Dependencies
Blocks
Part of the screen work — build order and full dependency map: Cratis/Scene#7
Context
Studio's app template can hold a NavBar (or similar widget) whose content
is assembled from navigation entries declared deep inside modules and
features — a many-contributors-to-one-consumer shape the language doesn't
have a construct for yet.
layoutslots are the wrong tool: they expressone parent placing one block of content into one region, not many children
contributing into a collection.
Proposal
Generic mechanism:
contribute to <Name>A widget declares it accepts contributions under a name (no generic
"channel" noun needed — the contribution point is just named like any
other construct, e.g.
Navigation):Anything anywhere in the module/feature tree can contribute to it, without
knowing or caring who's listening:
contribute to Xopens a property bag shaped by whateverXdeclares itneeds. For
Navigation,navigate to <Screen> [by <param>]is theimplicit default property (reusing the exact syntax
on row-clickalreadyuses) — a bare
navigate to Xwith no block still works and targets thenearest-enclosing contribution point. Other contribution points (e.g. a
future
Notificationspoint) would declare a different required shapeentirely — the mechanism is generic,
Navigationis just its first user.Resolution rule
A contribution attaches to the nearest enclosing template that declares
a matching contribution point, walking outward the same way bare name
references already resolve inside-out. A module with its own
contributes Navigationsubnav stops features inside it from bubbling tothe app shell; without one, contributions keep walking out. This gives
unlimited nesting (app nav, module subnav, feature sub-subnav) for free,
with no new resolution algorithm.
An optional explicit override (
navigation-item ... in <ContributionPoint>)should exist for the rare case where nearest-enclosing isn't wanted —
mirrors explicit query qualification (
Queue.All) being the override tothe bare-name default.
Route arguments
Arguments (e.g. an id flowing into a URL) are not string
interpolation. They reuse the existing typed
navigate ... by <param>binding, checked by the compiler the same way any other bare-name
reference is. How that becomes a URL/query-string/native deep link is a
rendering concern owned by the NavBar widget implementation, not the
model.
Open questions
contribution points — should mirror the existing "ambiguous query"
warning (named candidates, not a silent pick).
order,group) needed for anythingbeyond a flat nav list — worth scoping now vs. later.
Dependencies
Blocks
contribute tointoScene.ModelPart of the screen work — build order and full dependency map: Cratis/Scene#7