SetupCard

What every card shares: white with a hairline edge (CARD_FRAME), its topic as a heading on the white, and what it holds (fields, rows, its buttons at the foot) in a grey section inset 8px. A card of several topics passes sectioned and gives each a CardSection. Collapsed, it's one line, the topic and a summary: what stays where a card appeared earlier in the conversation. SetupField is its labelled text field that saves on blur or Enter.

Playground

Studio

SetupCard

Saving on blur or Enter

SetupField shows the saved value until the owner types. Leaving the field or pressing Enter hands the text to onCommit: return null once it's saved, or the reason it can't be — the text then stays, marked, with the reason under it. Escape brings the saved value back. While nobody is typing, the field follows saved, so a change made elsewhere shows at once. Try a number in this one.

Optional and refused

optional takes the word for it and puts it, bracketed, in the label. error shows a reason from outside, such as the server's, tied to the input.

Adding a row

A new service or person has no Add to tap: its row saves itself as the owner leaves it or presses Enter, like every other field on the card. Left blank, it goes quietly; started but incomplete, it stays with what's missing. Its trash button lets it go unsaved. See it on ServicesCard and TeamCard.

API reference

SetupCard

PropTypeDefaultDescription
titlestring—The topic, as a heading.
summarystring—One line of what the card holds, shown when collapsed.
collapsedbooleanfalseJust the title and summary.
actionReactNode—Beside the title: one button at most.
level2 | 3 | 42The title's heading level.
tone"page" | "thread""page"The type it reads in; the surface is the same. page: setup's fields' own. thread: a card in a chat (ChangeCard, DayCard, TodayCard), in the messages' type: text-sm, text-base on touch.
sectionedbooleanfalseIts children are CardSections, a topic each (DayCard, TodayCard): held as they are, not in the one grey section.
hideTitlebooleanfalseThe heading is read, not shown — in the conversation, where Okami's line introduces the card.
classNamestring—Layout only.

SetupField

PropTypeDefaultDescription
labelstring—The field's visible name.
savedstring—What's saved now.
onCommit(raw: string) => string | null—Save the text and return null, or return why it can't be saved.
optionalstring—The word for optional, in the label.
errorstring | null—A reason from outside to show.
hideLabelbooleanfalseRead the label, don't show it (rows under one heading).
leadingIconIcon—Drawn in the field, before the text.
size"sm" | "md" | "lg""md"As Input.

Guidelines

  • Build each topic on it — Studio, Services, Team, Hours, Summary — so they read as one set in the conversation.
  • Save on blur or Enter, never per keystroke: a half-typed name shouldn't reach the draft, or Okami.
  • A collapsed card is a trace, not a control. The live one is lower in the thread.