Navigation

Screens and a stack, not a router.

app.screens.register({ id: 'services', component: <Services /> });
app.screens.register({ id: 'detail', component: 'TaskDetail' });   // or a registered name
app.screens.reset('services');

app.screens.push('detail', { taskId: 'billing' });
app.screens.pop();          // focus is restored to where it was

The screen on top of the stack is a mount in a surface, exactly like root is. That is what makes it a screen and not a second rendering path: the shell arranges it, the layouts apply to it, and anything reading the surface registry sees it. Only the top is mounted - what a screen underneath keeps is its store scope, not its instances.

surface says where it goes, and defaults to main. A surface is the application’s word, so a screen that wants to be a side panel says surface: 'inspector' and nothing in the library has to know what that means.

Parameters arrive twice, on purpose. They are spread onto the screen’s node as props, which is the readable way for a screen to take an id; and they are published at $/layout/screen/params, which is the only way to read them eight levels down without every box in between forwarding something it does not care about.

const TaskDetail = defineComponent<{ taskId?: string }>('TaskDetail', ({ taskId }) => );

// or, from anywhere inside the screen
const { id, params } = useScreen<{ taskId: string }>();
const nav = useNavigate();

Each screen is its own focus scope, named screen:<id>. Tab order belongs to what is on screen rather than to the application, and it is why pop can put focus back: “where it was” is a question about a scope that died with its screen, not about an id that outlived it.

A screen’s own store scope ($/screen.<id>/…) is cleared when it is popped, unless it declared keepAlive. The current entry is published at $/layout/screen/current and the stack at $/layout/screen/stack, so a breadcrumb or a back button is a when clause rather than a subscription.


Back to top

MIT licensed. Pre-1.0 - the surface is still moving.