Shared UI component library
At a glance
Action(the base icon-button factory) isn't exported — only its 19 pre-bound variants are.- Four focused "cell" molecules cover computed values, confirm/deny, inline edit, and route-level errors.
ConfigLabelexpects translation keys, not display text — it runs both props throught().ui'sMultiSelectandnode-inputs'sMultiSelectare unrelated components that happen to share a name.
packages/ui is a small library of Mantine-based building blocks shared across the apps: icon actions, cells for tabular/config UIs, layout chrome, and a couple of standalone widgets. This page is a functional tour — what each is for and where it's typically reached for — as a companion to the Reference section's prop signatures.
Actions: one icon button factory, many pre-bound variants
atoms/action/action.tsx defines Action — a Mantine ActionIcon wrapped with an optional Tooltip and a required Icon (a react-icons component) — but Action itself isn't exported from the package; atoms/action/index.ts only re-exports its variants. Each variant is a couple of lines: Action pre-bound to one specific icon and default variant. There are nineteen — Add, Edit, Delete, Move, Cancel, Complete, Connect, Settings, Options, Reset, Grid, Pointer, Lock / UnLock, TextSelect / FieldSelect, Clipboard / CellClipboard / ClipboardPlus — covering everything from the file-viewer selection clipboard buttons to graph-editing gestures. If you need a new icon button, adding a variant file (icon + default variant) is the existing pattern rather than using ActionIcon directly.
Cells: small, focused table/config renderers
Four molecules, each doing one narrow job inside a table or config row:
ComputedCell— renders a computed value, handling the shapes that value can actually take:null("can't compute"),undefined("undefined"), an empty string ("empty"), a single-element array (unwrapped and shown directly, after first flattening a[[...]]double-wrap), or a multi-element array (shown one at a time withMovebuttons to step through it, labeledn/totalin aBadge). Non-array values are passed throughparseOutput(utils) before display.ConfirmCell— a plain Confirm/Cancel button pair (handleAccept/handleDeny), no state of its own.EditCell— switches between aSelectand aTextInputbased on whether the passed Zodvalidationis an enum (isZodEnum, fromtypes): enum-validated fields get a dropdown of the enum's values, everything else gets free text. CallshandleChange(defaultValue)once on mount regardless of which branch renders.ErrorBoundary— a route-level error display (reads the error viareact-router-dom'suseRouteError, so it's meant to be used as a route'serrorElement, not a component-level try/catch boundary), reports to Sentry on mount, and shows the error's rawmessageonly whenprocess.env.NODE_ENV === 'development'.
Layout chrome
BaseHeader and BaseFooter are thin wrappers around Mantine's Header/Footer with a fixed height (60, uniformly across breakpoints) and a default sx (space-between for the footer, a bottom border for the header) that callers can still override via their own sx prop. ConfigInput is a Box capped at maxWidth: 300 for wrapping a single config field, and ConfigLabel renders a title/description pair for one, running both through i18next's t() — which means the strings passed to it are expected to already be translation keys, not display text (matching how node-logic's translate step turns block/option titles into keys before they ever reach the UI).
Standalone widgets
Badge is a minimal styled wrapper with no logic. InfoTooltip is a small "i" icon that shows label in a tooltip on hover — used throughout config panels for inline help text. MultiSelect is a creatable Mantine multi-select.
Two components, one name
Don't confuse ui's MultiSelect with the similarly-named, separately implemented MultiSelect in node-inputs — they're unrelated components in different packages that happen to share a name. Check the import path, not just the name, before assuming which one you're looking at.