harebear-ui 0.6.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/AGENTS.md +32 -12
  2. package/README.md +109 -36
  3. package/bin/harebear-ui.mjs +66 -3
  4. package/dist/components/admin/app-nav.d.ts +57 -0
  5. package/dist/components/admin/app-nav.js +172 -0
  6. package/dist/components/admin/focus-layout.d.ts +14 -0
  7. package/dist/components/admin/focus-layout.js +36 -0
  8. package/dist/components/admin/settings.d.ts +31 -0
  9. package/dist/components/admin/settings.js +78 -0
  10. package/dist/components/ai/action-receipt.d.ts +16 -0
  11. package/dist/components/ai/action-receipt.js +47 -0
  12. package/dist/components/ai/ask-box.d.ts +27 -0
  13. package/dist/components/ai/ask-box.js +85 -0
  14. package/dist/components/ai/assistant.d.ts +94 -0
  15. package/dist/components/ai/assistant.js +229 -0
  16. package/dist/components/ai/dictation.d.ts +57 -0
  17. package/dist/components/ai/dictation.js +148 -0
  18. package/dist/components/data/sectioned-list.d.ts +37 -0
  19. package/dist/components/data/sectioned-list.js +139 -0
  20. package/dist/components/data/task-row.d.ts +22 -0
  21. package/dist/components/data/task-row.js +60 -0
  22. package/dist/components/layout/collapse.d.ts +14 -0
  23. package/dist/components/layout/collapse.js +24 -0
  24. package/dist/components/layout/media-item.d.ts +13 -0
  25. package/dist/components/layout/media-item.js +54 -0
  26. package/dist/components/layout/metric.d.ts +15 -0
  27. package/dist/components/layout/metric.js +51 -0
  28. package/dist/components/layout/show-more.d.ts +17 -0
  29. package/dist/components/layout/show-more.js +30 -0
  30. package/dist/components/layout/stack.d.ts +39 -0
  31. package/dist/components/layout/stack.js +114 -0
  32. package/dist/components/layout/text.d.ts +37 -0
  33. package/dist/components/layout/text.js +52 -0
  34. package/dist/components/theme/theme-toggle.d.ts +4 -1
  35. package/dist/components/theme/theme-toggle.js +11 -6
  36. package/dist/components/ui/check-circle.d.ts +16 -0
  37. package/dist/components/ui/check-circle.js +39 -0
  38. package/dist/components/ui/sonner.d.ts +15 -2
  39. package/dist/components/ui/sonner.js +20 -3
  40. package/dist/index.d.ts +18 -2
  41. package/dist/index.js +18 -2
  42. package/dist/styles.css +75 -0
  43. package/docs/COMPONENTS.md +160 -21
  44. package/docs/ROADMAP.md +95 -0
  45. package/docs/guides/agents.md +75 -0
  46. package/docs/guides/getting-started.md +217 -0
  47. package/docs/guides/theming.md +99 -0
  48. package/llms.txt +11 -3
  49. package/package.json +2 -1
  50. package/skills/harebear-ui/SKILL.md +2 -1
package/dist/styles.css CHANGED
@@ -53,6 +53,12 @@
53
53
  --color-chart-4: var(--chart-4);
54
54
  --color-chart-5: var(--chart-5);
55
55
  --color-chart-grid: var(--chart-grid);
56
+ --color-category-1: var(--category-1);
57
+ --color-category-2: var(--category-2);
58
+ --color-category-3: var(--category-3);
59
+ --color-category-4: var(--category-4);
60
+ --color-category-5: var(--category-5);
61
+ --color-category-6: var(--category-6);
56
62
  --color-sidebar: var(--sidebar);
57
63
  --color-sidebar-foreground: var(--sidebar-foreground);
58
64
  --color-sidebar-primary: var(--sidebar-primary);
@@ -108,6 +114,13 @@
108
114
  --chart-4: #0f8a7e;
109
115
  --chart-5: #8b5cc9;
110
116
  --chart-grid: #eeeef0;
117
+ /* Category palette for members, lists and calendars: 1 blue, 2 teal, 3 violet, 4 rose, 5 slate, 6 cyan. Never a status color. */
118
+ --category-1: #3166d4;
119
+ --category-2: #0d8578;
120
+ --category-3: #7a4cc7;
121
+ --category-4: #c03a78;
122
+ --category-5: #5a6578;
123
+ --category-6: #0a7fa3;
111
124
  --elevation: 0 1px 2px rgb(24 24 27 / 0.04), 0 6px 20px rgb(24 24 27 / 0.05);
112
125
 
113
126
  --sidebar: var(--background);
@@ -149,6 +162,12 @@
149
162
  --chart-4: #3cb8a8;
150
163
  --chart-5: #a98ae0;
151
164
  --chart-grid: #242427;
165
+ --category-1: #76a0f2;
166
+ --category-2: #3dbcac;
167
+ --category-3: #ad8de6;
168
+ --category-4: #ec7fae;
169
+ --category-5: #9ba6b8;
170
+ --category-6: #4cbde0;
152
171
  --elevation: 0 1px 2px rgb(0 0 0 / 0.3), 0 8px 24px rgb(0 0 0 / 0.22);
153
172
 
154
173
  color-scheme: dark;
@@ -187,6 +206,62 @@
187
206
  animation: hb-typing 1.2s infinite ease-in-out;
188
207
  }
189
208
 
209
+ /*
210
+ * Composite focus: the box around a bare field shows the focus ring (AskBox, SectionedList's add box).
211
+ * Pair with a border and fill: `rounded-xl border border-transparent bg-muted focus-box`.
212
+ */
213
+ @utility focus-box {
214
+ transition-property: border-color, background-color, box-shadow;
215
+ transition-duration: 150ms;
216
+ &:focus-within {
217
+ border-color: var(--primary);
218
+ background-color: var(--card);
219
+ box-shadow: 0 0 0 4px color-mix(in oklab, var(--primary) 15%, transparent);
220
+ }
221
+ }
222
+
223
+ /* Check pop: a short scale bump when a CheckCircle is ticked. */
224
+ @keyframes hb-check-pop {
225
+ 0% {
226
+ transform: scale(1);
227
+ }
228
+ 40% {
229
+ transform: scale(1.18);
230
+ }
231
+ 100% {
232
+ transform: scale(1);
233
+ }
234
+ }
235
+
236
+ @utility animate-check-pop {
237
+ animation: hb-check-pop 260ms cubic-bezier(0.3, 0.7, 0.4, 1.4);
238
+ }
239
+
240
+ /* Listening bars for DictationButton. */
241
+ @keyframes hb-listening {
242
+ 0%,
243
+ 100% {
244
+ transform: scaleY(0.35);
245
+ }
246
+ 50% {
247
+ transform: scaleY(1);
248
+ }
249
+ }
250
+
251
+ @utility animate-listening {
252
+ animation: hb-listening 900ms infinite ease-in-out;
253
+ }
254
+
255
+ @media (prefers-reduced-motion: reduce) {
256
+ .animate-check-pop,
257
+ .animate-listening {
258
+ animation: none;
259
+ }
260
+ .focus-box {
261
+ transition: none;
262
+ }
263
+ }
264
+
190
265
  /* Thin, quiet scrollbars in the theme's colors. Firefox and Chromium use the standard properties; Safari the ::-webkit rules. */
191
266
  @layer base {
192
267
  * {
@@ -16,6 +16,36 @@ Full working screens that combine these live in the repo under `playground/scree
16
16
  - **Icons are lucide-react elements.** Pass `<SearchIcon />`, not the component. Buttons size icons automatically.
17
17
  - **Status uses tones**, not colors: `"success" | "warning" | "danger" | "info" | "neutral"`.
18
18
 
19
+ ## Agent-first apps
20
+
21
+ A household or personal app where an assistant sits on every page and safe actions run on their own, with Undo.
22
+
23
+ ```tsx
24
+ <ThemeProvider>
25
+ <TooltipProvider>
26
+ <AssistantProvider onSend={(text, { page, append }) => runAgent(text, page, append)}>
27
+ <AppNav
28
+ brand={<AppBrand name="Homeclub" icon={<HouseIcon />} />}
29
+ places={[{ label: "Today", icon: <SunIcon />, href: "/", active: true, count: 3 }, ...]}
30
+ group={{ label: "Lists", items: lists, onAdd: newList, addLabel: "New list" }}
31
+ action={{ label: "New to-do", icon: <PlusIcon />, onSelect: openQuickAdd }}
32
+ footer={<UserMenu name={user.name} onSignOut={signOut} />}
33
+ >
34
+ <Outlet /> {/* pages call useAssistantPage({ id, title, suggestions }) */}
35
+ <AssistantDock title="HomeBot" fullScreenHref="/chat" />
36
+ </AppNav>
37
+ <Toaster />
38
+ </AssistantProvider>
39
+ </TooltipProvider>
40
+ </ThemeProvider>
41
+ ```
42
+
43
+ - Lists: `SectionedList` (`TaskRow` rows); when the agent or a bulk action changes data, confirm with `toastUndo`.
44
+ - In the assistant thread, each action it took is an `ActionReceipt` with Undo (append it from `onSend`).
45
+ - Settings and setup flows leave the frame: `FocusLayout` around `SettingsSection`s of `SettingsRow`s.
46
+ - Members, lists and calendars take a `category-1..6` color; status colors never double as categories.
47
+ - Live example: `playground/screens/household.tsx` (`#household`) and `settings.tsx` (`#settings`).
48
+
19
49
  ## Theme
20
50
 
21
51
  | Export | Use |
@@ -57,6 +87,7 @@ Every component in the shadcn registry is included. (shadcn's `form` item is an
57
87
  | Carousel | `Carousel`, `CarouselContent`, `CarouselItem`, `CarouselPrevious`, `CarouselNext`, `useCarousel`, type `CarouselApi` | embla. |
58
88
  | Chart | `ChartContainer`, `ChartTooltip`, `ChartTooltipContent`, `ChartLegend`, `ChartLegendContent`, `ChartStyle` | Recharts wrappers. Prefer `TrendChart` for line/area; use these for custom charts. |
59
89
  | Checkbox | `Checkbox` | |
90
+ | Check circle | `CheckCircle` | harebear. 24px round checkbox for to-do rows (44px touch target), pops when ticked. `tone="important"` tints it; pair with a word. Name it with `aria-labelledby` the row title. |
60
91
  | Collapsible | `Collapsible`, `CollapsibleTrigger`, `CollapsibleContent` | |
61
92
  | Combobox | `Combobox`, `ComboboxInput`, `ComboboxContent`, `ComboboxList`, `ComboboxItem`, `ComboboxGroup`, `ComboboxLabel`, `ComboboxCollection`, `ComboboxEmpty`, `ComboboxSeparator`, `ComboboxChips`, `ComboboxChip`, `ComboboxChipsInput`, `ComboboxTrigger`, `ComboboxValue`, `useComboboxAnchor` | Searchable select (Base UI). `<Combobox items={list}>` + `<ComboboxList>{(item) => <ComboboxItem value={item}>…}</ComboboxList>`. Chips for multi-select. |
62
93
  | Command | `Command`, `CommandDialog`, `CommandInput`, `CommandList`, `CommandEmpty`, `CommandGroup`, `CommandItem`, `CommandShortcut`, `CommandSeparator` | Use for ⌘K palettes. |
@@ -98,7 +129,7 @@ Every component in the shadcn registry is included. (shadcn's `form` item is an
98
129
  | Table | `Table`, `TableHeader`, `TableBody`, `TableFooter`, `TableRow`, `TableHead`, `TableCell`, `TableCaption` | Borderless rows with rounded hover; quiet 12px headers. `data-state="selected"` tints a row. |
99
130
  | Tabs | `Tabs`, `TabsList`, `TabsTrigger`, `TabsContent`, `tabsListVariants` | `TabsList variant`: `default` (segmented control), `pill` (rounded top-level nav), `line`. Use `Tabs` as a segmented filter too (date ranges, status filters). |
100
131
  | Textarea | `Textarea` | Same filled style as `Input`, auto-grows. |
101
- | Toast | `Toaster` | sonner. Mount once; call `toast("Saved")` from `sonner`. Follows the theme mode. |
132
+ | Toast | `Toaster` | sonner. Mount once; call `toast("Saved")` from `sonner`. Follows the theme mode. `toastUndo(message, { onUndo, undoLabel?, duration = 9000 })` shows an Undo toast for something already done. |
102
133
  | Toggle | `Toggle`, `toggleVariants`, `ToggleGroup`, `ToggleGroupItem` | |
103
134
  | Tooltip | `TooltipProvider`, `Tooltip`, `TooltipTrigger`, `TooltipContent` | Mount `TooltipProvider` once near the root. |
104
135
  | Trace | `Trace`, `TraceLine`, `TraceIcon`, `TraceTitle`, `TraceDescription`, `TraceCollapsible`, `TraceCollapsibleTrigger`, `TraceCollapsibleContent` | Agent step log (searched, read, ran). `TraceLine status`: `running` (shimmer), `error`, `pending`. |
@@ -242,6 +273,72 @@ Quiet note with an icon (sparkle by default). Props: `icon?`, `tone?` (`"muted"
242
273
 
243
274
  Muted tile that lifts on hover, for service launchers. Props: `title`, `subtitle?` (mono), `icon?`, `status?: { tone; label }`, `href`, or `asChild` with your router `<Link>` as the only child.
244
275
 
276
+ ### `AppNav`
277
+
278
+ One nav config, two renderings: on desktop a `SidebarLayout` sidebar (brand, action button, places, one collapsible group, footer; active place is a raised card; collapses to the icon rail), under 768px a bottom tab bar (first 5 places, 56px targets, `aria-current="page"`) plus a round floating action button. Use it instead of `AppShell` for consumer apps that need phone navigation.
279
+
280
+ Props: `places: AppNavPlace[]` (`label`, `icon?`, `href?` or `onSelect?`, `active?`, `count?`, `tab?: false` to keep out of the tab bar), `group?: AppNavGroup` (`label`, `items`, `defaultOpen?`, `onAdd?`, `addLabel?`), `action?: { label; icon; onSelect }`, `brand?`, `footer?` (usually `UserMenu`), `label?` (nav name, default "Main"), `linkComponent?`, `collapsible?`, `storageKey?`, `defaultOpen?`, `width?`, `children`.
281
+ On phones the group and footer live in the sidebar sheet: put a `SidebarTrigger` in the page header if users need them there. Render `AssistantDock` inside `children` so it clears the tab bar, and mount `<Toaster mobileOffset={{ bottom: "5.5rem" }} />` so toasts do too.
282
+
283
+ ### `FocusLayout`
284
+
285
+ A page outside the app frame (settings, onboarding, setup): slim sticky top bar, one centred column. Props: `title?`, `back?` (close or back link; icon-only needs `aria-label`), `actions?`, `width?` (`sm | md | lg`, default `md` = 42rem).
286
+
287
+ ### `SettingsSection`, `SettingsRow`
288
+
289
+ `SettingsSection`: card with `title`, `description?` and rows divided by hairlines (a labelled `region`). `SettingsRow`: `label`, `description?`, `control?` (Switch, Select, ToggleGroup, Button), `htmlFor?` (makes the label a `<label>` for the control). Add `content` to expand inline (change password, add a connection): without a `control` the row gets a "Change"/"Cancel" button (`expandLabel?`); control it with `open`/`onOpenChange` or `defaultOpen`.
290
+
291
+ ```tsx
292
+ ;<FocusLayout
293
+ title="Settings"
294
+ back={
295
+ <Button asChild variant="ghost" size="icon">
296
+ <a href="/" aria-label="Close">
297
+ <XIcon />
298
+ </a>
299
+ </Button>
300
+ }
301
+ >
302
+ <SettingsSection title="Notifications">
303
+ <SettingsRow
304
+ label="Daily summary"
305
+ description="Every morning at 7"
306
+ htmlFor="daily"
307
+ control={<Switch id="daily" />}
308
+ />
309
+ <SettingsRow label="Password" content={<ChangePasswordForm />} />
310
+ </SettingsSection>
311
+ </FocusLayout>
312
+ ```
313
+
314
+ ## Layout and text
315
+
316
+ Props instead of class names, for blocks that should look right without styling (dashboard widgets, generated UI). Every class string is a literal, so Tailwind finds them.
317
+
318
+ ### `Stack`, `Row`, `Grid`
319
+
320
+ `Stack` stacks children vertically, `Row` lays them out horizontally (`align`, `justify`, `wrap`). Both take a named `gap`: `none | xs | sm | md | lg | xl`. `Grid` makes equal columns: `cols={3}` or `cols={{ base: 1, sm: 2, md: 3 }}`. With `query="container"` the breakpoints measure the nearest `@container` ancestor (sm 28rem, md 42rem, lg 56rem) instead of the screen, for blocks that sit in cards of any width.
321
+
322
+ ### `Text`, `Heading`
323
+
324
+ `Text` takes `size` (`xs | sm | base | lg | xl | 2xl`), `tone` (`default | muted | success | warning | danger | info`), `weight`, `mono`, `truncate`, `lines` (1 to 3) and `tabular`, and renders `as` a span, p or div. `Heading` is a card section title (`level={3}`) or a small uppercase group label (`level={4}`).
325
+
326
+ ### `Metric`, `MetricGroup`
327
+
328
+ A number with `value`, `unit`, `label` and an optional `delta` in percent, green when it improves (`lowerIsBetter` for latency and the like). `MetricGroup` sets metrics side by side, evenly spaced.
329
+
330
+ ### `MediaItem`
331
+
332
+ Thumbnail (`image`, `imageShape`: `poster | square | wide`), a two-line `title` (linked when `href` is set, new tab), a `meta` line and a two-line `description`.
333
+
334
+ ### `ShowMore`
335
+
336
+ Shows the first `initial` children (default 5) and a "Show N more" button for the rest.
337
+
338
+ ### `Collapse`
339
+
340
+ Animates children between full height and 0 (CSS `grid-template-rows`), so neighbours slide instead of jumping. Closed content is `inert` and `aria-hidden`. Props: `open`, `contentClassName?`. No motion under `prefers-reduced-motion`.
341
+
245
342
  ## Data display
246
343
 
247
344
  ### `DataTable`
@@ -286,6 +383,23 @@ Tiny trend line. Props: `data: number[]`, `color?`, `area?` (fill, default true)
286
383
 
287
384
  Mini bar history (pings, uptime). Props: `data: (number | { value; tone?; label? })[]`, `max?`, `tone?` (default for plain numbers). Default size 96x26.
288
385
 
386
+ ### `TaskRow`
387
+
388
+ One to-do: `CheckCircle` aligned with the first line, title, one meta line, optional assignee avatar. Props: `title`, `checked`, `onCheckedChange(checked)`, `meta?`, `assignee?: { name; avatarUrl? }`, `important?` (say it in `meta` too), `onOpen?` (title becomes a button, e.g. to open a sheet), `disabled?`.
389
+
390
+ ### `SectionedList`
391
+
392
+ A to-do list: one add box at the top, sections with headings, done items folded into a "Show N done" toggle, an empty state. A ticked row stays visible for a moment, then folds away with `Collapse`. Props: `sections: { id; title?; items: SectionedListItem[] }[]` (item: `id`, `title`, `meta?`, `done?`, `important?`, `assignee?`), `onToggle(id, done)`, `onAdd?(text)`, `addPlaceholder?` (default "Add a to-do"), `onOpen?(id)`, `empty?`, `defaultShowDone?`.
393
+
394
+ ```tsx
395
+ ;<SectionedList
396
+ sections={[{ id: "today", title: "Today", items: todos }]}
397
+ onToggle={(id, done) => setDone(id, done)}
398
+ onAdd={addTodo}
399
+ empty={<Empty title="All clear" />}
400
+ />
401
+ ```
402
+
289
403
  ## AI and chat
290
404
 
291
405
  A chat screen is `ChatShell` (sidebar with `AppBrand`, `NewConversationButton`, `ConversationList`, `UserMenu`; optional details panel) around a `ChatPanel` (header, thread, `PromptInput`). Agent apps add `ToolGroup`/`ToolStep` for tool calls and `ApprovalCard`/`ApprovalResult` for permission prompts. See `playground/screens/chat.tsx` and `playground/screens/agent.tsx`.
@@ -414,6 +528,27 @@ Agent tool calls as a bordered, collapsible card. `ToolStatus = "queued" | "wait
414
528
  `ApprovalCard`: warning-ringed card for anything the agent waits on the user for. Props: `title`, `description?`, `icon?` (default shield, `null` for none), `reason?` (shown first after a bold "Why:"), `code?` + `codeLabel?` (wrapped code block with copy), `actions?` (buttons), `footer?`, `children` (more body).
415
529
  `ApprovalResult`: one-line record in the thread. Props: `decision: "approved" | "denied"`, `time?`, `children`.
416
530
 
531
+ ### `AssistantProvider`, `useAssistant`, `useAssistantPage`
532
+
533
+ One assistant conversation across pages. `AssistantProvider` props: `onSend(text, { page, messages, append, update })` (return the reply, or `append`/`update` messages yourself for streaming and receipts; a thrown error becomes the reply), `initialMessages?`, `defaultOpen?`. `useAssistant()` returns `{ open, setOpen, toggle, messages, pending, page, setPage, send, append, update, clear }`. A page calls `useAssistantPage({ id, title?, data?, suggestions? })` to become the context while mounted.
534
+
535
+ ### `AssistantDock`
536
+
537
+ The assistant as a floating panel over the page (never reflows it): header (icon, title, full-screen link, close), empty state with suggestions, thread, `AskBox`. Closed, it is a soft launcher button. Escape closes and returns focus to the launcher. Props: `title?` (default "Assistant"), `icon?`, `fullScreenHref?`, `emptyTitle?`, `emptyDescription?`, `suggestions?` (default: the page's), `placeholder?`, `dictation?`, `launcher?` (false when another control opens it), `launcherLabel?`.
538
+
539
+ ### `AskBox`
540
+
541
+ Large rounded composer: auto-growing text, `chips` shown while there is text, suggestion pills, `DictationButton`. The focus ring is on the box (`focus-box`). Props: `value`, `onValueChange`, `onSubmit(text)`, `placeholder?` (also the label, default "Ask anything"), `chips?`, `suggestions?`, `onSuggestion?` (default submits), `dictation?` (`SpeechSource`, or `false` to hide the mic), `lang?`, `disabled?`.
542
+
543
+ ### `DictationButton`, `useDictation`, `browserSpeechSource`
544
+
545
+ `DictationButton`: one round button that is a mic when the text is empty, stop with listening bars while listening (announces "Listening" politely), send once there is text. Props: `value`, `onTranscript(text)`, `onSend?` (else it submits the form), `source?`, `lang?`, `disabled?`. Without a supported source the mic is hidden.
546
+ `SpeechSource` is `{ isSupported(); start(handlers, { lang }) => stop }`; `browserSpeechSource` (default) uses the Web Speech API. `useDictation({ source?, lang?, onTranscript })` returns `{ supported, listening, interim, error, start, stop }` for custom controls.
547
+
548
+ ### `ActionReceipt`
549
+
550
+ What the assistant did, as a compact card: round check, `title` (past tense), `meta?`, Undo (`onUndo?`, `undoLabel?`). `undone` strikes it through and shows "Undone".
551
+
417
552
  ### `CodeSnippet`, `InlineCode`, `Prose`
418
553
 
419
554
  `CodeSnippet`: one-prop code panel with language label, copy button and shiki syntax highlighting (each language loads on first use). Props: `code`, `language?` (`bash`, `tsx`, `ts`, `js`, `json`, `python`, `sql`, `yaml`, `css`, `html`, `markdown`, `diff`; others render plain), `highlight?` (default true), `lineNumbers?`, `hideCopy?`. Built on the `CodeBlock` primitives; drop to those for diffs or highlighted lines.
@@ -462,34 +597,38 @@ Props: `onSubmit?({ name?, email, password })`, `nameField?` (default true), `co
462
597
 
463
598
  ## Hooks and utilities
464
599
 
465
- | Export | Use |
466
- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
467
- | `useCopyToClipboard(resetMs?)` | `{ copied, copy(text) }` for copy buttons. |
468
- | `useHighlightedCode(code, language)` | Shiki-highlighted lines (one node per line) for custom `CodeBlock`s; plain lines until the language loads. |
469
- | `loadHighlighter(language)`, `highlightCode(code, language)` | Async shiki access outside React. |
470
- | `useIsMobile()` | `true` under 768px. |
471
- | `useMediaQuery(query)` | `true` while the media query matches; `false` during SSR. |
472
- | `cn(...classes)` | clsx + tailwind-merge. Use for every `className` you compose. |
600
+ | Export | Use |
601
+ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
602
+ | `useCopyToClipboard(resetMs?)` | `{ copied, copy(text) }` for copy buttons. |
603
+ | `useHighlightedCode(code, language)` | Shiki-highlighted lines (one node per line) for custom `CodeBlock`s; plain lines until the language loads. |
604
+ | `loadHighlighter(language)`, `highlightCode(code, language)` | Async shiki access outside React. |
605
+ | `useIsMobile()` | `true` under 768px. |
606
+ | `useAssistant()`, `useAssistantPage(page)`, `useDictation(options)` | See [`AssistantProvider`](#assistantprovider-useassistant-useassistantpage) and [`DictationButton`](#dictationbutton-usedictation-browserspeechsource). |
607
+ | `useMediaQuery(query)` | `true` while the media query matches; `false` during SSR. |
608
+ | `cn(...classes)` | clsx + tailwind-merge. Use for every `className` you compose. |
473
609
 
474
610
  ## Tokens
475
611
 
476
612
  Use these as Tailwind utilities (`bg-*`, `text-*`, `border-*`, `ring-*`, `fill-*`, `stroke-*`):
477
613
 
478
- | Token | Use |
479
- | ----------------------------------- | ------------------------------------------------------------------------------------------------- |
480
- | `background` / `foreground` | Page background and body text. |
481
- | `card` / `card-foreground` | Raised surfaces (cards, active nav item, popovers via `popover`). |
482
- | `muted` / `muted-foreground` | Inputs, segmented controls, quiet panels; secondary text and labels. |
483
- | `primary` / `primary-foreground` | Brand accent (from `--brand`). Primary buttons, links, chart line. |
484
- | `primary-soft` | Tinted primary background for selected rows, soft badges, icon circles. Pair with `text-primary`. |
485
- | `secondary`, `accent` | Same as muted; kept for shadcn compatibility. |
486
- | `success`, `warning`, `destructive` | Status colors. Use `bg-success/12 text-success` for soft status fills. |
487
- | `border`, `input`, `ring` | Hairlines, input borders, focus rings. |
488
- | `chart-1` … `chart-5`, `chart-grid` | Data series and gridlines. |
489
- | `sidebar-*` | Sidebar surfaces (default to the page tokens). |
614
+ | Token | Use |
615
+ | ----------------------------------- | ------------------------------------------------------------------------------------------------------- |
616
+ | `background` / `foreground` | Page background and body text. |
617
+ | `card` / `card-foreground` | Raised surfaces (cards, active nav item, popovers via `popover`). |
618
+ | `muted` / `muted-foreground` | Inputs, segmented controls, quiet panels; secondary text and labels. |
619
+ | `primary` / `primary-foreground` | Brand accent (from `--brand`). Primary buttons, links, chart line. |
620
+ | `primary-soft` | Tinted primary background for selected rows, soft badges, icon circles. Pair with `text-primary`. |
621
+ | `secondary`, `accent` | Same as muted; kept for shadcn compatibility. |
622
+ | `success`, `warning`, `destructive` | Status colors. Use `bg-success/12 text-success` for soft status fills. |
623
+ | `border`, `input`, `ring` | Hairlines, input borders, focus rings. |
624
+ | `chart-1` … `chart-5`, `chart-grid` | Data series and gridlines. |
625
+ | `category-1` … `category-6` | Members, lists, calendars: blue, teal, violet, rose, slate, cyan, each with a dark value. Never status. |
626
+ | `sidebar-*` | Sidebar surfaces (default to the page tokens). |
490
627
 
491
628
  Other theme values: `rounded-sm/md/lg/xl/2xl` scale from `--radius` (default 14px; cards use `xl`, buttons and inputs `md`), `shadow-card` (the one elevation), `font-sans` (Geist), `font-mono` (Geist Mono), `animate-typing`.
492
629
 
630
+ Utilities: `focus-box` gives the box around a bare field the focus ring (primary border, card fill, 4px halo); pair it with `border border-transparent bg-muted`. `animate-check-pop` and `animate-listening` are the check and dictation animations. All motion is off under `prefers-reduced-motion`.
631
+
493
632
  Override any token in your CSS after the import:
494
633
 
495
634
  ```css
@@ -0,0 +1,95 @@
1
+ # Roadmap: components for household and agent-first apps
2
+
3
+ Status: the "Build first" list shipped in 0.8.0 (2026-11-11). Everything else is still proposed. Built items name their exports; see `docs/COMPONENTS.md` and the "Agent-first apps" recipe there.
4
+
5
+ These come from designing Homeclub, a household app with shared to-dos, calendars, docs and an assistant (HomeBot) on every page. The design and its notes live in the `HMilbradt/homeclub` repository (`design/`, `docs/missing-components.md`, `docs/research/`). Everything below was drawn there as plain markup with harebear-ui tokens. The aim is that the next app like it needs none of that markup: the library covers the common cases.
6
+
7
+ Judged against harebear-ui 0.7.0 (`src/components/`). Props of existing components were not checked one by one; an item marked "extends" may already be partly covered.
8
+
9
+ ## Reuse before building
10
+
11
+ These already exist and the Homeclub designs map onto them; new work should extend them, not fork them.
12
+
13
+ SidebarLayout, AppShell, UserMenu, ChatShell, ChatMessage, PromptInput, ConversationList, ToolSteps, TypingIndicator, ApprovalCard, Sheet, Drawer, Dialog, Popover, Sonner (Toaster), ToggleGroup, Tabs, Calendar, Empty, Avatar, Badge, Status, LinkTile, CopyField, Prose, AuthLayout.
14
+
15
+ ## Build first
16
+
17
+ Most reuse across apps, and Homeclub needs each on day one.
18
+
19
+ All built in 0.8.0:
20
+
21
+ 1. **AppNav** (`AppNav`, types `AppNavPlace`, `AppNavGroup`, `AppNavAction`): one config, desktop sidebar on SidebarLayout and a phone tab bar with a floating action button.
22
+ 2. **Assistant layer**: `AssistantProvider`, `useAssistant`, `useAssistantPage`, `AssistantDock`, `AskBox`, `DictationButton`, `useDictation`, `browserSpeechSource`, `ActionReceipt`.
23
+ 3. **Undo toast and motion**: `toastUndo` (Sonner), `Collapse`, `animate-check-pop`, all CSS and off under reduced motion.
24
+ 4. **Lists**: `CheckCircle`, `TaskRow`, `SectionedList`.
25
+ 5. **Settings**: `FocusLayout`, `SettingsSection`, `SettingsRow` (a settings page is FocusLayout plus sections; no separate SettingsLayout).
26
+ 6. **Foundations**: `category-1` to `category-6` tokens and the `focus-box` utility.
27
+
28
+ Calendar views and SmartInput follow when a second app needs them.
29
+
30
+ ## 1. Layouts and app frame (`admin/` or `layout/`)
31
+
32
+ | Component | What it does | Notes |
33
+ | :----------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------- |
34
+ | AppNav (built) | Takes one config (places, a collapsible group such as Lists, an "add" action, the profile menu). Renders the desktop sidebar (no border, active item as a raised card, profile popover at the bottom, sticky on long pages) and, under a breakpoint, a bottom tab bar with one round action button. | Extends SidebarLayout and UserMenu. The phone half is new. |
35
+ | FocusLayout (built) | A page outside the app frame: slim top bar with a close or back link and a title, then one centred column. | Settings, onboarding, setup flows. |
36
+ | SettingsSection, SettingsRow (built) | Card with a heading; rows with label, one-line description and a control slot (switch, select, segmented control, button). Rows can expand inline (change password, add a connection). | Most settings pages become composition only. |
37
+ | DetailSheet | A record's details: side sheet on desktop, full-screen sheet on a phone, with a close button and a scrollable body. | Extends Sheet and Drawer with one responsive API. |
38
+ | ReaderLayout | Back link, title, author and updated line, actions at the top (Edit, Chat with HomeBot), then Prose. | Docs, help, notes. |
39
+ | PageColumn | Centred column with a standard header slot (greeting or title, filter, primary input). | Today, Upcoming, list pages. |
40
+ | AuthLayout, single card variant | Calm centred card with the product mark, for sign in, invite and first-run setup. | Extends AuthLayout. |
41
+
42
+ ## 2. Assistant layer (`ai/`)
43
+
44
+ | Component | What it does | Notes |
45
+ | :-------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------ |
46
+ | AssistantProvider (built) | Holds the current conversation across pages and knows which page is open, so the assistant can use it as context. | Hook: `useAssistant()`. |
47
+ | AssistantDock (built) | Floating panel over the page (never reflows it) with header, empty state, thread, receipts and composer; a soft launcher button when closed; a link to full screen. Same on every page; pages pass suggestions only. | Extends ChatShell. |
48
+ | AskBox (built) | Large rounded input with chips that appear as you type, suggestion pills under it, and the dictation button. Focus ring on the box, not the field. | One placeholder per app ("Ask HomeBot anything"). |
49
+ | DictationButton, `useDictation` (built) | One button that is a microphone when empty, a stop button while listening (with listening bars and a live region), and send once there is text. The speech source plugs in (browser speech recognition, a server model). | Off-animation under reduced motion. |
50
+ | ActionReceipt (built) | What the assistant did, as a compact card: round check, title, one meta line, Undo. One per action. | The core of "safe actions run on their own". |
51
+ | WhatIDid | Collapsed list of plain past-tense steps under an answer. | A plain-language variant of ToolSteps. |
52
+ | ProgressCard | A long-running job: title, status word, progress bar, time left, an action when finished. | Downloads, imports, syncs. |
53
+ | ChatsHome | Recent chats grouped Today, This week, Earlier, with search and a row menu (Rename, Delete with inline confirm). | Extends ConversationList. |
54
+ | CitationChip | Pill link to the source an answer used. | |
55
+ | AssistantStatus | Working, needs you, done, shown on the launcher and in chat lists. | |
56
+
57
+ ## 3. Items, lists and calendar
58
+
59
+ | Component | What it does | Notes |
60
+ | :----------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------ |
61
+ | CheckCircle (built) | 24px round check, top-aligned with the first line, a pop when ticked, an "important" tint paired with a word. | `ui/` primitive. |
62
+ | TaskRow (built) | Check, title, one meta line, optional assignee avatar, opens a DetailSheet. | Works in any to-do or checklist app. |
63
+ | SectionedList (built) | Sections, one add box, finished items folded into "Show N done", empty state, items leaving without layout shift. | Uses the motion helpers below. |
64
+ | SmartInput | A text input that turns phrases into removable chips; the app supplies the rules (dates, people, lists). | Shared by quick add and the AskBox. |
65
+ | AgendaRow, DayStrip, WeekScroll, MiniMonth | Time, icon or check, title and whose dot; a strip of day buttons that jump to a day; stacked days you scroll; a month with event dots. | Calendar today is a date picker only. |
66
+ | SegmentedControl | Two or three options, raised selected segment (Mine / Everyone, Agenda / Week). | Restyle of ToggleGroup. |
67
+ | FilterChips, VisibilityBadge | On/off chips; "Only you" with a lock or "Everyone" with faces. | |
68
+ | InlineConfirm | A plain confirmation shown in place, for the few destructive actions that keep one. | Lighter than ConfirmDialog. |
69
+ | ChoiceCards | Two or three large side-by-side options (Google or Calendar link, Adult or Child). | |
70
+ | SearchHero, CardGrid | Big search box over a grid of LinkTiles grouped by topic. | |
71
+
72
+ ## 4. People
73
+
74
+ | Component | What it does |
75
+ | :---------------- | :------------------------------------------------------------------------------------------ |
76
+ | MemberAvatar | Photo, falling back to initial on the member's colour; sizes; ring variant. Extends Avatar. |
77
+ | AvatarStack | Overlapping faces with a "+N". |
78
+ | AvatarUpload | Upload, change or remove a photo with live preview. |
79
+ | ColorSwatchPicker | Radio group of category colours; colours used by someone else are marked and disabled. |
80
+
81
+ ## 5. Feedback and motion
82
+
83
+ | Item | What it does | Notes |
84
+ | :-------------------- | :----------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
85
+ | `toastUndo()` (built) | Standard wrapper around Sonner: action label, Undo, 9 second window, pause on hover, stacking and entry animation. | Sonner is already the toast layer. Check its current API before building. |
86
+ | Motion helpers | Check pop, collapse without layout shift, an optimistic list hook (`useOptimisticList`). | Built as CSS with no new dependency: `animate-check-pop`, `Collapse`. `useOptimisticList` is still proposed (React 19 `useOptimistic` may be enough). |
87
+ | Celebration | Occasional confetti when a day is cleared. Off under reduced motion. | Candidate: canvas-confetti. |
88
+
89
+ ## 6. Foundations (`src/styles.css`)
90
+
91
+ - **Category palette (built: `category-1..6`).** Six or so non-status colours for members, lists and calendars, each with a dark-mode value. Homeclub hard-codes hex values that stay the same in dark mode. Status colours (`success`, `warning`, `destructive`) must never double as category colours.
92
+ - **Composite focus (built: `focus-box`).** A documented class or token for "the box around a bare field shows the focus ring" (`focus-within`), so apps stop working around inline styles.
93
+ - **Size floors.** Checks 24px, phone touch targets 44px, no text under 12px. New components follow them; existing avatar initials and `kbd` are still 11px.
94
+ - **Brand mark slot.** AppNav (`brand`) and AuthLayout (`brand`) take the product mark as a prop.
95
+ - **Design canvas loading.** The design system artifact's README names `window.HarebearUI` but not which files to load on a Design canvas, so designs copy components as markup. Add a "Consuming this system" section listing the bundle and stylesheet.
@@ -0,0 +1,75 @@
1
+ # Working with AI agents
2
+
3
+ harebear-ui is built to be used by coding agents (Claude Code, Codex, Cursor, Copilot and the like). The package ships its own instructions, so an agent in your repo knows which components exist, how to style them, and how to check its work, without you pasting docs into the prompt.
4
+
5
+ ![What init sets up for your agent](../../.github/assets/agents.webp)
6
+
7
+ ## What ships in the package
8
+
9
+ | File (in `node_modules/harebear-ui/`) | What it is |
10
+ | ------------------------------------- | --------------------------------------------------------------------------------------------- |
11
+ | `llms.txt` | Short index: setup, the styling rules, every export by group. Small enough to paste anywhere. |
12
+ | `docs/COMPONENTS.md` | The catalog: every export with props, variants and examples. A test keeps it complete. |
13
+ | `docs/guides/` | These guides: setup per framework, theming, agents. |
14
+ | `skills/harebear-ui/SKILL.md` | A Claude Code skill that loads whenever the agent builds or changes UI. |
15
+ | `AGENTS.md` | Instructions for agents working on harebear-ui itself (not needed in your app). |
16
+
17
+ ## Set up your repo
18
+
19
+ ```bash
20
+ npx harebear-ui init
21
+ ```
22
+
23
+ This writes two things your agent reads automatically:
24
+
25
+ 1. **A harebear-ui section in `AGENTS.md`** (or in `CLAUDE.md` if that file exists and `AGENTS.md` does not). It points at the catalog and states the rules: import from the package root, tokens only, check light and dark mode and phone width. The section sits between `<!-- harebear-ui:start -->` and `<!-- harebear-ui:end -->` markers, and running `init` again after an upgrade replaces it in place.
26
+ 2. **A Claude Code skill** at `.claude/skills/harebear-ui/SKILL.md`. Claude Code loads it on UI tasks; it adds the composition rules (which composite to use for which screen) and the visual checks.
27
+
28
+ Commit both. Re-run `npx harebear-ui init` after upgrading harebear-ui to refresh them.
29
+
30
+ ### Per tool
31
+
32
+ | Tool | What it reads |
33
+ | ------------- | -------------------------------------------------------------------------------------------------------------------- |
34
+ | Claude Code | `CLAUDE.md` and `.claude/skills/`. If your instructions live in `AGENTS.md`, add a line `@AGENTS.md` to `CLAUDE.md`. |
35
+ | Codex, Cursor | `AGENTS.md`. See [agents.md](https://agents.md) for the tools that follow the convention. |
36
+ | Anything else | Point it at `node_modules/harebear-ui/llms.txt` in your own instructions file. |
37
+
38
+ ## Look things up instead of reading everything
39
+
40
+ The full catalog is long. Agents (and you) can pull just the entries a task needs:
41
+
42
+ ```bash
43
+ npx harebear-ui docs DataTable # one export
44
+ npx harebear-ui docs DataTable StatCard # several
45
+ npx harebear-ui docs Prompt # every export starting with "Prompt"
46
+ npx harebear-ui docs Tokens # a whole section: Theme, Tokens, Auth, "AI and chat", ...
47
+ npx harebear-ui docs # everything
48
+ ```
49
+
50
+ A lookup prints the matching `###` sections, or the primitive's table row with its header. It exits with status 1 when nothing matches, so an agent notices a wrong name instead of guessing.
51
+
52
+ ## Prompts that work well
53
+
54
+ The instructions already cover style rules, so prompts can stay about the product:
55
+
56
+ - "Build a settings page with a profile card, a notifications card with switches, and a danger zone with a delete-account ConfirmDialog."
57
+ - "Turn `orders.json` into an orders screen: DataTable with status badges, a detail panel when a row is clicked, and a KPI row above it."
58
+ - "Make a chat UI for our support bot with a conversation list, tool calls shown as ToolSteps and approval prompts for refunds."
59
+ - "Start from the admin reference screen and adapt it to our metrics endpoint."
60
+
61
+ Pointing at a reference screen is the fastest way to a good result. The playground has six, built only from public exports: [`playground/screens/`](https://github.com/HMilbradt/harebear-ui/tree/main/playground/screens) (admin dashboard, AI chat, agent with approvals, records table with detail panel, status home, auth).
62
+
63
+ ## Review what the agent built
64
+
65
+ Things to check before you accept a UI change:
66
+
67
+ - **Both modes.** Toggle light and dark. Anything that only works in one used a palette color instead of a token.
68
+ - **Phone width.** At 375px rows wrap, tables scroll inside their card, and the sidebar becomes a sheet.
69
+ - **No forks.** The agent imported from `harebear-ui` rather than copying component source into the app.
70
+ - **No color overrides.** `className` on harebear components is for layout. A `bg-*` or `text-*` color override on a library component means the agent hit a gap; ask it to report the gap instead.
71
+ - **Accessible icons.** Icon-only buttons have an `aria-label`.
72
+
73
+ ## Working on harebear-ui itself
74
+
75
+ Agents contributing to this repo should read [AGENTS.md](../../AGENTS.md) at the repo root. It covers the layout, the conventions for new components, the checks (`pnpm check`), and how to regenerate the README images (`pnpm shots`).