harebear-ui 0.8.0 → 0.9.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.
- package/AGENTS.md +2 -2
- package/dist/components/admin/app-nav.d.ts +4 -0
- package/dist/components/admin/app-nav.js +5 -2
- package/dist/components/admin/avatar-upload.d.ts +32 -0
- package/dist/components/admin/avatar-upload.js +121 -0
- package/dist/components/admin/category.d.ts +17 -0
- package/dist/components/admin/category.js +35 -0
- package/dist/components/admin/celebration.d.ts +7 -0
- package/dist/components/admin/celebration.js +61 -0
- package/dist/components/admin/color-swatch-picker.d.ts +15 -0
- package/dist/components/admin/color-swatch-picker.js +68 -0
- package/dist/components/admin/date-time-picker.d.ts +20 -0
- package/dist/components/admin/date-time-picker.js +97 -0
- package/dist/components/admin/detail-sheet.d.ts +18 -0
- package/dist/components/admin/detail-sheet.js +80 -0
- package/dist/components/admin/markdown-editor.d.ts +15 -0
- package/dist/components/admin/markdown-editor.js +42 -0
- package/dist/components/admin/user-chip.d.ts +34 -3
- package/dist/components/admin/user-chip.js +66 -7
- package/dist/components/admin/user-menu.d.ts +4 -1
- package/dist/components/admin/user-menu.js +2 -1
- package/dist/components/ai/ask-box.d.ts +14 -2
- package/dist/components/ai/ask-box.js +90 -54
- package/dist/components/ai/assistant.d.ts +13 -3
- package/dist/components/ai/assistant.js +37 -7
- package/dist/components/ai/code-block.d.ts +10 -3
- package/dist/components/ai/code-block.js +54 -5
- package/dist/components/ai/conversation-list.d.ts +13 -3
- package/dist/components/ai/conversation-list.js +15 -26
- package/dist/components/auth/auth.js +4 -6
- package/dist/components/data/agenda-row.d.ts +26 -0
- package/dist/components/data/agenda-row.js +62 -0
- package/dist/components/data/day-strip.d.ts +22 -0
- package/dist/components/data/day-strip.js +68 -0
- package/dist/components/data/sectioned-list.d.ts +21 -6
- package/dist/components/data/sectioned-list.js +44 -21
- package/dist/components/data/task-row.d.ts +3 -0
- package/dist/components/data/task-row.js +6 -14
- package/dist/components/ui/avatar.js +1 -1
- package/dist/components/ui/kbd.js +1 -1
- package/dist/components/ui/password-input.d.ts +8 -0
- package/dist/components/ui/password-input.js +32 -0
- package/dist/index.d.ts +15 -5
- package/dist/index.js +13 -3
- package/dist/lib/date.js +8 -0
- package/dist/lib/toast-clearance.js +22 -0
- package/dist/styles.css +48 -0
- package/docs/COMPONENTS.md +165 -15
- package/docs/ROADMAP.md +12 -11
- package/llms.txt +8 -7
- package/package.json +1 -1
- package/skills/harebear-ui/SKILL.md +2 -1
package/docs/COMPONENTS.md
CHANGED
|
@@ -40,10 +40,12 @@ A household or personal app where an assistant sits on every page and safe actio
|
|
|
40
40
|
</ThemeProvider>
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
- Lists: `SectionedList` (`TaskRow` rows); when the agent or a bulk action changes data, confirm with `toastUndo
|
|
43
|
+
- Lists: `SectionedList` (`TaskRow` rows); when the agent or a bulk action changes data, confirm with `toastUndo` and set `lingerMs` to its window so a ticked row stays struck through for about as long as Undo shows.
|
|
44
|
+
- A week agenda: `DayStrip` above one `SectionedList` with a section per day (`empty` keeps empty days) and `AgendaRow` rows from `renderItem`.
|
|
44
45
|
- In the assistant thread, each action it took is an `ActionReceipt` with Undo (append it from `onSend`).
|
|
46
|
+
- A page with its own ask box (Today) answers under it: `AskBox` with `reply` and `pending` from `useAssistant()`, `onStop={stop}`, and `send(text, { open: false })`.
|
|
45
47
|
- 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.
|
|
48
|
+
- Members, lists and calendars take a `category-1..6` color (`CategoryColor`); status colors never double as categories. People are `MemberAvatar` (`AvatarStack`, `VisibilityBadge`), list dots are `CategoryDot`, profile settings use `AvatarUpload` and `ColorSwatchPicker`.
|
|
47
49
|
- Live example: `playground/screens/household.tsx` (`#household`) and `settings.tsx` (`#settings`).
|
|
48
50
|
|
|
49
51
|
## Theme
|
|
@@ -75,7 +77,7 @@ Every component in the shadcn registry is included. (shadcn's `form` item is an
|
|
|
75
77
|
| Alert dialog | `AlertDialog`, `AlertDialogTrigger`, `AlertDialogContent`, `AlertDialogHeader`, `AlertDialogFooter`, `AlertDialogTitle`, `AlertDialogDescription`, `AlertDialogAction`, `AlertDialogCancel`, `AlertDialogMedia`, `AlertDialogOverlay`, `AlertDialogPortal` | Use for destructive confirmations. |
|
|
76
78
|
| Aspect ratio | `AspectRatio` | |
|
|
77
79
|
| Attachment | `Attachment`, `AttachmentGroup`, `AttachmentMedia`, `AttachmentContent`, `AttachmentTitle`, `AttachmentDescription`, `AttachmentActions`, `AttachmentAction`, `AttachmentTrigger` | File/image chips on messages and composers. `size`: `default`, `sm`, `xs`; `orientation`: `horizontal`, `vertical`. |
|
|
78
|
-
| Avatar | `Avatar`, `AvatarImage`, `AvatarFallback`, `AvatarGroup`, `AvatarGroupCount`, `AvatarBadge` | `size`: `sm` 28px, `default` 36px, `lg` 56px. Fallback is tinted initials
|
|
80
|
+
| Avatar | `Avatar`, `AvatarImage`, `AvatarFallback`, `AvatarGroup`, `AvatarGroupCount`, `AvatarBadge` | `size`: `sm` 28px, `default` 36px, `lg` 56px. Fallback is tinted initials, 12px at `sm`. For people use `MemberAvatar`. |
|
|
79
81
|
| Badge | `Badge`, `badgeVariants` | 24px pill. `variant`: `default` (primary), `secondary` (neutral, the common one), `soft` (tinted primary), `outline`, `success`, `warning`, `destructive`, `ghost`, `link`. harebear adds `size="lg"` (32px, lines up with sm buttons) and `tone` (`success \| warning \| danger \| info \| neutral`, the StatusBadge words; wins over `variant`). |
|
|
80
82
|
| Bubble | `Bubble`, `BubbleGroup`, `BubbleContent`, `BubbleReactions` | Chat bubble. `variant`: `default` (primary), `secondary`, `muted`, `tinted`, `outline`, `ghost`, `destructive`; `align`: `start`, `end`. |
|
|
81
83
|
| Breadcrumb | `Breadcrumb`, `BreadcrumbList`, `BreadcrumbItem`, `BreadcrumbLink`, `BreadcrumbPage`, `BreadcrumbSeparator`, `BreadcrumbEllipsis` | |
|
|
@@ -103,7 +105,7 @@ Every component in the shadcn registry is included. (shadcn's `form` item is an
|
|
|
103
105
|
| Input group | `InputGroup`, `InputGroupAddon`, `InputGroupButton`, `InputGroupText`, `InputGroupInput`, `InputGroupTextarea` | Inputs with icons, prefixes, buttons. |
|
|
104
106
|
| Input OTP | `InputOTP`, `InputOTPGroup`, `InputOTPSlot`, `InputOTPSeparator` | |
|
|
105
107
|
| Item | `Item`, `ItemMedia`, `ItemContent`, `ItemTitle`, `ItemDescription`, `ItemActions`, `ItemGroup`, `ItemSeparator`, `ItemHeader`, `ItemFooter` | Generic list rows. harebear fix: `ItemTitle` clamps to one line (long words break) and shows the full text as a tooltip when clamped, `ItemContent` has `min-w-0`. harebear adds `ItemTitle mono` for commands, paths and IDs. |
|
|
106
|
-
| Kbd | `Kbd`, `KbdGroup` | Mono keycap.
|
|
108
|
+
| Kbd | `Kbd`, `KbdGroup` | Mono keycap, 12px text. |
|
|
107
109
|
| Marker | `Marker`, `MarkerIcon`, `MarkerContent`, `markerVariants` | Inline status line in a thread ("Conversation saved"). `variant`: `default`, `separator` (date dividers), `border`. |
|
|
108
110
|
| Label | `Label` | |
|
|
109
111
|
| Menubar | `Menubar`, `MenubarMenu`, `MenubarTrigger`, `MenubarContent`, `MenubarItem`, `MenubarCheckboxItem`, `MenubarRadioGroup`, `MenubarRadioItem`, `MenubarLabel`, `MenubarSeparator`, `MenubarShortcut`, `MenubarGroup`, `MenubarPortal`, `MenubarSub`, `MenubarSubTrigger`, `MenubarSubContent` | |
|
|
@@ -242,11 +244,11 @@ Label-over-value pairs as a `<dl>`. Props: `items: { label; value }[]`, `columns
|
|
|
242
244
|
|
|
243
245
|
### `UserChip`
|
|
244
246
|
|
|
245
|
-
Avatar + name + subtitle. Props: `name`, `subtitle?`, `avatarUrl?`, `action?`, `size?`. In a sidebar icon rail only the avatar shows. Also exports `initials(name)`.
|
|
247
|
+
Avatar + name + subtitle. Props: `name`, `subtitle?`, `avatarUrl?`, `color?` (`CategoryColor` behind the initials), `action?`, `size?`. In a sidebar icon rail only the avatar shows. Also exports `initials(name)`.
|
|
246
248
|
|
|
247
249
|
### `UserMenu`
|
|
248
250
|
|
|
249
|
-
The signed-in user as a menu button (sidebar footer or top bar). The menu has a header, your items (`children`, e.g. a Settings `DropdownMenuItem`), a Light / Dark / System theme choice, and Sign out. In a sidebar icon rail the trigger is just the avatar and the menu opens to the side. Props: `name`, `subtitle?`, `avatarUrl?`, `children?`, `themeSwitch?` (default true, needs `ThemeProvider`), `onSignOut?`, `signOutLabel?`.
|
|
251
|
+
The signed-in user as a menu button (sidebar footer or top bar). The menu has a header, your items (`children`, e.g. a Settings `DropdownMenuItem`), a Light / Dark / System theme choice, and Sign out. In a sidebar icon rail the trigger is just the avatar and the menu opens to the side. Props: `name`, `subtitle?`, `avatarUrl?`, `color?` (`CategoryColor` behind the initials), `children?`, `themeSwitch?` (default true, needs `ThemeProvider`), `onSignOut?`, `signOutLabel?`.
|
|
250
252
|
|
|
251
253
|
```tsx
|
|
252
254
|
;<UserMenu name={email} subtitle="Signed in" onSignOut={signOut}>
|
|
@@ -257,6 +259,50 @@ The signed-in user as a menu button (sidebar footer or top bar). The menu has a
|
|
|
257
259
|
</UserMenu>
|
|
258
260
|
```
|
|
259
261
|
|
|
262
|
+
### `MemberAvatar`
|
|
263
|
+
|
|
264
|
+
A person's photo, or their initials on their category colour (`bg-category-N`, `text-category-foreground`). Props: `name`, `avatarUrl?`, `color?: CategoryColor` (1 to 6; without it the soft primary tint), `size?` (`sm` 28px, `default` 36px, `lg` 56px). It is `role="img"` named after the person; pass `aria-hidden` when the name is shown next to it. Used by `UserChip`, `UserMenu` and `TaskRow`.
|
|
265
|
+
|
|
266
|
+
```tsx
|
|
267
|
+
;<MemberAvatar name="Sam Rivera" avatarUrl={sam.photoUrl ?? undefined} color={sam.color} size="sm" />
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
### `AvatarStack`, `VisibilityBadge`
|
|
271
|
+
|
|
272
|
+
`AvatarStack`: overlapping small `MemberAvatar`s. Props: `members: { name; avatarUrl?; color? }[]`, `max?` (default 4): total slots; past it, `max - 1` faces and a "+N" chip (read as "N more"). `VisibilityBadge`: who can see something. Props: `visibility: "shared" | "private"`, `members?` (faces when shared), `label?` (default "Shared with everyone" or "Only you"; the lock shows when private).
|
|
273
|
+
|
|
274
|
+
```tsx
|
|
275
|
+
;<VisibilityBadge visibility={list.private ? "private" : "shared"} members={household} />
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
### `CategoryDot`
|
|
279
|
+
|
|
280
|
+
A 10px dot in a category colour, e.g. as the `icon` of a list in `AppNav`'s group. Props: `color: CategoryColor`, `label?` (accessible name when the colour means something on its own, e.g. whose event; decorative without it), `locked?` (adds a lock named `lockLabel?`, default "Only you").
|
|
281
|
+
|
|
282
|
+
### `ColorSwatchPicker`
|
|
283
|
+
|
|
284
|
+
The six category colours as a radio group (arrow keys skip taken ones). 32px swatches with 44px touch targets; the chosen one has a check and a ring. Props: `value?: CategoryColor`, `onValueChange?(color)`, `taken?: Partial<Record<CategoryColor, string>>` (colour to who has it: shown with their initial, disabled, named "Violet, taken by Riley"). Name it with `aria-label` or `aria-labelledby`.
|
|
285
|
+
|
|
286
|
+
```tsx
|
|
287
|
+
;<ColorSwatchPicker aria-label="Your colour" value={me.color} onValueChange={setColor} taken={{ 3: "Riley" }} />
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### `AvatarUpload`, `cropImageToSquare`
|
|
291
|
+
|
|
292
|
+
Profile photo: a 72px avatar, "Upload a photo" / "Change photo" and "Remove photo". The chosen image is cropped to its centred square at 256x256 in the browser (canvas, JPEG) and previewed at once. Props: `name`, `color?`, `avatarUrl?` (current photo), `onChange(photo: Blob | null)` (an event, not a controlled value) (`null` after Remove), `maxBytes?` (JPEG quality steps down to fit), `onError?(error)` ("Could not read that image." or "That photo is too big."), `description?`. `cropImageToSquare(file, { size?, maxBytes? })` is the crop on its own: a `Promise<Blob>`.
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
;<AvatarUpload
|
|
296
|
+
name={me.name}
|
|
297
|
+
color={me.color}
|
|
298
|
+
avatarUrl={me.photoUrl ?? undefined}
|
|
299
|
+
maxBytes={512 * 1024}
|
|
300
|
+
onChange={(photo) => (photo ? uploadPhoto(photo) : removePhoto())}
|
|
301
|
+
onError={(e) => toast.error(e.message)}
|
|
302
|
+
description="Without a photo, your initial and colour are used."
|
|
303
|
+
/>
|
|
304
|
+
```
|
|
305
|
+
|
|
260
306
|
### `ConfirmDialog`
|
|
261
307
|
|
|
262
308
|
Controlled "are you sure" dialog. Props: `open`, `onOpenChange`, `title`, `description?`, `confirmLabel?`, `cancelLabel?`, `destructive?` (red confirm), `onConfirm`.
|
|
@@ -265,20 +311,63 @@ Controlled "are you sure" dialog. Props: `open`, `onOpenChange`, `title`, `descr
|
|
|
265
311
|
|
|
266
312
|
Read-only value with a copy button (IDs, paths, URLs). Props: `value` (copied), `display?` (shown instead, full value as tooltip), `label?` (leading addon), `aria-label?`, `mono?` (default true).
|
|
267
313
|
|
|
314
|
+
### `DateTimePicker`
|
|
315
|
+
|
|
316
|
+
Date field: a button that opens a `Calendar` in a `Popover`, with an optional time field and a Clear button. Value is a floating local date, no time zone: `DateTimeValue = { date: "YYYY-MM-DD", time?: "HH:MM" }`. Props: `value: DateTimeValue | null`, `onValueChange(value | null)`, `withTime?` (time field under the calendar; enabled once a date is set), `placeholder?` (default "Pick a date"). Other props (`id`, `aria-label`, `disabled`) go to the trigger button. Day cells are 44px on phones.
|
|
317
|
+
|
|
318
|
+
### `DetailSheet`
|
|
319
|
+
|
|
320
|
+
A record's details, one API for both sizes: a floating side sheet from 768px up, a full-screen drawer with a close button on phones. Props: `open`, `onOpenChange`, `title` (heading and accessible name), `description?`, `footer?` (pinned under the scrolling body, e.g. Delete), `children` (the fields). `data-layout` is `"sheet"` or `"drawer"`.
|
|
321
|
+
|
|
322
|
+
```tsx
|
|
323
|
+
;<DetailSheet
|
|
324
|
+
open={!!task}
|
|
325
|
+
onOpenChange={(o) => !o && close()}
|
|
326
|
+
title="To-do"
|
|
327
|
+
footer={
|
|
328
|
+
<Button variant="ghost" onClick={askDelete}>
|
|
329
|
+
Delete
|
|
330
|
+
</Button>
|
|
331
|
+
}
|
|
332
|
+
>
|
|
333
|
+
<Field>
|
|
334
|
+
<FieldLabel htmlFor="when">When</FieldLabel>
|
|
335
|
+
<DateTimePicker id="when" withTime value={due} onValueChange={setDue} />
|
|
336
|
+
</Field>
|
|
337
|
+
</DetailSheet>
|
|
338
|
+
```
|
|
339
|
+
|
|
268
340
|
### `Callout`
|
|
269
341
|
|
|
270
342
|
Quiet note with an icon (sparkle by default). Props: `icon?`, `tone?` (`"muted" | "soft"`).
|
|
271
343
|
|
|
344
|
+
### `Celebration`, `celebrate`
|
|
345
|
+
|
|
346
|
+
An occasional confetti burst, e.g. when the last to-do of the day is ticked. Mount `<Celebration />` once near the root (like `Toaster`), then call `celebrate()` from anywhere. CSS only, about 1.5 s, renders nothing between bursts (`data-slot="celebration"` while it plays), and does nothing under `prefers-reduced-motion`. Keep it rare.
|
|
347
|
+
|
|
272
348
|
### `LinkTile`
|
|
273
349
|
|
|
274
350
|
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.
|
|
275
351
|
|
|
352
|
+
### `MarkdownEditor`
|
|
353
|
+
|
|
354
|
+
Markdown field with Write and Preview tabs; Preview renders inside `Prose`. Props: `value`, `onValueChange(value)`, `renderPreview(markdown)` (the library has no Markdown parser; pass yours), `wrapperClassName?`. Other props (`id`, `placeholder`, `aria-*`, `className`) go to the `Textarea`.
|
|
355
|
+
|
|
356
|
+
```tsx
|
|
357
|
+
;<MarkdownEditor
|
|
358
|
+
id="body"
|
|
359
|
+
value={body}
|
|
360
|
+
onValueChange={setBody}
|
|
361
|
+
renderPreview={(md) => <Markdown components={{ blockquote: ProseBlockquote }}>{md}</Markdown>}
|
|
362
|
+
/>
|
|
363
|
+
```
|
|
364
|
+
|
|
276
365
|
### `AppNav`
|
|
277
366
|
|
|
278
367
|
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
368
|
|
|
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 }
|
|
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
|
|
369
|
+
Props: `places: AppNavPlace[]` (`label`, `icon?`, `href?` or `onSelect?`, `active?`, `count?`, `tab?: false` to keep out of the tab bar, `sidebar?: false` for a tab-bar-only place such as Lists when the sidebar has a Lists group), `group?: AppNavGroup` (`label`, `items`, `defaultOpen?`, `onAdd?`, `addLabel?`), `action?: { label; icon; onSelect; sidebar?: false }` (`sidebar: false` keeps only the round phone button), `brand?`, `footer?` (usually `UserMenu`), `label?` (nav name, default "Main"), `linkComponent?`, `collapsible?`, `storageKey?`, `defaultOpen?`, `width?`, `children`.
|
|
370
|
+
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. Toasts stack above the tab bar, the action button and the dock launcher on their own; no `Toaster` offset needed.
|
|
282
371
|
|
|
283
372
|
### `FocusLayout`
|
|
284
373
|
|
|
@@ -385,11 +474,16 @@ Mini bar history (pings, uptime). Props: `data: (number | { value; tone?; label?
|
|
|
385
474
|
|
|
386
475
|
### `TaskRow`
|
|
387
476
|
|
|
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? }
|
|
477
|
+
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?; color? }` (a `MemberAvatar`), `important?` (say it in `meta` too), `onOpen?` (title becomes a button, e.g. to open a sheet), `disabled?`.
|
|
389
478
|
|
|
390
479
|
### `SectionedList`
|
|
391
480
|
|
|
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
|
|
481
|
+
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 struck through for `lingerMs`, then folds away with `Collapse`. Props: `sections: { id; title?; action?; empty?; items: SectionedListItem[] }[]` (item: `id`, `title`, `meta?`, `done?`, `important?`, `assignee?`), `onToggle(id, done)`, `lingerMs?` (default 600; 9000 matches `toastUndo`), `renderItem?(item, toggle)`, `onAdd?(text)`, `addPlaceholder?` (default "Add a to-do"), `addChips?(text)`, `onOpen?(id)`, `empty?`, `defaultShowDone?`.
|
|
482
|
+
|
|
483
|
+
- Section `id` is also the `<section>`'s DOM id, so `DayStrip` or an `#id` link can jump to it. Keep ids unique on the page.
|
|
484
|
+
- `action` sits at the right of the heading (a small ghost `Button`, e.g. "Move to today"; stretched to 44px on phones). `empty` keeps the section shown with that text when nothing in it is open ("Nothing planned").
|
|
485
|
+
- `renderItem` draws other rows, e.g. `AgendaRow`. Its `toggle(done)` lingers and folds the row like a `TaskRow`. Items without `done` (events) always stay. Type the items with `SectionedList<MyItem>`.
|
|
486
|
+
- `addChips(text)` returns chips shown at the right of the add box while it has text, like `AskBox` `chips` (the date or person parsed from the text).
|
|
393
487
|
|
|
394
488
|
```tsx
|
|
395
489
|
;<SectionedList
|
|
@@ -400,6 +494,38 @@ A to-do list: one add box at the top, sections with headings, done items folded
|
|
|
400
494
|
/>
|
|
401
495
|
```
|
|
402
496
|
|
|
497
|
+
### `AgendaRow`
|
|
498
|
+
|
|
499
|
+
One line of a day's agenda: time column, event icon (or a `CheckCircle` for a to-do), title, one meta line, whose dot and name. Props: `title`, `time?` ("3:15", "All day"), `meta?`, `who?: { name; color: CategoryColor }` (`CategoryDot` before the name), `checked?` + `onCheckedChange?(checked)` (draws the check instead of the icon), `important?`, `onOpen?` (title becomes a button, e.g. to open an event dialog).
|
|
500
|
+
|
|
501
|
+
### `DayStrip`
|
|
502
|
+
|
|
503
|
+
A row of day links (short weekday, date, a dot when `hasPlans`) that smooth-scroll to the element whose id is the day's `id` (instant under reduced motion) and move focus to it; scrolls sideways when the days do not fit. Props: `days: { id; date: "YYYY-MM-DD"; hasPlans? }[]` (floating local date, like `DateTimePicker`), `value?` (selected id, `aria-current`), `onValueChange?(id)`, `aria-label?` (default "Jump to a day"). Make it sticky with `className="sticky top-0 bg-background"` and give the scroll container `scroll-padding-top` so headings land below it.
|
|
504
|
+
|
|
505
|
+
```tsx
|
|
506
|
+
;<>
|
|
507
|
+
<DayStrip
|
|
508
|
+
days={week.map((d) => ({ id: d.key, date: d.date, hasPlans: d.items.length > 0 }))}
|
|
509
|
+
value={day}
|
|
510
|
+
onValueChange={setDay}
|
|
511
|
+
/>
|
|
512
|
+
<SectionedList<WeekItem>
|
|
513
|
+
lingerMs={9000}
|
|
514
|
+
sections={week.map((d) => ({ id: d.key, title: d.label, empty: "Nothing planned", items: d.items }))}
|
|
515
|
+
onToggle={setDone}
|
|
516
|
+
renderItem={(i, toggle) => (
|
|
517
|
+
<AgendaRow
|
|
518
|
+
time={i.time}
|
|
519
|
+
title={i.title}
|
|
520
|
+
who={i.who}
|
|
521
|
+
{...(i.kind === "todo" && { checked: !!i.done, onCheckedChange: toggle })}
|
|
522
|
+
onOpen={() => open(i)}
|
|
523
|
+
/>
|
|
524
|
+
)}
|
|
525
|
+
/>
|
|
526
|
+
</>
|
|
527
|
+
```
|
|
528
|
+
|
|
403
529
|
## AI and chat
|
|
404
530
|
|
|
405
531
|
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`.
|
|
@@ -495,7 +621,7 @@ Pill showing the active model with a status dot, opening a menu. Props: `models:
|
|
|
495
621
|
Grouped thread list. Props: `groups: { label; items: Conversation[] }[]`, `activeId?`, `onSelect?(id)`, `onDelete?(conversation)` (adds a delete button per row that confirms first; `deleteDescription?` is the confirmation body), `renderAction?(conversation)` (any other trailing control; wins over `onDelete`; on desktop it shows on hover/focus), `empty?`.
|
|
496
622
|
`Conversation = { id; title; description?; tone?; pulse?; deleteDisabled? }`: `description` is the second line (time, or a live state with a `tone` dot); `deleteDisabled` blocks delete for that row (a string is the reason, shown as the tooltip).
|
|
497
623
|
Inside a `Sidebar` it closes the mobile sheet on select and hides in the icon rail.
|
|
498
|
-
`groupByDate(items, getDate, toConversation,
|
|
624
|
+
`groupByDate(items, getDate, toConversation, options?)` buckets items into Today / Yesterday / Previous 7 days / Earlier, newest first. `options` is `{ now?, buckets? }` (or just `now`); `buckets: "week"` gives Today / This week (the 6 days before today) / Earlier.
|
|
499
625
|
`formatWhen(date, now?, locale?)`: short timestamp for rows and headers: the time today ("9:41 AM"), the date this year ("Nov 3"), else with the year.
|
|
500
626
|
|
|
501
627
|
### `NewConversationButton`
|
|
@@ -530,15 +656,32 @@ Agent tool calls as a bordered, collapsible card. `ToolStatus = "queued" | "wait
|
|
|
530
656
|
|
|
531
657
|
### `AssistantProvider`, `useAssistant`, `useAssistantPage`
|
|
532
658
|
|
|
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.
|
|
659
|
+
One assistant conversation across pages. `AssistantProvider` props: `onSend(text, { page, messages, append, update, signal })` (return the reply, or `append`/`update` messages yourself for streaming and receipts; a thrown error becomes the reply; `signal` aborts when the user presses Stop, so pass it to `fetch` or listen for `abort` to tell your server), `initialMessages?`, `defaultOpen?`. `useAssistant()` returns `{ open, setOpen, toggle, messages, pending, reply, page, setPage, send, stop, append, update, clear }`: `send(text, { open: false }?)` skips opening the dock, `stop()` aborts the running send, ends `pending` and drops its late reply, `reply` is the assistant messages after the latest user message (null until there is one), for `AskBox`. A page calls `useAssistantPage({ id, title?, data?, suggestions? })` to become the context while mounted.
|
|
534
660
|
|
|
535
661
|
### `AssistantDock`
|
|
536
662
|
|
|
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
|
|
663
|
+
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` (Stop while the assistant works, wired to `useAssistant().stop`). 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
664
|
|
|
539
665
|
### `AskBox`
|
|
540
666
|
|
|
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
|
|
667
|
+
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?`, `pending?` (blocks sending; with `onStop?` the send button becomes Stop), `reply?` (the answer under the box; passing it, even `null`, shows "Working" while `pending`), `chatHref?` (an "Open chat" link under the reply).
|
|
668
|
+
|
|
669
|
+
```tsx
|
|
670
|
+
// Inline answer under the box (no dock), e.g. a Today page
|
|
671
|
+
const { send, pending, stop, reply } = useAssistant()
|
|
672
|
+
;<AskBox
|
|
673
|
+
value={text}
|
|
674
|
+
onValueChange={setText}
|
|
675
|
+
onSubmit={(t) => {
|
|
676
|
+
setText("")
|
|
677
|
+
send(t, { open: false })
|
|
678
|
+
}}
|
|
679
|
+
pending={pending}
|
|
680
|
+
onStop={stop}
|
|
681
|
+
reply={reply}
|
|
682
|
+
chatHref={`/chat/${conversationId}`}
|
|
683
|
+
/>
|
|
684
|
+
```
|
|
542
685
|
|
|
543
686
|
### `DictationButton`, `useDictation`, `browserSpeechSource`
|
|
544
687
|
|
|
@@ -549,11 +692,12 @@ Large rounded composer: auto-growing text, `chips` shown while there is text, su
|
|
|
549
692
|
|
|
550
693
|
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
694
|
|
|
552
|
-
### `CodeSnippet`, `InlineCode`, `Prose`
|
|
695
|
+
### `CodeSnippet`, `InlineCode`, `Prose`, `ProseBlockquote`
|
|
553
696
|
|
|
554
697
|
`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.
|
|
555
698
|
`InlineCode`: monospace span. `truncate?: number` cuts longer string children with an ellipsis and puts the full text in the tooltip.
|
|
556
699
|
`Prose`: typography for model output and markdown. Styles plain `p, ul, ol, li, strong, a, code, pre, h1-h4, blockquote, table` children, so it works with `react-markdown`.
|
|
700
|
+
Tip boxes: a blockquote whose first word is `Tip:` (`> Tip: Turn the power off first.`) renders as a `Callout` without the word. Prose does this for plain `<blockquote>` children; with react-markdown pass `components={{ blockquote: ProseBlockquote }}`.
|
|
557
701
|
|
|
558
702
|
### Chat primitives vs. composites
|
|
559
703
|
|
|
@@ -571,6 +715,10 @@ Full-page wrapper. Props: `variant` (`"centered"` card on the page, `"muted"` sa
|
|
|
571
715
|
|
|
572
716
|
Props: `onSubmit?({ email, password? })` (omit to submit natively to an `action`), `mode?` (`"password"` or `"email-only"` for magic links), `providers?: { id; label; icon? }[]` + `onProviderClick?(id)` (3+ providers with icons collapse to an icon row), `providersFirst?`, `forgotPasswordHref?`, `signupHref?`, `title?`, `description?`, `submitLabel?`, `loading?`, `error?`.
|
|
573
717
|
|
|
718
|
+
### `PasswordInput`
|
|
719
|
+
|
|
720
|
+
Password `Input` with a Show/Hide button (`aria-label` "Show password" / "Hide password") that switches `type` between `password` and `text`. Input props go to the input; `wrapperClassName?` styles the wrapper. `LoginForm` and `SignupForm` use it for every password field.
|
|
721
|
+
|
|
574
722
|
### `SignupForm`
|
|
575
723
|
|
|
576
724
|
Props: `onSubmit?({ name?, email, password })`, `nameField?` (default true), `confirmPassword?` (default true; mismatches are blocked with a browser validation message), `minPasswordLength?` (default 8), `passwordHint?`, `providers?`, `onProviderClick?`, `providersFirst?`, `loginHref?`, `title?`, `description?`, `submitLabel?`, `loading?`, `error?`.
|
|
@@ -605,6 +753,7 @@ Props: `onSubmit?({ name?, email, password })`, `nameField?` (default true), `co
|
|
|
605
753
|
| `useIsMobile()` | `true` under 768px. |
|
|
606
754
|
| `useAssistant()`, `useAssistantPage(page)`, `useDictation(options)` | See [`AssistantProvider`](#assistantprovider-useassistant-useassistantpage) and [`DictationButton`](#dictationbutton-usedictation-browserspeechsource). |
|
|
607
755
|
| `useMediaQuery(query)` | `true` while the media query matches; `false` during SSR. |
|
|
756
|
+
| `categoryBg[color]`, type `CategoryColor` | `bg-category-N` class for a colour `1..6`, as a complete class name. |
|
|
608
757
|
| `cn(...classes)` | clsx + tailwind-merge. Use for every `className` you compose. |
|
|
609
758
|
|
|
610
759
|
## Tokens
|
|
@@ -623,6 +772,7 @@ Use these as Tailwind utilities (`bg-*`, `text-*`, `border-*`, `ring-*`, `fill-*
|
|
|
623
772
|
| `border`, `input`, `ring` | Hairlines, input borders, focus rings. |
|
|
624
773
|
| `chart-1` … `chart-5`, `chart-grid` | Data series and gridlines. |
|
|
625
774
|
| `category-1` … `category-6` | Members, lists, calendars: blue, teal, violet, rose, slate, cyan, each with a dark value. Never status. |
|
|
775
|
+
| `category-foreground` | Text and icons on a category fill (initials, a swatch's check). |
|
|
626
776
|
| `sidebar-*` | Sidebar surfaces (default to the page tokens). |
|
|
627
777
|
|
|
628
778
|
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`.
|
package/docs/ROADMAP.md
CHANGED
|
@@ -34,7 +34,7 @@ Calendar views and SmartInput follow when a second app needs them.
|
|
|
34
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
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
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
|
|
37
|
+
| DetailSheet (built) | 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
38
|
| ReaderLayout | Back link, title, author and updated line, actions at the top (Edit, Chat with HomeBot), then Prose. | Docs, help, notes. |
|
|
39
39
|
| PageColumn | Centred column with a standard header slot (greeting or title, filter, primary input). | Today, Upcoming, list pages. |
|
|
40
40
|
| AuthLayout, single card variant | Calm centred card with the product mark, for sign in, invite and first-run setup. | Extends AuthLayout. |
|
|
@@ -62,21 +62,22 @@ Calendar views and SmartInput follow when a second app needs them.
|
|
|
62
62
|
| TaskRow (built) | Check, title, one meta line, optional assignee avatar, opens a DetailSheet. | Works in any to-do or checklist app. |
|
|
63
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
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. |
|
|
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. | Built so far: AgendaRow and DayStrip. |
|
|
66
66
|
| SegmentedControl | Two or three options, raised selected segment (Mine / Everyone, Agenda / Week). | Restyle of ToggleGroup. |
|
|
67
|
-
| FilterChips, VisibilityBadge
|
|
67
|
+
| FilterChips, VisibilityBadge (built) | On/off chips; "Only you" with a lock or "Everyone" with faces. | FilterChips still proposed. |
|
|
68
68
|
| InlineConfirm | A plain confirmation shown in place, for the few destructive actions that keep one. | Lighter than ConfirmDialog. |
|
|
69
69
|
| ChoiceCards | Two or three large side-by-side options (Google or Calendar link, Adult or Child). | |
|
|
70
70
|
| SearchHero, CardGrid | Big search box over a grid of LinkTiles grouped by topic. | |
|
|
71
71
|
|
|
72
72
|
## 4. People
|
|
73
73
|
|
|
74
|
-
| Component
|
|
75
|
-
|
|
|
76
|
-
| MemberAvatar | Photo, falling back to initial on the member's colour; sizes; ring
|
|
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.
|
|
74
|
+
| Component | What it does |
|
|
75
|
+
| :------------------------ | :-------------------------------------------------------------------------------------------------- |
|
|
76
|
+
| MemberAvatar (built) | Photo, falling back to initial on the member's colour; sizes; ring via AvatarStack. Extends Avatar. |
|
|
77
|
+
| AvatarStack (built) | Overlapping faces with a "+N". |
|
|
78
|
+
| AvatarUpload (built) | Upload, change or remove a photo with live preview. |
|
|
79
|
+
| ColorSwatchPicker (built) | Radio group of category colours; colours used by someone else are marked and disabled. |
|
|
80
|
+
| CategoryDot (built) | Dot in a category colour, optional lock for private items. |
|
|
80
81
|
|
|
81
82
|
## 5. Feedback and motion
|
|
82
83
|
|
|
@@ -84,12 +85,12 @@ Calendar views and SmartInput follow when a second app needs them.
|
|
|
84
85
|
| :-------------------- | :----------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
85
86
|
| `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
87
|
| 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
|
|
88
|
+
| Celebration (built) | Occasional confetti when a day is cleared. Off under reduced motion. | Built as CSS with no new dependency: `Celebration` + `celebrate()`. |
|
|
88
89
|
|
|
89
90
|
## 6. Foundations (`src/styles.css`)
|
|
90
91
|
|
|
91
92
|
- **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
93
|
- **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.
|
|
94
|
+
- **Size floors.** Checks 24px, phone touch targets 44px, no text under 12px. Avatar initials and `kbd` are 12px.
|
|
94
95
|
- **Brand mark slot.** AppNav (`brand`) and AuthLayout (`brand`) take the product mark as a prop.
|
|
95
96
|
- **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.
|
package/llms.txt
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
- Use harebear-ui components before writing new UI. Primitives keep shadcn/ui names and props.
|
|
15
15
|
- Style with theme tokens only: bg-background, bg-card, bg-muted, text-muted-foreground, bg-primary, bg-primary-soft, text-success, text-warning, text-destructive, border-border, shadow-card, rounded-md/lg/xl. No hex colors or Tailwind palette colors.
|
|
16
|
-
- Status is a tone: success | warning | danger | info | neutral. Members, lists and calendars use category-1..6 (bg-category-3), never status colors.
|
|
17
|
-
- Agent-first apps (assistant on every page, undoable actions): AppNav + AssistantProvider/AssistantDock + SectionedList + toastUndo + FocusLayout/SettingsSection. Recipe: `npx harebear-ui docs "Agent-first apps"`.
|
|
16
|
+
- Status is a tone: success | warning | danger | info | neutral. Members, lists and calendars use category-1..6 (bg-category-3, or `color={3}` on MemberAvatar, CategoryDot, ColorSwatchPicker), never status colors.
|
|
17
|
+
- Agent-first apps (assistant on every page, undoable actions): AppNav + AssistantProvider/AssistantDock + SectionedList + toastUndo + FocusLayout/SettingsSection. A page's own AskBox answers inline with `reply` from useAssistant and stops with `pending` + `onStop={stop}`. Recipe: `npx harebear-ui docs "Agent-first apps"`.
|
|
18
18
|
- Icons: lucide-react elements, e.g. `<SearchIcon />`. Icon-only buttons need aria-label.
|
|
19
19
|
- Change the brand with `<ThemeProvider accent="#hex" radius={14}>` or `--brand` / `--radius` in CSS.
|
|
20
20
|
|
|
@@ -32,13 +32,14 @@
|
|
|
32
32
|
## Component index
|
|
33
33
|
|
|
34
34
|
Theme: ThemeProvider, useTheme, ThemeToggle, ThemeScript
|
|
35
|
-
Layout/admin: SidebarLayout, SidebarCollapseButton, AppShell, AppNav, FocusLayout, SettingsSection, SettingsRow, AppBrand, PageHeader, StatCard, SearchInput, StatusDot, StatusBadge, UsageMeter, ActivityFeed, Timeline, KeyValueGrid, UserChip, UserMenu, Callout, LinkTile, ConfirmDialog, CopyField
|
|
35
|
+
Layout/admin: SidebarLayout, SidebarCollapseButton, AppShell, AppNav, FocusLayout, SettingsSection, SettingsRow, AppBrand, PageHeader, StatCard, SearchInput, StatusDot, StatusBadge, UsageMeter, ActivityFeed, Timeline, KeyValueGrid, UserChip, UserMenu, MemberAvatar, AvatarStack, VisibilityBadge, CategoryDot, ColorSwatchPicker, AvatarUpload, Callout, LinkTile, ConfirmDialog, CopyField, DetailSheet
|
|
36
36
|
Layout and text: Stack, Row, Grid, Text, Heading, Metric, MetricGroup, MediaItem, ShowMore, Collapse
|
|
37
|
-
Data: TaskRow, SectionedList, DataTable, createDataTableColumnHelper, TrendChart, TrendLegend, BarList, Sparkline, StatusBars
|
|
37
|
+
Data: TaskRow, SectionedList, AgendaRow, DayStrip, DataTable, createDataTableColumnHelper, TrendChart, TrendLegend, BarList, Sparkline, StatusBars
|
|
38
38
|
Assistant layer: AssistantProvider, useAssistant, useAssistantPage, AssistantDock, AskBox, DictationButton, useDictation, browserSpeechSource, ActionReceipt
|
|
39
|
-
AI/chat composites: ChatShell, ChatPanel, ChatThread, ChatMessage, AssistantAvatar, MessageActions, PromptInput, PromptInputChip, PromptInputSelect, ModelPicker, ConversationList, NewConversationButton, groupByDate, formatWhen, ToolCall, ToolGroup, ToolStep, ToolStatusIcon, ApprovalCard, ApprovalResult, TypingIndicator, CodeSnippet, InlineCode, Prose
|
|
39
|
+
AI/chat composites: ChatShell, ChatPanel, ChatThread, ChatMessage, AssistantAvatar, MessageActions, PromptInput, PromptInputChip, PromptInputSelect, ModelPicker, ConversationList, NewConversationButton, groupByDate, formatWhen, ToolCall, ToolGroup, ToolStep, ToolStatusIcon, ApprovalCard, ApprovalResult, TypingIndicator, CodeSnippet, InlineCode, Prose, ProseBlockquote
|
|
40
40
|
AI/chat primitives (shadcn): Message, Bubble, MessageScroller, Attachment, Trace, Marker, Questionnaire, CodeBlock
|
|
41
41
|
Auth: AuthLayout, LoginForm, SignupForm, GitHubIcon, GoogleIcon, AppleIcon
|
|
42
|
-
|
|
42
|
+
Forms: PasswordInput, DateTimePicker, MarkdownEditor
|
|
43
|
+
Feedback: Toaster, toastUndo, CheckCircle, Celebration, celebrate
|
|
43
44
|
Primitives (the full shadcn/ui registry): Accordion, Alert, AlertDialog, AspectRatio, Attachment, Avatar, Badge, Breadcrumb, Bubble, Button, ButtonGroup, Calendar, Card, Carousel, Chart, Checkbox, CodeBlock, Collapsible, Combobox, Command, ContextMenu, Dialog, DirectionProvider, Drawer, DropdownMenu, Empty, Field, HoverCard, Input, InputGroup, InputOTP, Item, Kbd, Label, Marker, Menubar, Message, MessageScroller, NativeSelect, NavigationMenu, Pagination, Popover, Progress, Questionnaire, RadioGroup, Resizable, ScrollArea, Select, Separator, Sheet, Sidebar, Skeleton, Slider, Spinner, Switch, Table, Tabs, Textarea, Toaster, Toggle, ToggleGroup, Tooltip, Trace
|
|
44
|
-
Hooks/utils: useCopyToClipboard, useHighlightedCode, useIsMobile, useMediaQuery, useSidebarOptional, cn
|
|
45
|
+
Hooks/utils: categoryBg, cropImageToSquare, useCopyToClipboard, useHighlightedCode, useIsMobile, useMediaQuery, useSidebarOptional, cn
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "harebear-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Opinionated, pre-themed shadcn/ui component library for React 19 + Tailwind CSS v4. Admin, data, and AI chat building blocks, ready for agents.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Harrison Milbradt",
|
|
@@ -26,10 +26,11 @@ This project uses `harebear-ui` for all UI. Its theme, tokens, and components ar
|
|
|
26
26
|
- DataTable columns: define with `createDataTableColumnHelper<Row>()` at module scope, pass `getRowId`.
|
|
27
27
|
- Chat apps: `ChatShell` (sidebar: `AppBrand`, `NewConversationButton`, `ConversationList` + `groupByDate`, `UserMenu`; optional `details` panel) around a `ChatPanel` (title, actions, `notice`, `composer`). Don't hand-build the sidebar, rail or panel.
|
|
28
28
|
- Chat content: `ChatMessage role="user" | "assistant"`; render model output inside `Prose`; composer is `PromptInput` (+ `PromptInputChip`, `PromptInputSelect`); code is `CodeSnippet`; agent tool calls are `ToolGroup`/`ToolStep` (or the lighter `Trace`); permission prompts are `ApprovalCard`/`ApprovalResult`; working state is `TypingIndicator label`; clarifying questions are `Questionnaire`.
|
|
29
|
-
- Agent-first and household apps: `AppNav` (sidebar on desktop, tab bar on phones) around pages; `AssistantProvider` + `AssistantDock` (pages call `useAssistantPage`); `AskBox` with `DictationButton`; `ActionReceipt` for each action the agent took; `toastUndo` after undoable changes; to-dos are `SectionedList` / `TaskRow` / `CheckCircle`; settings are `FocusLayout` + `SettingsSection` + `SettingsRow`. Recipe: `npx harebear-ui docs "Agent-first apps"`. Categories (members, lists) use `category-1..6`.
|
|
29
|
+
- Agent-first and household apps: `AppNav` (sidebar on desktop, tab bar on phones) around pages; `AssistantProvider` + `AssistantDock` (pages call `useAssistantPage`); `AskBox` with `DictationButton` (inline answers: `AskBox` `reply={reply}` from `useAssistant()` plus your own `chatHref`, `send(text, { open: false })`; Stop: `pending` + `onStop={stop}`); `ActionReceipt` for each action the agent took; `toastUndo` after undoable changes; to-dos are `SectionedList` / `TaskRow` / `CheckCircle` (`lingerMs` = the Undo window); a week agenda is `DayStrip` + one `SectionedList` with a section per day and `AgendaRow` rows via `renderItem`; settings are `FocusLayout` + `SettingsSection` + `SettingsRow`. Recipe: `npx harebear-ui docs "Agent-first apps"`. Categories (members, lists) use `category-1..6`. People are `MemberAvatar` (photo or initials on their `color`), `AvatarStack` and `VisibilityBadge`; list dots are `CategoryDot` (`locked` for private); profile settings use `AvatarUpload` and `ColorSwatchPicker`.
|
|
30
30
|
- Notices: `Alert variant="warning" | "success" | "info" | "destructive"`. Confirmations: `ConfirmDialog`. Copyable IDs: `CopyField`. Live status: `StatusDot`/`StatusBadge` with `pulse`.
|
|
31
31
|
- If you need a className to fix spacing, color, wrapping or borders on a harebear component, that is a library gap: report it instead of overriding.
|
|
32
32
|
- Sign-in and sign-up pages: `AuthLayout` + `LoginForm` / `SignupForm`. Don't hand-build auth forms.
|
|
33
|
+
- Form fields beyond `Input`: `PasswordInput` (Show/Hide; every password field), `DateTimePicker` (`{ date: "YYYY-MM-DD", time?: "HH:MM" }`, floating local), `MarkdownEditor` (Write/Preview; pass `renderPreview`). A record's details open in `DetailSheet` (side sheet on desktop, full screen on phones). Markdown goes inside `Prose`; `> Tip:` blockquotes become a `Callout` (react-markdown: `components={{ blockquote: ProseBlockquote }}`). Rare joy moments: mount `Celebration` once, call `celebrate()`.
|
|
33
34
|
- Theme: `ThemeProvider` at the root (`accent`, `radius`, `defaultMode`), `ThemeToggle` for the light/dark button. Both modes must work: never style for only one.
|
|
34
35
|
|
|
35
36
|
## Check your work
|