The toolbar
Bundleware.defineToolbar(<MyToolbar />) registers the component that renders the
toolbar. It runs while the toolbar is shown and must render exactly one <Toolbar>:
| Part | Props |
|---|---|
<Toolbar> | icon (brand image, 16 px on the plate), theme (below), wordmark? (the plate's text, default @name), badge? (an edition badge, such as '2027 EDITION'), layout? ('classic', 'player', 'ticker' or 'floating-character'), styles? (Styling) |
<Toolbar.Button> | A command. kind?: 'tab' (default) stands on the shelf; 'button' and 'default' are push buttons. |
<Toolbar.Menu> | title, icon?, ink?, note? (fine print at the foot); children are <Toolbar.Menu.Item> commands and <Toolbar.Menu.Section title?> groups of them. |
<Toolbar.SplitButton> | A command for the button itself, plus <Toolbar.Menu.Item> children for its arrow. |
<Toolbar.Module> | A tall index tab: title, subtitle?, icon on an ink tile, ink?, and a command. As the bar narrows it drops the subtitle, then the text. |
<Toolbar.Search> | placeholder, and either url with exactly one {q} or onSearch(text); buttonTitle?, icon?, width? ('narrow', 'med', 'wide'), note?. Children are up to 12 suggestion rows: <Toolbar.Search.Suggestion title subtitle? icon? ink? badge? buttonTitle?>, where {q} in title stands for the typed text, and menu items or sections. |
<Toolbar.Strip> | A full-width band under the bar for something that changed the page: text, note?, icon?, ink?, and one button (buttonTitle with onAction or action). One per toolbar. |
<Toolbar.Text> | text |
<Toolbar.Status> | text, title? (bold leading text), dot? ('green', 'red', 'yellow') |
<Toolbar.Separator> | |
<Toolbar.Right> | Parts aligned to the right edge. The floating-character layout has none. |
<Toolbar.Widget> | Exactly one component element, rendered in the band: widgets. |
An icon is an Icon constant (Icon.Search is the string 'search') or SVG
markup you wrote: self-contained, without scripts, styles, event handlers or
external references.
Commands, menus and modules take an ink? for their cap; menu items also take
subtitle? and badge?. Bars are 32 px and step down from Wide to Medium and
Narrow before anything overflows; commands at the right edge go first, into the »
menu.
The theme
| Key | |
|---|---|
ink | One of the nine inks: steel, tangerine, leaf, grape, cherry, teal, gold, night, paper. It colours the plate and the caps of parts without their own ink. |
brandColor | Without ink, a hex colour; the plate takes the nearest ink. |
brandShape | The plate: 'slant' (default), 'flag' or 'block'. Older shapes draw a slant plate. |
background | One background image under the parts: CSS gradients and data: SVG or PNG URLs only, at most 32 KiB. |
dark | Light text and status on the bar, for a dark background. |
accent | An ink or hex colour; while a background shows, the shelf line takes it. |
Bundleware 0.3's theme options (palette, appearanceOverrides, font, bevel,
divider, buttonShape, era, height and brandTextColor) still load and are
ignored.
The toolbar component is a component like any other: it can use hooks, and parts
can come from your own components (function SummaryMenu() { return <Toolbar.Menu …/> }).
When it re-renders, the host updates the row in place: titles, icons, disabled and
checked change, parts appear and disappear, and widgets keep running. Its effects
run while the toolbar is shown, so a useEffect in it is the place for toolbar-wide
timers and listeners. Parts render only in the toolbar's row; inside a widget they
throw, and the row reports text or elements put directly in it.
Commands and actions
<Toolbar.Button> and <Toolbar.Menu.Item> take a title, optional icon,
tooltip and disabled, and do exactly one thing:
onAction={() => …}: runs your function. While a promise it returns is pending, the command is busy; a thrown error's message appears beside it.action={<Action.OpenInBrowser url="https://…" />}: a real link, opened in a new tab. Links cannot be disabled or checked.action={<Action.OpenWindow title="Details" target={<Details />} />}: openstargetin a window.action={<Action.ShowPopup popup={{ variant: 'unavailable', title: 'Hi' }} />}: a canned dialog.
checked makes an onAction command checkable, and is controlled, as form fields are
in React: the checkmark shows your state, and onAction changes it.
<Toolbar.Menu.Item title="Compact" checked={compact} onAction={() => setCompact(!compact)} />Widgets and windows
A widget is any component in <Toolbar.Widget>: it renders in its slot in the band,
with ordinary elements, and its props are the values the toolbar passed, functions
and objects included, updating in place when the toolbar re-renders. A window's body
is any component you open, with <Action.OpenWindow target> or
context.openWindow(<Details />, { title }); it receives your props plus close().
Mounts end when the toolbar is hidden or removed, when the page reloads or an in-page navigation leaves the toolbar's site rules, and while the toolbar stack makes way for an overlay it cannot fit around (such as a verification challenge). Windows close and pending work is cancelled. Stores survive the overlay case and in-page navigation, not hiding or reload; a persisted store survives those too. When toolbars return, the mounts run again. A mount that throws shows its error; other toolbars keep working.