Skip to main content
Version: 3.0 (next)
Coming soon

App Studio is coming soon: it is in development and testing and is not part of release 3.0. This reference describes the SDK as it is being built and may change before release.

Generated

Generated from the SDK sources by scripts/appstudio-sdk-docs.cjs for runtime-v1 — do not edit; run npm run appstudio:docs:sdk.

@maestrohub/app-ui

The App Studio UI kit: layout, display, input, table and chart components.

Runtime: runtime-v1. 53 exports (37 values, 16 types). Import with:

import { ... } from '@maestrohub/app-ui';

Hooks​

usePalette​

function usePalette(): Palette

usePalette returns the kit colours for the current theme — the host's own surface / ink / muted / border / subtle / primary / danger when the shell sent them, the kit's palette otherwise.

useTheme​

function useTheme(): ThemeMode

useTheme returns the live theme mode the shell set (light when unset).

Components​

Badge​

function Badge({ tone, children }: { tone?: "ok" | "warn" | "critical" | "neutral"; children?: ReactNode; }): JSX.Element

A small rounded pill coloured by tone (default neutral) from the palette's badge pairs.

BarChart​

function BarChart({ items, height, unit, max }: { items: { label: string; value: number; tone?: Tone; }[]; height?: number; unit?: string; max?: number; }): JSX.Element

A responsive SVG bar chart of items (label, value, optional tone). The scale tops out at max or the largest value; negative values are drawn as zero-height bars, labels longer than 12 characters are truncated. Renders "No data." for an empty list.

Button​

function Button({ intent, disabled, reason, confirm, onClick, children }: ButtonProps): JSX.Element

The kit's action button. When disabled and reason are both set the reason renders as the button's title and as a caption beneath it, so a dead control always says why. With confirm, the first click swaps the label for the confirm text and shows a Cancel button; only the second click fires onClick.

Card​

function Card({ title, children }: { title?: string; children?: ReactNode; }): JSX.Element

A bordered, themed panel with an optional title heading above children. Adds a bottom margin so stacked cards space themselves.

CheckboxField​

function CheckboxField({ label, checked, onChange, disabled }: { label: string; checked: boolean; onChange: (v: boolean) => void; disabled?: boolean; }): JSX.Element

A checkbox with its label inline; reports onChange(boolean). Unlike the other fields it has no hint.

DateField​

function DateField({ label, value, onChange, hint, disabled, withTime }: { label: string; value: string; onChange: (iso: string) => void; hint?: string; disabled?: boolean; withTime?: boolean; }): JSX.Element

DateField / DateTimeField take and return ISO strings (empty = unset).

EmptyState​

function EmptyState({ title, description, action }: { title: string; description?: string; action?: ReactNode; }): JSX.Element

A dashed-border placeholder for "nothing here yet": bold title, muted description, and an optional action slot below.

ErrorNotice​

function ErrorNotice({ error, title, onRetry, retryLabel }: ErrorNoticeProps): JSX.Element | null

Renders a caught error as an alert: the title (or the platform code when no title is given), the reason, the remediation when the platform supplied one, and a Retry button when onRetry is set. Understands ApiError, LiveError, shell refusals and plain errors via describeError; renders nothing for null/undefined.

Example

const t = useTopic('plant/line1/oee');
return t.error ? <ErrorNotice error={t.error} /> : <MetricCard label="OEE" value={t.value} />;

FilterBar​

function FilterBar({ children, actions }: { children?: ReactNode; actions?: ReactNode; }): JSX.Element

FilterBar is the horizontal strip that holds a report's parameters.

Gauge​

function Gauge({ value, max, threshold, unit }: { value: number; max?: number; threshold?: number; unit?: string; }): JSX.Element

A large numeric readout (value + unit, default %) over a horizontal fill bar sized by value / max (default max 100, clamped to 0–100 %). When threshold is set and value is below it, both the number and the bar turn the danger colour.

Grid​

function Grid({ columns, gap, minColumnWidth, children }: { columns?: number; gap?: number; minColumnWidth?: number; children?: ReactNode; }): JSX.Element

Grid lays children out in columns equal columns (1 on narrow screens).

KeyValueList​

function KeyValueList({ items }: { items: { key: string; value: ReactNode; }[]; }): JSX.Element

A two-column definition list (dl) of items; each item's key is the muted term and value the description. Keys must be unique — they are the React keys.

Loading​

function Loading({ label }: { label?: string; }): JSX.Element

A muted one-line status text (role="status"), default "Loading…". No spinner.

MetricCard​

function MetricCard({ label, value, unit, delta, tone, hint }: { label: string; value: ReactNode; unit?: string; delta?: number; tone?: Tone; hint?: string; }): JSX.Element

A KPI tile: uppercase label, a large value with optional unit, and an optional hint line. tone colours the value (ok / critical); delta renders a badge with an up/down arrow whose tone is derived from the sign of the delta, not from tone.

NumberField​

function NumberField({ label, value, onChange, min, max, step, unit, hint, disabled }: { label: string; value: number | null; onChange: (v: number | null) => void; min?: number; max?: number; step?: number; unit?: string; hint?: string; disabled?: boolean; }): JSX.Element

A labelled type="number" input. value is number | null; an empty field reports null, anything else Number(text). unit is appended to the label as "(unit)"; min/max/step pass through to the input.

Page​

function Page({ title, subtitle, actions, children }: { title?: string; subtitle?: string; actions?: ReactNode; children?: ReactNode; }): JSX.Element

The top-level app frame: a centred column (max 1400 px) with the kit font and ink colour. Renders a header with title (h1), subtitle and right-aligned actions only when a title or actions are given.

Row​

function Row({ gap, align, wrap, children }: { gap?: number; align?: CSSProperties["alignItems"]; wrap?: boolean; children?: ReactNode; }): JSX.Element

A horizontal flex row of children; gap (12), align (center) and wrap (true) map to the flex properties.

Section​

function Section({ title, description, actions, children }: { title?: string; description?: string; actions?: ReactNode; children?: ReactNode; }): JSX.Element

A titled block inside a Page: an h2 title, muted description, and actions on the right, above children. The header row is omitted when neither title nor actions are set.

SelectField​

function SelectField({ label, value, onChange, options, placeholder, hint, disabled }: { label: string; value: string; onChange: (v: string) => void; options: SelectOption[]; placeholder?: string; hint?: string; disabled?: boolean; }): JSX.Element

A labelled select over options. When placeholder is set it is rendered as a leading option with an empty value, so choosing it reports ''.

Sparkline​

function Sparkline({ values, width, height, tone }: { values: number[]; width?: number; height?: number; tone?: Tone | "primary"; }): JSX.Element

An inline, unlabelled SVG line of values scaled to its own min/max (width 120 × height 28 by default). Non-finite values are dropped; fewer than two remaining renders an em dash instead.

Stack​

function Stack({ children, gap }: { children?: ReactNode; gap?: number; }): JSX.Element

A vertical flex column of children separated by gap pixels (default 12).

StatusDot​

function StatusDot({ tone, label }: { tone?: Tone; label?: string; }): JSX.Element

A 10 px coloured dot for tone (default neutral) followed by an optional label.

Table​

function Table({ columns, rows, rowKey, pageSize, filterable, sort: initialSort, exportName, emptyText, onRowClick, caption }: TableProps): JSX.Element

The data table: client-side text filter (filterable), click-to-sort headers (numeric when both values parse as numbers, else locale string compare), pagination by pageSize, and CSV export of every filtered and sorted row via the shell when exportName is set. An export the shell or the size cap refuses is shown inline as an ErrorNotice. Cells render through formatCell.

Tabs​

function Tabs({ items, initial }: { items: TabItem[]; initial?: string; }): JSX.Element

A tab strip over a single panel. Holds the active id in local state, starting at initial or the first item; only the active item's content is rendered. Uses tablist/tab/tabpanel roles.

Text​

function Text({ tone, size, children }: { tone?: "body" | "muted" | "strong"; size?: "sm" | "md" | "lg"; children?: ReactNode; }): JSX.Element

Text is the kit's paragraph: the one place body copy is styled.

TextArea​

function TextArea({ label, value, onChange, rows, placeholder, hint, disabled }: { label: string; value: string; onChange: (v: string) => void; rows?: number; placeholder?: string; hint?: string; disabled?: boolean; }): JSX.Element

A labelled multi-line text input (rows default 3, vertically resizable). Controlled via value / onChange(string).

TextField​

function TextField({ label, value, onChange, placeholder, hint, disabled }: { label: string; value: string; onChange: (v: string) => void; placeholder?: string; hint?: string; disabled?: boolean; }): JSX.Element

A labelled single-line text input. Controlled: value in, onChange(string) out; optional placeholder, hint caption and disabled.

TimeRangeField​

function TimeRangeField({ label, value, onChange }: { label?: string; value: TimeRange; onChange: (r: TimeRange) => void; }): JSX.Element

TimeRangeField: the "last 24 h / last 7 d / custom" control every report needs.

TimeSeriesChart​

function TimeSeriesChart({ series, bands, height, yLabel, yMin, yMax, unit }: { series: Series[]; bands?: Band[]; height?: number; yLabel?: string; yMin?: number; yMax?: number; unit?: string; }): JSX.Element

A responsive SVG line chart of one or more Series with optional shaded bands, four y grid lines, a legend, and the first and last x values as axis labels (formatted as times when any x is not a number). The y range auto-fits the data plus the bands unless yMin/yMax are given; point markers are drawn only for series with 60 points or fewer. Renders "No data." when there are no points.

Timeline​

function Timeline({ items }: { items: { at: string; title: ReactNode; detail?: ReactNode; tone?: Tone; }[]; }): JSX.Element

Timeline lists dated events newest first — the log/handover/alarm history shape every operations app ends up drawing.

Functions​

describeError​

function describeError(error: unknown): ErrorDescription | null

describeError turns any caught value into {reason, remediation?, code?}. Exported so an app (or a test) can read the explanation without the DOM.

formatCell​

function formatCell(value: unknown, column: Column, row: TableRow, context: { columnValues: number[]; }, dark: boolean): { text: string; node?: ReactNode; style?: React.CSSProperties; }

Applies a column's CellFormatter to one value and returns the plain text (used for filtering, sorting and CSV), an optional node to render instead of the text (badges, progress bars), and an optional cell style (heatmap background). context.columnValues supplies the column's numeric values for the percentile heatmap; dark picks the heat scale. Non-numeric input to a numeric formatter renders "—".

Example

formatCell(0.8734, { key: 'oee', label: 'OEE', format: { kind: 'number', digits: 1, unit: '%' } }, row, { columnValues: [] }, false)
// → { text: '0.9 %' }

heatColor​

function heatColor(t: number, dark: boolean): string

heatColor maps 0..1 to a cool→warm scale readable on both themes.

percentileOf​

function percentileOf(v: number, all: number[]): number

percentileOf returns the fraction of all that is ≤ v (0..1).

toCSV​

function toCSV(columns: Column[], rows: TableRow[], format: (value: unknown, column: Column, row: TableRow) => string): string

toCSV renders rows with the columns' formatted text (RFC 4180 quoting).

Types​

Band​

interface Band

A horizontal shaded band on a TimeSeriesChart (a target range, an alarm limit).

Members

  • from: number — Lower y bound.
  • label?: string | undefined — Text drawn at the band's top-right.
  • to: number — Upper y bound.
  • tone?: Tone | undefined — Fill colour (default ok).

ButtonProps​

interface ButtonProps

Props for Button.

Members

  • children?: React.ReactNode — Button label.
  • confirm?: string | undefined — confirm asks before firing — the G3 rung-2 affordance.
  • disabled?: boolean | undefined — Disables the control; pair with reason so the button explains itself.
  • intent?: "neutral" | "primary" | "danger" | undefined — Colour intent: primary (accent), danger, or neutral (subtle fill). Default primary.
  • onClick?: (() => void) | undefined — Fired on click — after the confirm step when confirm is set; never while disabled.
  • reason?: string | undefined — reason renders the disabled explanation (FR-42's honest-UI half): a disabled control always says why (house rule 36).

CellFormatter​

type CellFormatter = {
kind: 'number';
digits?: number;
unit?: string;
} | {
kind: 'time';
} | {
kind: 'badge';
map?: Record<string, Tone>;
} | {
kind: 'percentile-heatmap';
invert?: boolean;
} | {
kind: 'threshold';
bands: {
max: number;
tone: Tone;
}[];
above?: Tone;
} | {
kind: 'category-color';
map: Record<string, Tone>;
} | {
kind: 'compare';
baseline: string;
percent?: boolean;
digits?: number;
} | {
kind: 'progress-bar';
max: number;
tone?: Tone;
};

The formatter catalogue — closed, schema-shaped, pure.

Column​

interface Column

One column of a Table.

Members

  • align?: "left" | "right" | undefined — Cell alignment; when omitted numeric cells align right, others left.
  • format?: CellFormatter | undefined — Declarative cell formatter; plain String(value) when omitted.
  • key: string — The row property to read; also the sort key.
  • label: string — Header text.
  • sortable?: boolean | undefined — Set to false to make the header inert; every other value keeps click-to-sort on.
  • width?: string | number | undefined — Header width, passed to the th style.

ErrorDescription​

interface ErrorDescription

The rendered explanation of an error, independent of the DOM.

Members

  • code?: string | undefined — The platform's code (APP_RATE_LIMITED, ACTION_NOT_DECLARED, …).
  • reason: string — The headline: what was refused or what failed.
  • remediation?: string | undefined — What to do next, when the platform said.
  • retryAfterSeconds?: number | undefined — Seconds the platform asked the app to wait (429 only).

ErrorNoticeProps​

interface ErrorNoticeProps

Props for ErrorNotice.

Members

  • error: unknown — Whatever was caught; null/undefined renders nothing.
  • onRetry?: (() => void) | undefined — Offers a "Retry" button; the notice does not retry by itself.
  • retryLabel?: string | undefined — Label for the retry button (default "Retry").
  • title?: string | undefined — Optional heading above the explanation.

Palette​

interface Palette

The kit's colour set for one ThemeMode, returned by usePalette.

Members

  • badge: Record<"critical" | "ok" | "warn" | "neutral", CSSProperties> — Background + text pair per Tone, as Badge renders them.
  • border: string — Borders and rules.
  • chart: string — Data accent for charts and sparklines — the kit's own, never the host's button colour (a shell whose primary is near-white on dark would draw every series in white).
  • danger: string — Critical / error colour.
  • ink: string — Primary text.
  • muted: string — Secondary text.
  • ok: string — Positive colour.
  • primary: string — Accent (primary buttons, active tab). The host's button colour when tokens were sent.
  • primaryInk: string — Text ON the accent — the host's --primary-foreground when tokens were sent. Never hardcode white on primary: the shell's default dark theme uses an inverted-mono accent (near-white primary, dark navy text), so white-on-primary renders an unreadable button.
  • subtle: string — Subtle fill (table header, neutral button, track backgrounds).
  • surface: string — Card / control background.

Point​

interface Point

One sample in a Series.

Members

  • x: string | number | Date — A number, or a date / date string (parsed with new Date); mixing kinds makes the chart treat the axis as time.
  • y: number | null — The value; null leaves a gap in the line.

SelectOption​

interface SelectOption

One choice in a SelectField: the value reported by onChange and the label shown.

Members

  • label: string — Text shown in the dropdown.
  • value: string — Reported by onChange when chosen; also the React key, so values must be unique.

Series​

interface Series

One line in a TimeSeriesChart.

Members

  • dashed?: boolean | undefined — Draw the line dashed.
  • name: string — Legend label; also the React key, so names must be unique.
  • points: Point[] — The samples, in x order.
  • tone?: Tone | "primary" | undefined — Line colour (default primary).

TabItem​

interface TabItem

One tab for Tabs: a stable id, the button label, and the panel content.

Members

  • content: React.ReactNode — Rendered in the panel while the tab is active.
  • id: string — Identifies the tab; Tabs.initial refers to it.
  • label: string — Text on the tab button.

TableProps​

interface TableProps

Props for Table.

Members

  • caption?: React.ReactNode — Muted text in the toolbar, left of the filter.
  • columns: Column[] — Column definitions, in display order.
  • emptyText?: string | undefined — Shown in the body when no rows are visible (default "No rows.").
  • exportName?: string | undefined — Export: the file name (CSV of ALL rows after filter+sort, not the page).
  • filterable?: boolean | undefined — Text filter over every displayed cell.
  • onRowClick?: ((row: TableRow) => void) | undefined — Makes rows clickable and receives the clicked row.
  • pageSize?: number | undefined — Rows per page (default 25); a pager appears when there is more than one page.
  • rowKey?: string | undefined — Stable row id — a column key (default: the row index).
  • rows: TableRow[] — All rows; the table filters, sorts and pages them itself.
  • sort?: { key: string; dir: "asc" | "desc"; } | undefined — Initial sort.

TableRow​

type TableRow = Record<string, unknown>;

One data row: a plain object keyed by Column.key. Cell values are formatted by formatCell.

ThemeMode​

type ThemeMode = 'light' | 'dark';

The two colour modes; read from html[data-theme], which the SDK runtime stamps from the shell.

TimeRange​

interface TimeRange

An ISO-8601 from / to pair, as TimeRangeField reads and reports it.

Members

  • from: string — Start instant, ISO-8601.
  • to: string — End instant, ISO-8601.

Tone​

type Tone = 'ok' | 'warn' | 'critical' | 'neutral';

The semantic colour a status-bearing component maps to a palette colour (ok, warn, critical, neutral).