@roughbook/ui
v0.4.2
Published
Roughbook's presentational components, shared by the web and the studio's local UI.
Readme
@roughbook/ui
Roughbook's presentational components, shared by the web (this repo) and the studio's local UI
(roughbook-studio/ui, a Vite + React app). They take data as props, and get everything else
(links, navigation, actions) from the host app through one context. Nothing here imports
next/*, a server action or the filesystem.
Using it
Wrap the app in UiHostProvider:
import { UiHostProvider, type UiHost } from "@roughbook/ui";
const host: UiHost = {
Link: (props) => <a {...props} />,
navigate: (href) => router.go(href),
previewSrc: ({ page, component, iteration }) => `${devUrl}/rough-preview/${page}/${component}/${iteration}`,
// Optional: a still picture of each iteration, for cards.
thumbnailSrc: ({ page, component, iteration }) => `/thumbnails/${page}/${component}/${iteration}`,
actions: {
rejectIteration: async (form) => post("/api/reject", Object.fromEntries(form)),
// ...
},
};
<UiHostProvider host={host}>{app}</UiHostProvider>;Linkrenders links within the app:next/linkon the web, an anchor elsewhere.navigatemoves to another screen, as Compare does when an iteration is removed.previewSrcis the address that renders one iteration on its own, in Compare.thumbnailSrc, optional, is the address of a still picture of one iteration, which cards show. A host without it shows each card live throughpreviewSrc. The web passes its thumbnail route; a card whose picture is missing or fails shows its name and aStatusDot.actionsare what the designer may do. Form actions get the form's fields, always withproject,page,componentanditerationId;UiActionsinsrc/host.tsxlists the rest for each. A control whose action is left out is not shown, so a host offers only what it supports.
Links follow the web's paths under each component's base: ${base}/<iteration>,
${base}/iterations and ${base}/iterations/compare?ids=<id>,<id>. A host with its own router
uses the same paths.
Styles are Tailwind v4 utilities on Roughbook's shell tokens. Import the theme after Tailwind; it also tells Tailwind to scan this package:
@import "tailwindcss";
@import "@roughbook/ui/theme.css";Set --font-sans, --font-display and --font-mono on the page (the web uses next/font:
Inter, Space Grotesk and IBM Plex Mono).
What is here
- Iterations:
IterationCard,PreviewCardand thePreviewPictureboth draw (athumbnail, orlivefor a stage: the scaled frame that runs the design),Stage,AppPreview(an app-mode iteration through the repo's dev server, with the screenshot fallback),PreviewFrameandPreviewSurface(the one preview frame of the frameworks plan: a live page, the latest rendered images or the studio's own server's page under the same chrome, with the environment's viewports and variants, the iteration's state and progress, Reload, Open and Start the app for a page, Render again and On the device for images; frames load only while on screen, four at most; the pure parts are importable from@roughbook/uiwithout JSX:frameStatus,previewAddressand the variants' query parameters,termLabelfor the stack's words beside Roughbook's,fitScale,shouldReload,noteSeen,liveSet,frameControlsandsnapshotImageName),LineageTree,CompareView(whoseviewportsandframelet a host draw each column with its own frame), andIterationInspector: Direction, Hypothesis, Review, Rating and Notes open, the rest under a native "Details", and no row for what is not known. The host passes what it knows and its own controls ascontrols(review, rating, notes, and the studio's run, tests and screenshots);inspectorRows(input)is the same split without JSX. - Decisions:
SelectConfirmDrawer,RejectDrawer,ForkDrawer,ReviewButton(the review drawer and its history),IterationNotesForm,ReviewPrompts, and ratings:RatingForm(the designer's own, saved on a press),RatingField(the same in the select and reject drawers) andRatingBadge(the team's average on a card), shown where the host hasrateIteration. - Delivery:
PromotePanel,InteractiveResultPanel. - Parts:
Drawer(drawn on the page's body once hydrated, so no layer of the page covers it),Field,TextInput,Notes,Section,ChipSelect,SaveSectionButton,ToggleButton,DeleteConfirmForm,ReadinessPill,ReadinessList. - Quiet:
HelpTip(a?that opens its children on click or tap, where an explanation goes instead of a sentence on the page) andStatusDot(a state as a dot, its word in the tooltip andaria-label).iterationGlyph(iteration, selectedNumber)picks an iteration's dot: selected, making, failed, rejected, promoted or none. - Canvas:
Canvas, a project's pages as sections, components as frames and iterations as cards, moved as one container: pan with space-drag, middle-drag, a drag or two-finger scroll, zoom with a pinch or Ctrl-wheel; Shift 1 fits everything, Shift 2 the selection, arrows move the selection, Enter goes in or opens, Esc comes out,/goes to the prompt and L to the list. It draws only what is on screen, as arole="grid"of links. The host owns the selection and gives the selection's actions (SelectionToolbar,selectionToolbarItem) and the prompt (PromptBar, a<form>whose action comes from the host).CanvasListis the same canvas as a list, which a phone always shows;CanvasSection,CanvasFrame,CanvasCard,CanvasFoldandCanvasDesignSystemare its pieces.useContextPanelopens the panel from a host's own control. Canvas cards passprefetch={false}to the host'sLink; a host of plain anchors drops it. WithcardViewandonCardViewChangethe canvas filters and sorts its cards and drawsCanvasFilter(decision, generation, sort) beside the zoom controls and above the list; the card under the pointer, or the selected card, shows its family as lines (lineage);controlsRefgives a hostCanvasControls(select, revealing a card folded away or filtered out, zoom, fit, list). - Palette:
CommandPalette, ⌘K or Ctrl K or its button: a field, the commands a query finds (matchCommands), arrows, Enter and Esc. The host gives the commands (PaletteCommand: id, label, group, hint, keywords, quiet) andonRun;showKeys={false}leaves ⌘K to the button's title. A page with no bar puts it inStage'spalette(first among the header's controls, and beside Exit fullscreen);Stage's andCompareView'scontrolsRef(StageControls,CompareControls) let its commands choose the width and the rest, andReviewButtonopens from outside withopenandonOpenChange. - Vocabulary and logic, also importable from Node without JSX:
@roughbook/ui/iteration-status(statuses, rejection reasons, refinement presets, generation states),@roughbook/ui/reviews(review fields, checks and decisions),@roughbook/ui/canvas(CanvasInput,layoutCanvas,zoomLevel,visibleItems,fitRect,neighbour,focusFromPath/pathForFocusbetween a canvas route and its focus, the card view (CardView,cardMatches,cardOrder) and a card's family (lineageOf,lineageLinks)) and@roughbook/ui/commands(matchCommands).
The package ships TypeScript source, so its consumer compiles it: Next.js does for workspace
packages, and Vite does for the studio's UI, which is bundled into the studio package.
npm run type-check -w @roughbook/ui checks it without the web's @/ paths.
