Text inputs
One input treatment across the whole app: --silo-color-input-bg background, 6×8px padding, small radius, the shared focus ring. Four components cover the text-entry patterns modals use.
Input
import { Input } from "@silo-code/sdk";
<Input value={name} onChange={(e) => setName(e.target.value)} placeholder="Workspace name" />
<Input block /> {/* width: 100% */}| Prop | Type | Default | Notes |
|---|---|---|---|
block | boolean | false | stretch to the container width |
| …rest | React.ComponentProps<"input"> | controlled like any input |
Textarea
Same tokens as Input, plus comfortable line-height, vertical resize, and a sensible minimum height.
<Textarea
value={notes}
onChange={(e) => setNotes(e.target.value)}
placeholder="Notes…"
/>SearchInput
The filter-as-you-type field: leading search icon, and a clear ✕ that appears once there's a value. Pair it with a List for the standard picker pattern (there's no combined component on purpose — the composition is four lines; see Building modals).
<SearchInput
value={query}
onValueChange={setQuery}
placeholder="Filter branches…"
/>| Prop | Type | Notes |
|---|---|---|
value / onValueChange | string / (v: string) => void | controlled value |
placeholder | string? | |
autoFocus | boolean? | pickers usually want this |
onClear | (() => void)? | extra hook when ✕ clears |
InlineEdit
Click-to-edit a value in place — a static display with a pencil affordance that swaps to a field with explicit ✓ Save / ✗ Cancel buttons. Use it for values where committing an empty/invalid value would be visibly broken elsewhere (the canonical case: the workspace name, which renders in tabs, the sidebar, and the window title) — everything else in a modal should save as you type instead.
<InlineEdit
value={ws.name}
onSave={(name) => ctx.workspaces.rename(ws.id, name)}
validate={validateWorkspaceName} // optional — invalid ⇒ inline error, no save
aria-label="Rename workspace"
/>
<InlineEdit multiline value={description} onSave={setDescription} aria-label="Edit description" />| Prop | Type | Notes |
|---|---|---|
value | string | the committed value |
onSave | (value: string) => void | called with the trimmed, validated value; not called if unchanged |
validate | ((v: string) => { ok: true; value: string } | { ok: false; error: string })? | failure shows the error inline and blocks the save |
multiline | boolean? | textarea-based editing |
aria-label | string | required |
Keyboard (built in): entering edit focuses and selects the field. Enter saves — except in multiline, where plain Enter is a newline and ⌘/Ctrl+Enter saves. Escape is two-stage: the first Esc cancels the edit; the next Esc closes the modal (the host coordinates this — don't add your own Escape handling).
| Color | Token |
|---|---|
| Field background / text / border | --silo-color-input-bg / --silo-color-input-text / --silo-color-border |
| Display value | --silo-color-text-hi |
| Inline error | --silo-color-err |
| Pencil / ✓ / ✗ | stock IconButton size="sm" |