Panels
The app's frame and its panels: Drawing in one piece, or the model tree, the toolbar, the sidebar, the messages
and the windows of the dialogs, laid out by the app. Start with Drawing.
Components
Drawing
const Drawing: React.FC<DrawingProps>;
The app's frame around a drawing: a bar with its tools, a sidebar with the model's tree and its bodies, the stage, and a footer that says where things stand.
It is what Buerligons is made of, in one piece: the ToolBar in the bar, the SideBar, and on the stage
the ViewOptionButtons, the ViewPlugButtons, the Messages, and the windows of the active
feature (FeaturePlugin) and of the global plugins (GlobalPlugins). It mounts the stylesheet
(AppStyle) itself. The sidebar's edge is dragged to set its width, and a button in the bar puts it away;
both are kept for the next visit (in localStorage).
Drawing contains no canvas: the app's canvas is its child, and fills the stage. The plugins need buerli's
PluginManager mounted once in the app, and BuerliPluginsGeometry in the canvas for what they draw (both from
@buerli.io/react).
Where the app's init left buerli's stock form controls in, Drawing hands buerli react-cad's elements
instead; an app that brought controls of its own keeps them. It also sets the colour of the model's edges and
points in buerli's geometry config to the theme's ink, whenever the theme changes.
Its props: DrawingProps.
Example
import { Canvas } from '@react-three/fiber'
import { BuerliCadFacade } from '@buerli.io/classcad'
import { useBuerliCadFacade } from '@buerli.io/react'
import { Drawing, Menu, sessionClient, StageLook } from '@buerli.io/react-cad'
function Editor() {
const { drawingId, Geometry } = useBuerliCadFacade('bracket')
const file = {
undo: { caption: 'Undo', callback: () => BuerliCadFacade.utils.undo(drawingId) },
redo: { caption: 'Redo', callback: () => BuerliCadFacade.utils.redo(drawingId) },
}
return (
<Drawing
drawingId={drawingId}
Menu={<Menu items={file} trigger={['click']} />}
Status="ClassCAD · in this tab"
Trail={<a href="/help">Help</a>}
readOnly={sessionClient.useSessionRole() === 'view'}>
<Canvas orthographic>
<StageLook />
<Geometry />
</Canvas>
</Drawing>
)
}
ModelTree
const ModelTree: React.FC<ModelTreeProps>;
Shows the structure of the model: a part's features, or an assembly's nodes.
Which of the two it shows is the useEditMode of the drawing. For a part it is the list of its features in the order they are built, with the rollback bar: a feature is dragged to reorder it, double-clicked to open its dialog, and has a context menu (rename, edit, delete). For an assembly it is the tree of its instances; one is double-clicked to work on it. The header names the current product and has its actions: back out of it, export it, convert to a subassembly, open the products. With neither a part nor an assembly, it shows a placeholder. Read-only (DrawingProps.readOnly), the tree is browsed but not edited.
Its props: ModelTreeProps.
Example
import { Canvas } from '@react-three/fiber'
import { BuerliPluginsGeometry, useBuerliCadFacade } from '@buerli.io/react'
import { AppStyle, FeaturePlugin, FtVisibilityController, GlobalPlugins, Messages, ModelTree, StageLook, ToolBar } from '@buerli.io/react-cad'
// The pieces laid out by the app instead of Drawing: then `init` is given react-cad's `elements` by the app.
function Workbench() {
const { drawingId, Geometry } = useBuerliCadFacade('bracket')
return (
<div className="rcad" style={{ display: 'grid', gridTemplate: '48px 1fr / 280px 1fr', height: '100vh' }}>
<AppStyle />
<header style={{ gridColumn: 'span 2' }}><ToolBar drawingId={drawingId} /></header>
<aside><ModelTree drawingId={drawingId} /></aside>
<main style={{ position: 'relative' }}>
<Canvas orthographic>
<StageLook />
<Geometry />
<BuerliPluginsGeometry drawingId={drawingId} />
</Canvas>
<Messages drawingId={drawingId} />
</main>
<FeaturePlugin drawingId={drawingId} />
<GlobalPlugins drawingId={drawingId} />
<FtVisibilityController drawingId={drawingId} />
</div>
)
}
ToolBar
const ToolBar: React.FC<ToolBarProps>;
The tools a part or an assembly is built with: one button a tool, its drawing on it.
Tools that are kin share a button; its caret opens the set. In a part the tools are the features (a sketch, work geometry, extrusion, boolean, fillet, patterns, primitives …), in an assembly the constraints. A tool makes the new feature (uncommitted, in the current product) and opens its dialog; while a feature's dialog is open, it makes none. Until the drawing has a current product, the buttons are placeholders.
Its props: ToolBarProps. The example of ModelTree lays it out with the other panels.
SideBar
const SideBar: React.FC<SideBarProps>;
The sidebar's two panes: the model's tree above, and what the model is made of below it.
The upper pane is the ModelTree (a part's features, an assembly's nodes); the lower one is the part's bodies (Solids) or the assembly's constraints (Constraints), as the current product is a part or an assembly. While the drawing has pending commands, the panes take no clicks. Drawing renders it in its sidebar; an app that composes the pieces itself gives it a container of the height it is to fill.
Its props: SideBarProps.
Example
import type { DrawingID } from '@buerli.io/core'
import { AppStyle, SideBar } from '@buerli.io/react-cad'
// the tree and the bodies (or constraints) of a drawing, in a column of the app's own
function ModelColumn({ drawingId }: { drawingId: DrawingID }) {
return (
<aside className="rcad" style={{ width: 300, height: '100%', display: 'flex', flexDirection: 'column' }}>
<AppStyle />
<SideBar drawingId={drawingId} />
</aside>
)
}
Messages
const Messages: React.FC<MessagesProps>;
The app's messages: what buerli's showMessage (@buerli.io/core) says, as toasts and in a log.
A new message comes up as a toast and leaves again after a few seconds; an error stays until the log has been opened. The button under the toasts opens the log of all of them, and a dot on it says that there are new ones; the log has a button that clears it. Drawing shows them in the stage's lower right corner.
Its props: MessagesProps.
Example
import { showMessage } from '@buerli.io/core'
import type { DrawingID } from '@buerli.io/core'
import { Messages } from '@buerli.io/react-cad'
// where the app shows them: over the stage's lower right corner
const Toasts = () => (
<div style={{ position: 'absolute', right: 12, bottom: 12, zIndex: 6 }}>
<Messages drawingId={drawingId} />
</div>
)
// anywhere in the app: a toast, and a line in the log
showMessage({ type: 'warning', text: 'The sketch is not closed: nothing was extruded.', drawingId })
FeaturePlugin
const FeaturePlugin: React.FC<FeaturePluginProps>;
The window of the active feature: the dialog of the feature's plugin, in a window that can be dragged.
The active feature is the drawing's plugin.active.feature (set by the ToolBar for a new feature, and by
a double click in the ModelTree). The window's head is the feature's drawing, its name and the call that
makes it; closing it sets the active feature to none. It renders nothing while no feature is active.
Drawing renders it over the stage.
Its props: FeaturePluginProps.
Example
import { getDrawing } from '@buerli.io/core'
import type { DrawingID, ObjectID } from '@buerli.io/core'
import { FeaturePlugin } from '@buerli.io/react-cad'
// the window, once, over the app's stage
const Dialog = () => <FeaturePlugin drawingId={drawingId} modalProps={{ width: 312, minPosition: { x: 300, y: 60 } }} />
// a feature's dialog opened from the app: the window shows it
getDrawing(drawingId).api.plugin.setActiveFeature(extrusionId)
GlobalPlugins
const GlobalPlugins: React.FC<GlobalPluginsProps>;
The windows of the drawing's global plugins (Measure, Expressions, Products, …): one for each plugin that is on.
The global plugins are the ones init's globalPlugins gives every drawing. A plugin is switched on and off with
the drawing's api.plugin.setActiveGlobal (as the ViewPlugButtons and the model tree's header do), and
closing its window switches it off. Drawing renders them over the stage; an app that composes the pieces
itself renders them once, anywhere.
Its props: GlobalPluginsProps.
Example
import { getDrawing } from '@buerli.io/core'
import type { DrawingID } from '@buerli.io/core'
import { GlobalPlugins } from '@buerli.io/react-cad'
// the windows, once, anywhere in the app
const Windows = () => <GlobalPlugins drawingId={drawingId} modalProps={{ width: 380, minPosition: { x: 300, y: 60 } }} />
// a button of the app's own that opens the Measure panel
const openMeasure = () => {
const { plugin, api } = getDrawing(drawingId)
const measure = plugin.global.find((id) => plugin.refs[id].name === 'Measure')
if (measure) api.plugin.setActiveGlobal(measure, true)
}
Constraints
const Constraints: React.FC<ConstraintsProps>;
Lists the constraints of the current assembly, and says whether the assembly's solver has solved them.
A row has a context menu (rename, delete), and the pointer on it shows the mates the constraint joins (HoveredConstraintDisplay). Its props: ConstraintsProps. The example of useEditMode shows it for an assembly.
Readfile
const Readfile: ForwardRefExoticComponent<ReadfileProps & RefAttributes<any>>;
A hidden file input that loads a model the user picks: an .ofb, .stp/.step or .iwp file.
Its ref is the <input>: a button of the app's calls ref.current.click() to open the browser's file dialog. The
file is loaded into a new drawing named after it (BuerliCadFacade.utils.connect), which becomes the active one.
A guest of a shared session loads it into the session's drawing instead, in place of its model, for everyone in
it. What goes wrong is said with showMessage. Its props: ReadfileProps.
Example
import { useRef } from 'react'
import { Readfile } from '@buerli.io/react-cad'
// an Open button: the browser's file dialog, and the model the user picks in a drawing of its own
function OpenButton() {
const input = useRef<HTMLInputElement>(null)
return (
<>
<button onClick={() => input.current?.click()}>Open…</button>
<Readfile ref={input} singleDrawingApp />
</>
)
}
Solids
const Solids: React.FC<SolidsProps>;
Lists the bodies of the current product: its solids and sheets (useVisibleSolids).
A row is hovered and selected with the body on the stage, renamed, shown or hidden with its eye, and has a context menu. Several rows are selected with Shift and Ctrl.
Its props: SolidsProps. The example of useEditMode shows it for a part, and Constraints for an assembly.
ViewOptionButtons
const ViewOptionButtons: React.FC;
Switches for what of the model is shown: its faces, its wires, its edges, its points.
Each is a switch over buerli's geometry config, the one setViewOptions sets; the wireframe is only there while the faces are shown. They take no props: they are the same for every drawing. Drawing docks them on the stage's right-hand side.
Example
import { ThemeToggle, ViewOptionButtons, ViewPlugButtons } from '@buerli.io/react-cad'
import type { DrawingID } from '@buerli.io/core'
// the stage's docks of an app that lays the pieces out itself
const StageDocks = ({ drawingId }: { drawingId: DrawingID }) => (
<>
<div className="rcad-dock rcad-dock-col" style={{ position: 'absolute', top: 12, right: 12 }}>
<ViewOptionButtons />
<ThemeToggle />
</div>
<div className="rcad-dock" style={{ position: 'absolute', bottom: 12, left: 12 }}>
<ViewPlugButtons drawingId={drawingId} />
</div>
</>
)
ViewPlugButtons
const ViewPlugButtons: React.FC<ViewPlugButtonsProps>;
Buttons that open and close the global plugins laid over the stage: Dimensions, Measure, Bounding box, Session Management.
A button is there only where the drawing has the plugin (init's globalPlugins); it switches the plugin on and
off, and its window is one of the GlobalPlugins. The Session Management button is not shown to a guest of a
shared session. Drawing docks them in the stage's lower left corner.
Its props: ViewPlugButtonsProps.
Example
import { init, WASMClient } from '@buerli.io/classcad'
import type { DrawingID } from '@buerli.io/core'
import { BoundingBoxInfo, Dimensions, elements, Measure, ViewPlugButtons } from '@buerli.io/react-cad'
// a button for each of these global plugins that the drawings have
init((drawingId) => new WASMClient(drawingId, { token: 'ccpk_…' }), {
elements,
globalPlugins: [Dimensions, Measure, BoundingBoxInfo],
})
const Tools = ({ drawingId }: { drawingId: DrawingID }) => (
<div className="rcad-dock" style={{ position: 'absolute', left: 12, bottom: 12 }}>
<ViewPlugButtons drawingId={drawingId} />
</div>
)
Functions
getViewOptions()
function getViewOptions(): ViewOptions;
What of the model is drawn now, as buerli's geometry config says (which the stage draws from).
The example of setViewOptions switches one of them with it.
Returns
The ViewOptions in force, for every drawing.
setViewOptions()
function setViewOptions(options): void;
Shows or hides what of the model is drawn, for every drawing.
It merges the options into buerli's geometry config (init's config.geometry); what it leaves out stays as it
is. The ViewOptionButtons show what is set here, whoever sets it: the user, or the app (Buerligons switches
the edges off in its realistic look).
Parameters
| Parameter | Type | Description |
|---|---|---|
options | Partial<ViewOptions> | What to change, such as { edges: false }. |
Returns
void
Example
import { getViewOptions, setViewOptions } from '@buerli.io/react-cad'
// a key that switches the edges on and off, as the edges' button on the stage does
window.addEventListener('keydown', (e) => {
if (e.key !== 'e') return
const { edges } = getViewOptions()
setViewOptions({ edges: !edges })
})
// a look of the app's own: the faces alone, without edges or points
setViewOptions({ faces: true, wireframe: false, edges: false, vertices: false })
Types
ConstraintsProps
type ConstraintsProps = {
drawingId: DrawingID;
};
Props of Constraints.
Properties
| Property | Type | Description |
|---|---|---|
drawingId | DrawingID | The drawing whose current assembly's constraints are listed. |
DrawingProps
type DrawingProps = {
children?: React.ReactNode;
drawingId: DrawingID;
Menu?: React.JSX.Element;
readOnly?: boolean;
Status?: React.ReactNode;
themeSwitch?: boolean;
Trail?: React.ReactNode;
ViewOptions?: React.ReactNode;
};
Props of Drawing.
Properties
| Property | Type | Description |
|---|---|---|
children? | React.ReactNode | What fills the stage: the app's canvas, with the drawing's geometry in it. |
drawingId | DrawingID | The drawing to show, such as the active one (useBuerli(s => s.drawing.active)). |
Menu? | React.JSX.Element | What leads the bar, before the button that puts the sidebar away: a file menu, undo and redo. |
readOnly? | boolean | When true, hides the feature toolbar and disables model-tree editing (browsing stays). Default false. |
Status? | React.ReactNode | What the footer's first cell names before the engine's state (ready, working, not connected): where the engine runs, say. Default: ClassCAD. |
themeSwitch? | boolean | Shows the theme switch (ThemeToggle) at the end of the bar. false where the page has a switch of its own and sets the app's theme from it with setRCadThemeMode. Default true. |
Trail? | React.ReactNode | What the bar ends with, before the theme switch. |
ViewOptions? | React.ReactNode | Buttons of the app's own for the stage's right-hand dock, after the ViewOptionButtons. |
FeaturePluginProps
type FeaturePluginProps = {
drawingId: DrawingID;
modalProps?: {
bodyStyle?: React.CSSProperties;
minPosition?: {
x?: number;
y?: number;
};
width?: string | number;
};
};
Props of FeaturePlugin.
Properties
GlobalPluginsProps
type GlobalPluginsProps = {
drawingId: DrawingID;
modalProps?: {
bodyStyle?: React.CSSProperties;
minPosition?: {
x?: number;
y?: number;
};
width?: string | number;
};
};
Props of GlobalPlugins.
Properties
MessagesProps
type MessagesProps = {
drawingId: DrawingID;
};
Props of Messages.
Properties
| Property | Type | Description |
|---|---|---|
drawingId | DrawingID | The drawing the messages are of: when it changes, the log is cleared. |
ModelTreeProps
type ModelTreeProps = {
drawingId: DrawingID;
};
Props of ModelTree.
Properties
| Property | Type | Description |
|---|---|---|
drawingId | DrawingID | The drawing whose model is shown. |
ReadfileProps
type ReadfileProps = {
singleDrawingApp?: boolean;
};
Props of Readfile.
Properties
| Property | Type | Description |
|---|---|---|
singleDrawingApp? | boolean | Removes the drawing that was active before, once the file is loaded into a new one: the app has one drawing. |
SideBarProps
type SideBarProps = {
drawingId: DrawingID;
};
Props of SideBar.
Properties
| Property | Type | Description |
|---|---|---|
drawingId | DrawingID | The drawing whose model is shown. |
SolidsProps
type SolidsProps = {
drawingId: DrawingID;
};
Props of Solids.
Properties
| Property | Type | Description |
|---|---|---|
drawingId | DrawingID | The drawing whose bodies are listed. |
ToolBarProps
type ToolBarProps = {
drawingId: DrawingID;
};
Props of ToolBar.
Properties
| Property | Type | Description |
|---|---|---|
drawingId | DrawingID | The drawing whose current product the tools build. |
ViewOptions
type ViewOptions = {
edges: boolean;
faces: boolean;
vertices: boolean;
wireframe: boolean;
};
What of the model is drawn: its faces (or their wires), its edges, its points.
Properties
ViewPlugButtonsProps
type ViewPlugButtonsProps = {
drawingId: DrawingID;
};
Props of ViewPlugButtons.
Properties
| Property | Type | Description |
|---|---|---|
drawingId | DrawingID | The drawing whose global plugins the buttons open. |
Advanced
Most apps do not need these directly: types they meet through the exports above, and what is there for special cases or for building on buerli itself.
FtVisibilityController
const FtVisibilityController: React.FC<FtVisibilityControllerProps>;
Shows and hides the views of the current part's features as the rollback bar and the fields ask.
A feature below the rollback bar is not in force: its view (a work plane, a sketch) is hidden while it is there, and shown again when the bar moves past it. While a field picks, the features picked into it by their tree object (a sketch, a work plane) are shown, and hidden again afterwards if they were hidden before. It renders nothing. Drawing renders it; an app that composes the pieces itself renders it once beside its ModelTree, as the example there does. Its props: FtVisibilityControllerProps.
FtVisibilityControllerProps
type FtVisibilityControllerProps = {
drawingId: DrawingID;
};
Props of FtVisibilityController.
Properties
| Property | Type | Description |
|---|---|---|
drawingId | DrawingID | The drawing whose features' views it shows and hides. |