1.0.5.2 Primitive components — Button, Input, Textarea, Card, Modal, Pill, Tooltip, Toast, Spinner
Estimate: 35m · Depends on: 1.0.5.1
Build the React primitive components that every screen will compose from. Nine primitives cover almost everything Motir's UI needs: Button (4 variants), Input, Textarea, Card, Modal, Pill / Tag, Tooltip, Toast, Spinner. Each must use only the tokens from 1.0.5.1 — never hardcoded values — so a future theme tweak propagates through one source.
Why this is the biggest Subtask in Story 1.0.5: primitives are the foundation of every later UI Subtask in the entire project. Getting them right (accessible, consistent, composable) saves work in every Subtask that touches the UI; getting them wrong propagates problems for months. This Subtask deserves the most attention in the story.
What you'll do: For each primitive, create a file under /components/ui/<Name>.tsx with a typed props interface, all variants implemented, and full keyboard / aria support. Use class-variance-authority for variant management and tailwind-merge for class composition (the modern React + Tailwind primitive pattern). Render every variant + state of every primitive on the /app/_tokens/page.tsx route from 1.0.5.1 as a living style guide.
Acceptance criteria
- Button: variants
primary | secondary | ghost | danger× sizessm | md | lg× statesdefault | hover | active | focus | disabled | loading. Loading state shows the Spinner inline. - Input, Textarea: with label, error message, helper text, disabled state, prefix/suffix slots.
- Card: with optional header / footer slots, hover state, optional clickable mode (wraps in
<a>or button). - Modal: accessible (focus trap, ESC closes, click-outside closes, returns focus on close), supports a header / body / footer slot pattern.
- Pill / Tag: variants for status (planned / in-progress / done) and severity (info / warn / danger / success).
- Tooltip: appears on hover + focus, sensible positioning, accessible name on the trigger.
- Toast: stackable, auto-dismiss with hover-to-pause, variants (info / success / warn / error).
- Spinner: 3 sizes; works inside Button and as standalone.
- Every primitive uses ONLY tokens from
globals.css— zero hardcoded hex / px values. /app/_tokens/page.tsxrenders all primitives × all variants × key states as a single specimen page.- Each primitive has a brief JSDoc
@examplecomment with a minimal usage sample.
Context refs
/app/globals.css(from 1.0.5.1) — the token sourcetailwind.config.ts(from 1.0.5.1) — the Tailwind theme- awesome-design-md — open-source component-pattern corpus, fetched at prompt-gen time
- Radix UI primitives docs (URL) — for the unstyled accessibility primitives we can wrap (Modal, Tooltip, Toast)
cva+tailwind-mergedocs