Workspaces¶
A workspace shows several variants at once: a grid of states for review, a strip of tabs, or a page of prose with live variants between the paragraphs. Chapter 2 introduced the explicit grid. This page covers every layout.
Each :layout needs its own slot:
| Layout | Needs | Use it when |
|---|---|---|
:grid |
:variants |
You want explicit variants in a specific order. |
:variants-grid |
nothing, :for or :variants |
You want every variant under a story parent, or a curated list of them. |
:tabs |
:variants |
You want one variant visible at a time. |
:prose |
:content |
You want prose interleaved with rendered variants. |
A missing slot, or a slot the body does not accept, throws
:rf.error/workspace-shape at registration. Most projects start with :grid
and :variants-grid, and add :tabs or :prose when a component or workflow
needs real documentation.
Grid¶
(rf.story/reg-workspace :Workspace.login-form/all-states
{:doc "The five login states side by side."
:layout :grid
:variants [:story.login-form/idle
:story.login-form/submitting
:story.login-form/error
:story.login-form/submitting-retry
:story.login-form/authenticated]
:columns 3})
:columns fixes the column count of a :grid or :variants-grid; without it
the grid fits as many columns as the width allows. A view wider than its cell
scrolls inside the cell. A grid renders its first 100 cells and offers
+N more for the rest, up to 400.
Variants grid¶
:variants-grid lists every variant under a parent story for you:
(rf.story/reg-workspace :Workspace.login-form/auto-grid
{:layout :variants-grid
:for :story.login-form
:columns 3})
Use an explicit grid when the order is part of the story you want to tell. Use
:variants-grid when you want every variant under a parent to appear without
maintaining the list by hand. The cells come in variant-id order. :for names
the story; without it, the workspace id does, so :Workspace.login-form/auto-grid
enumerates :story.login. Give it :variants instead of :for, and it
renders exactly those variants.
A :variants-grid mounts every cell at once, each in its own frame. A view
that creates its own frame provider internally defeats that, because its cells
end up sharing state. For such a view, :isolation :shared mounts one cell at
a time, with previous and next buttons to move between them.
Tabs¶
:tabs mounts one variant at a time, under a strip of tabs:
(rf.story/reg-workspace :Workspace.login-form/tabs
{:layout :tabs
:variants [:story.login-form/idle :story.login-form/error]})
Prose¶
:prose interleaves Markdown with variants, in order:
(rf.story/reg-workspace :Workspace.login-form/guide
{:layout :prose
:content [{:type :prose :body "## Signing in\nThe form starts empty."}
{:type :variant :id :story.login-form/idle}
{:type :prose :body "A rejected password re-enables the form."}
{:type :variant :id :story.login-form/error}]})
A variant's Docs mode page also shows the prose of any
:prose workspace that includes it.
What the cells share¶
Each cell's frame has its own app-db, event queue, subscription cache and epoch history, while every frame runs the same registered handlers (What a frame is). If a cell dispatches an event, it changes that cell's frame and no other.
A frame isolates state, not the page. Every cell renders into the one page that hosts the shell:
- that page's stylesheets reach every cell;
- only one element on the page can hold focus;
- a modal that a view portals into
document.bodylands on the shared page, outside its cell.
Text colour and font are reset at the cell boundary, so a view renders in the browser's default text styles rather than the shell's. A view that relies on text styles inherited from its app's shell must set them itself, for example in a decorator.
Storybook renders stories in a preview iframe, although its docs pages can render them inline in the page itself. Story's canvas and workspaces have no iframe mode, so a job such as checking that a design system's CSS holds up without the host page's stylesheets around it needs a tool that provides an iframe boundary.
The background picker's colour sits behind each cell's view as well as behind the canvas (Modes, viewports and backgrounds).
Troubleshooting¶
| Symptom | Cause | Fix |
|---|---|---|
| Automatic grid includes a new unwanted variant | :variants-grid enumerates the parent |
Use an explicit :grid when the review set is curated. |
:rf.error/workspace-shape |
Required slots or mutually exclusive fields are wrong | Give grid/tabs :variants, prose :content, and automatic grid only one of :for or :variants. |
| Only the first cells appear | The grid reached its display cap | Use +N more, or split a large catalogue into focused workspaces. |
| A portalled dialog covers neighbouring cells | Cells share a browser document | Review that variant alone or adapt the portal target. |