@intellia/app-ui
v0.7.0
Published
On-brand React primitives for apps built within the Hutly platform (by Sammy, other agents, or customers) — deliberately tiny, sized for a single-file HTML artifact. Not @intellia/design-system, which is the platform's own (ui/, admin/) unpublished compon
Readme
@intellia/app-ui
On-brand React primitives for apps built within the Intellia platform — by
Sammy, other agents, or customers. Deliberately tiny, sized for a single-file
HTML artifact. Not @intellia/design-system, which is the platform's own
(ui/, admin/) unpublished component system.
Install
yarn add @intellia/app-uiComponents
Button (primary, secondary, ghost), ButtonLink (an <a href> styled as
a Button), Input, Textarea, Select, Card, Text — plus initThemeSync,
which follows the host's live theme (window.hutly.theme) and reflects it as
data-theme on <html>.
For data-heavy screens: DataTable (controlled sort and paging, row click,
inline editable text and number cells), Dialog, Tabs, DatePicker,
Combobox (async search, debounced 250 ms), Menu (a button that opens a list
of actions), NumberInput (fixed decimals),
StatusChip (six semantic tones), Keypad (with a 64 px kiosk size) and
ToastProvider / useToast (built on sonner). Wrap the app once in ToastProvider.
A required Select whose value is "" or null shows a disabled
placeholder option ("Choose…", or its placeholder) instead of looking as if its
first option were chosen.
NumberInput, DatePicker and Combobox take invalid (sets aria-invalid and
the danger border) and aria-describedby, so a form can mark a field and link its
own message. Combobox also takes size, reports null as soon as its text is
cleared, and on Enter picks only an option the person highlighted or the first
match for text they typed.
A DataTable wider than its box shades the side with hidden columns and becomes
a focusable region (named by its optional label, else "Table") that arrow keys
scroll. Headers wrap.
Menu takes a label (the trigger text and the menu's name), optional
children to show instead (the label then stays the accessible name), the
Button's variant (default secondary) and size, and items of
{ label, onSelect, disabled?, tone?: "danger" }. It opens below the trigger,
aligned to its end edge (align="start" for the other), and stays on screen.
Arrow keys, Home and End move between items; Enter or Space selects; Escape and
Tab close it and return focus to the trigger.
<Menu
label="Actions"
items={[
{ label: "Duplicate", onSelect: duplicate },
{ label: "Delete", onSelect: confirmDelete, tone: "danger" },
]}
>
⋯
</Menu>A cleared editable number cell commits null; set editable.required to refuse
an empty cell (number or text) with an inline message instead. An editable number
cell or NumberInput with decimals refuses an entry with more places ("Up to 2
decimal places") rather than rounding it; trailing zeros do not count.
toast.success / error / info return the toast's id, and toast.dismiss(id?)
removes that toast (or every toast, without an id). Errors stay until dismissed,
so clear the stale one when the retry succeeds — or pass the same { id } to
replace it in place:
const toast = useToast();
toast.error("New item failed", message, { id: "create-item" });
// later, on success — replaces the error instead of stacking under it
toast.success("Item created", undefined, { id: "create-item" });Every component works inside the app frame's allow-scripts sandbox: buttons
are type="button", nothing submits a form, and nothing touches browser
storage. react-dom is a peer dependency (Dialog portals into the app's own
document.body).
Usage
import "@intellia/app-ui/tokens.css";
import { Button, Card, Text, initThemeSync } from "@intellia/app-ui";
initThemeSync();
function App() {
return (
<Card>
<Text as="h1" size="xl" weight="semibold">
Hutly App
</Text>
<Button onClick={() => console.log("clicked")}>Get started</Button>
</Card>
);
}intellia app init scaffolds a new project already wired with these primitives —
see @intellia/app-sdk's README for the full app-building workflow.
