-
Notifications
You must be signed in to change notification settings - Fork 0
Description
So my philosophy on nested routing is, the top level is a discriminated union, but when a particular case of that union is active, another union is possible. The parent union doesn't need to be aware of the child union's existence.
And that can repeat recursively. Theoretically, two sibling child unions can coexist and overlap.
The problem is, there is only one URL on the page. And competing routers would just be annoying. But a good thing about superouter is, that is not a part of its concern as superouter has no side effects.
So I think the root router is always updated whenever a child router updates. And the side effects simply observes the root, not the child.
A child router should therefore not be defined as part of the root router's definition. Or at least, it should not be a requirement.
So given all that, the API I'm imagining is something like this:
let Route = superouter.type({
Home: "/",
Messages: "/messages"
Settings: "/settings/:page",
Other: "/other",
});
let Messages = Route.Messages.type({
Rooms: "/rooms",
Settings: "/settings"
})
let Rooms = Messages.Rooms.type({
Message: "/:room_id",
Settings: "/settings"
})
let RoomSettings = Rooms.Settings.type({
Home: "/",
ConfirmDanger: "/danger/confirm",
Danger: "/danger"
})
// as always
Route.toURL( Route.Messages() )
// => '/messages'
// but a new method
Route.toRootURL( Route.Message() )
// => '/messages'
// For the root route, they are equivalent, but for a nested route...
RoomSettings.toURL( RoomSettings.ConfirmDanger({ room_id: 1 }) )
// => '/danger/confirm'
RoomSettings.toURL( RoomSettings.ConfirmDanger({ room_id: 1}) )
// => '/messages/rooms/1/settings/danger/confirm'You'll notice that room_id had to be passed in, even though RoomSettings doesn't have any parameters in the URL's. This would be enforced by superouter.
In a framework that uses superouter, this parent state could be automatically threaded through so that RoomSettings.ConfirmDanger().value.room_id would be valid.
Each subroute would still have the standard methods, e.g. matchOr. Which would pass a global URL into a local subroute object. But for symmetery there would be matchLocalOr which would only parse a suburl, which may be handy for building relative hrefs.
RoomSettings.matchOr( () => RoomSettings.Home(), window.location.pathname )
From superouters perspective, a subroute is the same as a root route but it inherits the prefix of a parent route, and all property validation of the parent. The type name of the route would also inherit the type name of the parent as a prefix. E.g. The type name could then be enforced to be globally unique in a framework (if required).
RoomSettings.ConfirmDanger({ room_id: 1})
// { type: 'Route.Messages.Rooms.Settings', tag: 'ConfirmDanger', value: { room_id: 1 } }