Optional Router navigator#
Import from @fairylights-studio/ngx-m3-adaptive/router. Only applications using
this secondary entrypoint need Angular Router.
Architecture: Shareable URLs & In-Memory Shadow Stack#
The router integration decouples the browser URL from session history:
- Shareable URL: The URL strictly reflects only the currently active Destination (e.g.
?pane=primary:42), never a serialized history trail. URLs can be copied, sent to colleagues, or bookmarked. - In-Memory Shadow Stack: Complete Material 3 navigation history and
BackBehaviorpolicies (PopLatest,PopUntilScaffoldValueChange, etc.) are maintained in memory during the active session. - Synthetic Root: Opening an external deep link directly seeds the shadow stack with a fallback root beneath the active destination, so in-app Back navigation never encounters a dead end.
- Clean Root URL: At the root destination (e.g. Inbox list), the query parameter is omitted entirely (e.g.
/inbox). - Workspace Memory: The in-memory
MatPaneRouteMemoryServicecaches workspace state keyed by an explicitcacheKey, safely restoring the user's selected pane when switching between top-level routes without cross-tenant collisions. - Template Helpers:
navigator.queryParamsFor(pane, key)andnavigator.linkCommandsFor(pane, key)allow seamless integration with native<a [routerLink]>elements.
Usage#
import {
createMatPaneQueryParamCodec,
createMatPaneRouterNavigator,
matPaneGuard,
} from '@fairylights-studio/ngx-m3-adaptive/router';
@Component({
...
})
export class MessagesComponent {
readonly navigator = createMatPaneRouterNavigator(
createMatPaneQueryParamCodec({
queryParam: 'pane',
fallbackRoot: { pane: 'secondary', contentKey: null },
}),
{
cacheKey: 'inbox-messages', // Or dynamic: (snapshot) => `${snapshot.params['orgId']}:inbox`
},
);
}
Route Guard#
Validate pane query parameters and reject malformed/unknown roles at the route level:
export const routes: Routes = [
{
path: 'inbox',
component: MessagesComponent,
canActivate: [matPaneGuard],
},
];
Template Links (<a [routerLink]>)#
Enable middle-click (open in new tab) and right-click (copy link) with native hyperlinks:
<a [routerLink]="[]" [queryParams]="navigator.queryParamsFor('primary', message.id)">
{{ message.subject }}
</a>
Query-param Wire Format#
| Destination | Encoded Query Parameter | Rendered URL |
|---|---|---|
{ pane: 'secondary', contentKey: null } (Root) |
(omitted) | /inbox |
{ pane: 'primary', contentKey: null } |
?pane=primary |
/inbox?pane=primary |
{ pane: 'primary', contentKey: 'msg-42' } |
?pane=primary:msg-42 |
/inbox?pane=primary:msg-42 |
{ pane: 'primary', contentKey: 'key:with:colons' } |
?pane=primary:key%3Awith%3Acolons |
/inbox?pane=primary:key%3Awith%3Acolons |