Skip to main content

Theme

The app's stylesheet, its colours in light and in dark, the stage's colours, and the switch between the two.

Components​

AppStyle​

const AppStyle: React.FC;

Mounts the app's tokens and styles, as global stylesheets that live as long as it is mounted.

The tokens are the colours of the current theme (ThemeColors), each a custom property on :root, --rcad-<kebab-case> (--rcad-ink, --rcad-accent-fill), with the app's metrics (--rcad-row-h, …) and its face, JetBrains Mono, which the library carries. The styles name only those properties, so they follow the theme.

Drawing renders it. A host that composes the pieces itself (a ModelTree here, a ToolBar there) renders one <AppStyle /> beside them, and puts them inside an element with the class rcad, which sets the app's type.

Example​

import type { DrawingID } from '@buerli.io/core'
import { AppStyle, ModelTree, ToolBar } from '@buerli.io/react-cad'

// two pieces in a page of the app's own: one stylesheet, and the class that sets the app's type
const Pieces = ({ drawingId }: { drawingId: DrawingID }) => (
<div className="rcad">
<AppStyle />
<ToolBar drawingId={drawingId} />
<div style={{ height: 400 }}>
<ModelTree drawingId={drawingId} />
</div>
<p style={{ color: 'var(--rcad-mute)' }}>The tokens are custom properties too.</p>
</div>
)

ThemeToggle​

const ThemeToggle: React.FC;

The theme switch: a button with a disc, half inked, that switches between the light and the dark theme.

It sets the mode with setRCadThemeMode, which remembers the reader's pick for the next visit. The disc turns to the other side in the dark. Drawing shows it at the end of its bar (unless themeSwitch is false).

Example​

import type { DrawingID } from '@buerli.io/core'
import { AppStyle, ThemeToggle, ToolBar } from '@buerli.io/react-cad'

// a bar of the app's own: its tools, and the theme switch at its end
const Bar = ({ drawingId }: { drawingId: DrawingID }) => (
<header className="rcad" style={{ display: 'flex', justifyContent: 'space-between' }}>
<AppStyle />
<ToolBar drawingId={drawingId} />
<ThemeToggle />
</header>
)

Functions​

setRCadThemeMode()​

function setRCadThemeMode(mode, options?): void;

Sets the app's theme to light or dark.

The pick is remembered for the next visit (in localStorage); picking what the system has forgets it, so that the app follows the system again. A page that has a theme of its own passes { remember: false } and calls this whenever its theme changes: the app then follows the page (and Drawing is given themeSwitch={false}).

Parameters​

ParameterTypeDescription
modeThemeModeThe theme to show.
options?{ remember?: boolean; }remember: false leaves the reader's remembered pick alone.
options.remember?boolean-

Returns​

void

Example​

import { useEffect } from 'react'
import type { DrawingID } from '@buerli.io/core'
import { Drawing, setRCadThemeMode } from '@buerli.io/react-cad'

// a page with a theme switch of its own: the app follows it, and shows no switch of its own
function EditorPage({ dark, drawingId }: { dark: boolean; drawingId: DrawingID }) {
useEffect(() => setRCadThemeMode(dark ? 'dark' : 'light', { remember: false }), [dark])
return <Drawing drawingId={drawingId} themeSwitch={false} />
}

getStage()​

function getStage(): StageColors;

The stage's colours in the current theme, outside of a component (as useStage, without rendering again).

Returns​

StageColors

Example​

import { init, WASMClient } from '@buerli.io/classcad'
import { elements, getStage } from '@buerli.io/react-cad'

// buerli's highlight colours from the stage's, as Buerligons sets them
const stage = getStage()
init((drawingId) => new WASMClient(drawingId, { token: 'ccpk_…' }), {
elements,
theme: { primary: stage.pick, secondary: stage.hover, dark: stage.datum, highlightedGeom: stage.select, hoveredGeom: stage.hover },
})

Hooks​

useRCadTheme()​

function useRCadTheme(): ThemeColors;

Returns the colours of the current theme, and renders again when the theme changes.

Returns​

ThemeColors

lightTheme or darkTheme.

Example​

import { useRCadTheme, useRCadThemeMode } from '@buerli.io/react-cad'

// a panel of the app's own in the app's colours, in either theme
function Note({ children }: { children: React.ReactNode }) {
const colors = useRCadTheme()
const mode = useRCadThemeMode()
return (
<div style={{ background: colors.panel, color: colors.ink, border: `1px solid ${colors.line}`, boxShadow: colors.shadow }}>
{children} <small style={{ color: colors.dim }}>({mode})</small>
</div>
)
}

useStage()​

function useStage(): StageColors;

Returns the stage's colours in the current theme, and renders again when the theme changes.

Returns​

StageColors

Example​

import { Line } from '@react-three/drei'
import { useStage } from '@buerli.io/react-cad'

// a guide of the app's own on the stage, in the stage's colours: it follows the theme
function Guide({ from, to }: { from: [number, number, number]; to: [number, number, number] }) {
const stage = useStage()
return <Line points={[from, to]} color={stage.datum} lineWidth={1.5} dashed dashSize={2} gapSize={2} />
}

useRCadThemeMode()​

function useRCadThemeMode(): ThemeMode;

Returns the current theme's mode, 'light' or 'dark', and renders again when it changes.

The example of useRCadTheme uses it beside the colours.

Returns​

ThemeMode

Types​

StageColors​

type StageColors = {
alt: string;
axisX: string;
axisY: string;
axisZ: string;
badgeDisc: string;
badgeInk: string;
body: string;
datum: string;
dimExpr: string;
dimHalo: string;
dimLine: string;
dimText: string;
edge: string;
gridMajor: string;
gridMinor: string;
hover: string;
pick: string;
plane: string;
select: string;
sketchConstruction: string;
sketchFree: string;
sketchHover: string;
sketchHoverSoft: string;
sketchIdle: string;
sketchIdlePoint: string;
sketchMark: string;
sketchOver: string;
sketchRedundant: string;
sketchSelect: string;
sketchSolved: string;
};

The colours of what is drawn on the stage: the model, what lies over it, a sketch on its sheet.

They are written down in BRANDING.md, "The stage". The model is a solid grey body with ink edges. What a sketch's colours say is the editor's own code (how far a curve is defined), in the family's tones. useStage gives them for the current theme; they are CSS colour strings (#rrggbb), which three.js takes as they are.

Properties​

PropertyTypeDescription
altstringStands in for the highlight on a body of nearly its colour.
axisXstringThe X axis: red.
axisYstringThe Y axis: green.
axisZstringThe Z axis: blue.
badgeDiscstringA constraint's badge at rest: its disc.
badgeInkstringA constraint's badge at rest: its ring and its glyph.
bodystringA body the model gives no colour of its own: a neutral grey, clearly off the ground.
datumstringA point or an axis of the part's own, and the origin.
dimExprstringA value that is an expression.
dimHalostringWhat its text stands on.
dimLinestringA dimension's lines and arrows.
dimTextstringA dimension's value, a readout's text.
edgestringIts edges: ink, in either theme.
gridMajorstringIts rule around every fifth.
gridMinorstringThe squared sheet's rule around every cell.
hoverstringUnder the pointer: the highlight, held back.
pickstringTaken by the feature being made: red.
planestringA plane: the outline, and the same colour, thinned, as its fill.
selectstringIn hand: the highlight.
sketchConstructionstringA construction curve that is not fully defined: grey.
sketchFreestringA curve the solver can still move (under-defined): blue.
sketchHoverstringUnder the pointer: green.
sketchHoverSoftstringPointed at from a list: the same green, paler.
sketchIdlestringA sketch that is not being edited: teal.
sketchIdlePointstringThe points of a sketch that is not being edited: a shade deeper.
sketchMarkstringA constraint or a region in hand: yellow.
sketchOverstringA curve, or a constraint, that is defined more than once: red.
sketchRedundantstringA constraint that says what is already so: orange.
sketchSelectstringA curve or a point in hand: amber.
sketchSolvedstringA curve that is fully defined: ink.

ThemeColors​

type ThemeColors = {
accent: string;
accentFill: string;
accentHover: string;
accentLine: string;
accentTint: string;
accentWash: string;
active: string;
axisX: string;
axisY: string;
axisZ: string;
blue: string;
canvasDimLine: number;
canvasLabelBg: number;
canvasText: number;
chrome: string;
chromeLine: string;
dim: string;
geoAlt: string;
geoBody: string;
geoEdge: string;
geoHover: string;
geoPick: string;
geoSelect: string;
green: string;
hover: string;
ink: string;
ink2: string;
line: string;
line2: string;
mute: string;
onAccent: string;
onGreen: string;
orange: string;
panel: string;
panel2: string;
paper: string;
ring: string;
shadow: string;
shadowLg: string;
toastBg: string;
toastStrong: string;
toastText: string;
viewport: string;
};

The colours of the app, in light and in dark: lightTheme and darkTheme.

They are the family's own (paper and ink, one red; graphite and chalk in the dark), written down for a technical application in BRANDING.md, "The app". Every one of them that is a string is also a custom property on :root, --rcad-<kebab-case> (accentFill is --rcad-accent-fill), which is what the stylesheet draws from (see AppStyle). The colours of what is drawn on the stage are StageColors.

Properties​

PropertyTypeDescription
accentstringRed as type and lines.
accentFillstringRed as a fill: the one primary action.
accentHoverstringHover on a red fill.
accentLinestringA hairline of red: focus, a field under the hand.
accentTintstringA stronger wash, for small marks (icons).
accentWashstringA wash of red: over what a feature made, behind a changed value.
activestringA row or a button that is on, or held.
axisXstringThe X axis: red. On the stage's triad, and in a sign about it.
axisYstringThe Y axis: green.
axisZstringThe Z axis: blue.
bluestringA note; what the engine reports.
canvasDimLinenumberA dimension's lines and arrows on the stage, as a number for three.js.
canvasLabelBgnumberThe ground of a label on the stage (a measure, a dimension), as a number for three.js.
canvasTextnumberText on the stage (a dimension's value, a readout), as a number for three.js (0x1a1a3a).
chromestringBars, the sidebar, menus: the app's own paper.
chromeLinestringThe rule between two pieces of chrome.
dimstringLabels, captions, metadata, what is switched off.
geoAltstringStands in for the highlight on a body of nearly its colour.
geoBodystringA body the model gives no colour of its own: a neutral grey, clearly off the ground.
geoEdgestringAn edge of the model: ink, in either theme.
geoHoverstringUnder the pointer: the highlight, held back.
geoPickstringTaken by the feature being made: red, as everything a feature makes.
geoSelectstringIn hand: the highlight, "a face lit".
greenstringDone, proven, live.
hoverstringA row or a button under the pointer.
inkstringHeadings, primary text, icons.
ink2stringRows, values, secondary content.
linestringA hairline over any ground.
line2stringA stronger hairline: a field's edge under the pointer, a key cap.
mutestringBody copy, notes.
onAccentstringType on a red fill.
onGreenstringType on a green fill.
orangestringWorking, and a warning.
panelstringWindows and cards that float over the viewport.
panel2stringInset fills: fields, chips, a pressed button.
paperstringThe sheet a sketch is drawn on.
ringstringThe hairline ring a floating thing carries with its shadow.
shadowstringMenus, small cards.
shadowLgstringWindows.
toastBgstringThe ground of a toast or a tooltip.
toastStrongstringWhat stands out in it: a title, a value.
toastTextstringIts text.
viewportstringThe ground the model is shown on.

ThemeMode​

type ThemeMode = "light" | "dark";

The theme's mode: light, or dark.

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.

darkStage​

const darkStage: StageColors;

The stage's colours in the dark theme. useStage gives the current theme's; see also stageColors.


darkTheme​

const darkTheme: ThemeColors;

The app's colours in the dark theme: graphite and chalk, one red. See the example of lightTheme.


lightStage​

const lightStage: StageColors;

The stage's colours in the light theme. useStage gives the current theme's; see also stageColors.


lightTheme​

const lightTheme: ThemeColors;

The app's colours in the light theme: paper and ink, one red.

Example​

import { darkTheme, lightTheme } from '@buerli.io/react-cad'

// a page around the app in the app's colours, whatever its theme is now
const pageColors = (dark: boolean) => {
const colors = dark ? darkTheme : lightTheme
return { background: colors.viewport, color: colors.ink, accentColor: colors.accent }
}
document.body.style.background = pageColors(true).background

stageColors()​

function stageColors(mode): StageColors;

The stage's colours in a theme: lightStage or darkStage.

Parameters​

ParameterTypeDescription
modeThemeModeThe theme.

Returns​

StageColors

Example​

import { stageColors } from '@buerli.io/react-cad'

// the stage's colours of both themes, side by side: a legend of what a sketch's colours say
const legend = (['light', 'dark'] as const).map((mode) => {
const s = stageColors(mode)
return { mode, free: s.sketchFree, solved: s.sketchSolved, over: s.sketchOver }
})

stageFont​

const stageFont: string;

The face of what is written on the stage (a dimension, a readout), as a data: url: JetBrains Mono, latin, weight 500, without ligatures (woff).

It is what drei's <Text font={stageFont}> takes, so that a label of the app's own on the stage is set in the app's face. (JetBrains Mono is under the SIL Open Font License.)

Example​

import { Text } from '@react-three/drei'
import { stageFont, useStage } from '@buerli.io/react-cad'

// a label of the app's own on the stage, set as a dimension is
function Label({ text, position }: { text: string; position: [number, number, number] }) {
const stage = useStage()
return (
<Text font={stageFont} fontSize={4} color={stage.dimText} position={position}>
{text}
</Text>
)
}

useRCadThemeStore​

const useRCadThemeStore: UseBoundStore<StoreApi<{
colors: ThemeColors;
mode: ThemeMode;
setMode: (mode, options?) => void;
}>>;

The theme's store (zustand): its mode, its colors, and setMode.

In a component, useRCadTheme and useRCadThemeMode read it; outside of one, useRCadThemeStore.getState() does, and useRCadThemeStore.subscribe hears it change. The mode starts as the reader picked it last time, or as the system has it (prefers-color-scheme), and follows the system while the reader has picked nothing.