harebear-ui 0.5.0 → 0.6.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.
@@ -12,7 +12,9 @@ export interface StatusBadgeProps extends React.ComponentProps<typeof Badge> {
12
12
  tone?: StatusTone;
13
13
  /** Pulse the dot. */
14
14
  pulse?: boolean;
15
+ /** Below 640px show only the dot; the label stays for screen readers. For crowded mobile headers. */
16
+ compact?: boolean;
15
17
  }
16
18
  /** Pill with a status dot and label, e.g. Paid / Pending / Refunded. `size="lg"` lines up with sm buttons. */
17
- declare function StatusBadge({ tone, pulse, variant, children, className, ...props }: StatusBadgeProps): React.JSX.Element;
19
+ declare function StatusBadge({ tone, pulse, compact, variant, children, className, ...props }: StatusBadgeProps): React.JSX.Element;
18
20
  export { StatusBadge, StatusDot };
@@ -20,7 +20,7 @@ function StatusDot({ tone = "neutral", pulse, className, ...props }) {
20
20
  });
21
21
  }
22
22
  /** Pill with a status dot and label, e.g. Paid / Pending / Refunded. `size="lg"` lines up with sm buttons. */
23
- function StatusBadge({ tone = "neutral", pulse, variant = "secondary", children, className, ...props }) {
23
+ function StatusBadge({ tone = "neutral", pulse, compact, variant = "secondary", children, className, ...props }) {
24
24
  return /* @__PURE__ */ jsxs(Badge, {
25
25
  "data-slot": "status-badge",
26
26
  variant,
@@ -29,7 +29,10 @@ function StatusBadge({ tone = "neutral", pulse, variant = "secondary", children,
29
29
  children: [/* @__PURE__ */ jsx(StatusDot, {
30
30
  tone,
31
31
  pulse
32
- }), children]
32
+ }), compact ? /* @__PURE__ */ jsx("span", {
33
+ className: "sr-only sm:not-sr-only",
34
+ children
35
+ }) : children]
33
36
  });
34
37
  }
35
38
  export { StatusBadge, StatusDot };
@@ -14,12 +14,14 @@ export interface ApprovalCardProps extends Omit<React.ComponentProps<"section">,
14
14
  actions?: React.ReactNode;
15
15
  /** Small print under the actions. */
16
16
  footer?: React.ReactNode;
17
+ /** Why the agent wants this, shown first in the body after a bold "Why:". */
18
+ reason?: React.ReactNode;
17
19
  }
18
20
  /**
19
21
  * Highlighted card for anything the agent is waiting on the user for: a tool approval, a question, a choice.
20
22
  * Body text goes in children (e.g. the agent's reason).
21
23
  */
22
- declare function ApprovalCard({ title, description, icon, code, codeLabel, actions, footer, className, children, ...props }: ApprovalCardProps): React.JSX.Element;
24
+ declare function ApprovalCard({ title, description, icon, code, codeLabel, actions, footer, reason, className, children, ...props }: ApprovalCardProps): React.JSX.Element;
23
25
  export interface ApprovalResultProps extends React.ComponentProps<"div"> {
24
26
  decision: "approved" | "denied";
25
27
  /** Trailing time, e.g. "10:42". */
@@ -9,7 +9,7 @@ import { CheckIcon, ShieldAlertIcon, XIcon } from "lucide-react";
9
9
  * Highlighted card for anything the agent is waiting on the user for: a tool approval, a question, a choice.
10
10
  * Body text goes in children (e.g. the agent's reason).
11
11
  */
12
- function ApprovalCard({ title, description, icon = /* @__PURE__ */ jsx(ShieldAlertIcon, {}), code, codeLabel, actions, footer, className, children, ...props }) {
12
+ function ApprovalCard({ title, description, icon = /* @__PURE__ */ jsx(ShieldAlertIcon, {}), code, codeLabel, actions, footer, reason, className, children, ...props }) {
13
13
  const id = React.useId();
14
14
  return /* @__PURE__ */ jsxs("section", {
15
15
  "data-slot": "approval-card",
@@ -34,9 +34,12 @@ function ApprovalCard({ title, description, icon = /* @__PURE__ */ jsx(ShieldAle
34
34
  })]
35
35
  })]
36
36
  }),
37
- children && /* @__PURE__ */ jsx("div", {
37
+ (reason || children) && /* @__PURE__ */ jsxs("div", {
38
38
  className: "text-[14.5px] leading-relaxed whitespace-pre-wrap wrap-anywhere [&_strong]:font-semibold",
39
- children
39
+ children: [reason && /* @__PURE__ */ jsxs("p", { children: [/* @__PURE__ */ jsx("strong", { children: "Why: " }), reason] }), reason && children ? /* @__PURE__ */ jsx("div", {
40
+ className: "mt-2",
41
+ children
42
+ }) : children]
40
43
  }),
41
44
  code !== void 0 && /* @__PURE__ */ jsxs(CodeBlock, { children: [/* @__PURE__ */ jsxs(CodeBlockHeader, { children: [/* @__PURE__ */ jsx(CodeBlockTitle, { children: codeLabel ?? "command" }), /* @__PURE__ */ jsx(CodeBlockActions, { children: /* @__PURE__ */ jsx(CodeBlockCopyButton, { value: code }) })] }), /* @__PURE__ */ jsx(CodeBlockContent, {
42
45
  wrap: true,
@@ -10,8 +10,11 @@ export interface ChatThreadProps extends React.ComponentProps<"div"> {
10
10
  declare function ChatThread({ autoScroll, className, contentClassName, children, ...props }: ChatThreadProps): React.JSX.Element;
11
11
  export interface ChatMessageProps extends React.ComponentProps<"div"> {
12
12
  role: "user" | "assistant";
13
- /** Assistant avatar. Defaults to a sparkle in a tinted circle. */
14
- avatar?: React.ReactNode;
13
+ /**
14
+ * Assistant avatar. Defaults to a sparkle in a tinted circle. `false` renders no avatar and lets the content use
15
+ * the full width, for agent threads where one turn is many blocks (text, tool groups, approvals).
16
+ */
17
+ avatar?: React.ReactNode | false;
15
18
  /** Rendered under assistant content, usually <MessageActions />. */
16
19
  actions?: React.ReactNode;
17
20
  /** User bubble color: "muted" (gray, default) or "soft" (tinted with the accent). */
@@ -58,7 +58,7 @@ function ChatMessage({ role, avatar, actions, variant = "muted", className, chil
58
58
  "data-role": "assistant",
59
59
  className: cn("flex items-start gap-4", className),
60
60
  ...props,
61
- children: [avatar ?? /* @__PURE__ */ jsx(AssistantAvatar, {}), /* @__PURE__ */ jsxs("div", {
61
+ children: [avatar === false ? null : avatar ?? /* @__PURE__ */ jsx(AssistantAvatar, {}), /* @__PURE__ */ jsxs("div", {
62
62
  className: "flex min-w-0 flex-1 flex-col gap-3.5",
63
63
  children: [children, actions]
64
64
  })]
@@ -17,7 +17,11 @@ export interface CodeSnippetProps extends Omit<React.ComponentProps<typeof CodeB
17
17
  */
18
18
  declare function CodeSnippet({ code, language, highlight, lineNumbers, hideCopy, className, ...props }: CodeSnippetProps): React.JSX.Element;
19
19
  /** Inline monospace span for commands and identifiers. */
20
- declare function InlineCode({ className, ...props }: React.ComponentProps<"code">): React.JSX.Element;
20
+ export interface InlineCodeProps extends React.ComponentProps<"code"> {
21
+ /** Cut string children longer than this many characters with an ellipsis; the full text becomes the tooltip. */
22
+ truncate?: number;
23
+ }
24
+ declare function InlineCode({ truncate, className, children, title, ...props }: InlineCodeProps): React.JSX.Element;
21
25
  /**
22
26
  * Typography for long-form and model output. Styles plain HTML children
23
27
  * (p, ul, ol, li, strong, a, code, pre, h1-h4, blockquote, table), so it works
@@ -40,12 +40,14 @@ function CodeSnippet({ code, language, highlight = true, lineNumbers, hideCopy,
40
40
  })]
41
41
  });
42
42
  }
43
- /** Inline monospace span for commands and identifiers. */
44
- function InlineCode({ className, ...props }) {
43
+ function InlineCode({ truncate, className, children, title, ...props }) {
44
+ const cut = truncate !== void 0 && typeof children === "string" && children.length > truncate;
45
45
  return /* @__PURE__ */ jsx("code", {
46
46
  "data-slot": "inline-code",
47
+ title: title ?? (cut ? children : void 0),
47
48
  className: cn("rounded-[6px] bg-muted px-1.5 py-0.5 font-mono text-[12.5px]", className),
48
- ...props
49
+ ...props,
50
+ children: cut ? `${children.slice(0, truncate)}…` : children
49
51
  });
50
52
  }
51
53
  /**
@@ -10,6 +10,8 @@ export interface Conversation {
10
10
  tone?: StatusTone;
11
11
  /** Pulse the status dot. */
12
12
  pulse?: boolean;
13
+ /** With `onDelete`: block deleting this row. A string is shown as the reason, e.g. "Stop the agent first". */
14
+ deleteDisabled?: boolean | string;
13
15
  }
14
16
  export interface ConversationGroup {
15
17
  /** e.g. "Today", "Yesterday", "Previous 7 days". */
@@ -22,6 +24,13 @@ export interface ConversationListProps extends Omit<React.ComponentProps<"nav">,
22
24
  onSelect?: (id: string) => void;
23
25
  /** Trailing control per row, e.g. a delete button. On devices that can hover it shows on hover and focus; on touch it is always visible. */
24
26
  renderAction?: (conversation: Conversation) => React.ReactNode;
27
+ /**
28
+ * Adds a delete button to each row that asks for confirmation first, then calls this. Ignored when `renderAction`
29
+ * is set. Use `Conversation.deleteDisabled` to block it per row.
30
+ */
31
+ onDelete?: (conversation: Conversation) => void;
32
+ /** Body of the delete confirmation. Default "This cannot be undone." */
33
+ deleteDescription?: React.ReactNode;
25
34
  /** Shown when there are no conversations. Default "No conversations yet". */
26
35
  empty?: React.ReactNode;
27
36
  }
@@ -29,12 +38,17 @@ export interface ConversationListProps extends Omit<React.ComponentProps<"nav">,
29
38
  * Grouped list of chat threads for a sidebar. Inside a Sidebar it closes the mobile sheet on select,
30
39
  * and hides itself when the sidebar is collapsed to its icon rail.
31
40
  */
32
- declare function ConversationList({ groups, activeId, onSelect, renderAction, empty, className, ...props }: ConversationListProps): React.JSX.Element;
41
+ declare function ConversationList({ groups, activeId, onSelect, renderAction, onDelete, deleteDescription, empty, className, ...props }: ConversationListProps): React.JSX.Element;
33
42
  /**
34
43
  * Buckets items into Today / Yesterday / Previous 7 days / Earlier by a timestamp (ms or Date),
35
44
  * newest first, and drops empty groups. Pass `now` for deterministic tests.
36
45
  */
37
46
  declare function groupByDate<T>(items: T[], getDate: (item: T) => number | Date, toConversation: (item: T) => Conversation, now?: number | Date): ConversationGroup[];
47
+ /**
48
+ * Short timestamp for lists and headers: the time today ("9:41 AM"), the date this year ("Nov 3"), else with the
49
+ * year ("Nov 3, 2025"). Uses the browser locale unless `locale` is given. Pass `now` for deterministic tests.
50
+ */
51
+ declare function formatWhen(date: number | Date, now?: number | Date, locale?: string | string[]): string;
38
52
  export interface NewConversationButtonProps extends React.ComponentProps<typeof Button> {
39
53
  /** Default "New conversation". */
40
54
  label?: string;
@@ -48,4 +62,4 @@ export interface NewConversationButtonProps extends React.ComponentProps<typeof
48
62
  * tooltip; on mobile it closes the sidebar sheet after the click.
49
63
  */
50
64
  declare function NewConversationButton({ label, icon, shortcut, variant, onClick, className, ...props }: NewConversationButtonProps): React.JSX.Element;
51
- export { ConversationList, NewConversationButton, groupByDate };
65
+ export { ConversationList, NewConversationButton, formatWhen, groupByDate };
@@ -1,19 +1,35 @@
1
1
  "use client";
2
+ import { ConfirmDialog } from "../admin/confirm-dialog.js";
2
3
  import { StatusDot } from "../admin/status.js";
3
4
  import { Button } from "../ui/button.js";
4
5
  import { Empty, EmptyDescription } from "../ui/empty.js";
5
6
  import { useSidebarOptional } from "../ui/sidebar.js";
6
7
  import { Tooltip, TooltipContent, TooltipTrigger } from "../ui/tooltip.js";
7
8
  import { cn } from "../../lib/utils.js";
9
+ import * as React from "react";
8
10
  import { jsx, jsxs } from "react/jsx-runtime";
9
- import { PlusIcon } from "lucide-react";
11
+ import { PlusIcon, Trash2Icon } from "lucide-react";
10
12
  // src/components/ai/conversation-list.tsx
11
13
  /**
12
14
  * Grouped list of chat threads for a sidebar. Inside a Sidebar it closes the mobile sheet on select,
13
15
  * and hides itself when the sidebar is collapsed to its icon rail.
14
16
  */
15
- function ConversationList({ groups, activeId, onSelect, renderAction, empty = "No conversations yet", className, ...props }) {
17
+ function ConversationList({ groups, activeId, onSelect, renderAction, onDelete, deleteDescription = "This cannot be undone.", empty = "No conversations yet", className, ...props }) {
16
18
  const sidebar = useSidebarOptional();
19
+ const [confirm, setConfirm] = React.useState(null);
20
+ const [confirmOpen, setConfirmOpen] = React.useState(false);
21
+ const deleteButton = (c) => /* @__PURE__ */ jsx(Button, {
22
+ variant: "ghost",
23
+ size: "icon-sm",
24
+ "aria-label": `Delete ${c.title}`,
25
+ title: typeof c.deleteDisabled === "string" ? c.deleteDisabled : "Delete conversation",
26
+ disabled: !!c.deleteDisabled,
27
+ onClick: () => {
28
+ setConfirm(c);
29
+ setConfirmOpen(true);
30
+ },
31
+ children: /* @__PURE__ */ jsx(Trash2Icon, {})
32
+ });
17
33
  const select = (id) => {
18
34
  onSelect?.(id);
19
35
  sidebar?.setOpenMobile(false);
@@ -24,43 +40,57 @@ function ConversationList({ groups, activeId, onSelect, renderAction, empty = "N
24
40
  "aria-label": "Conversations",
25
41
  className: cn("flex flex-col gap-4.5 group-data-[collapsible=icon]:hidden", className),
26
42
  ...props,
27
- children: [visible.map((g) => /* @__PURE__ */ jsxs("div", {
28
- className: "flex flex-col gap-0.5",
29
- children: [/* @__PURE__ */ jsx("div", {
30
- className: "px-3 pb-1.5 text-xs font-medium text-muted-foreground",
31
- children: g.label
32
- }), g.items.map((c) => {
33
- const active = c.id === activeId;
34
- const action = renderAction?.(c);
35
- return /* @__PURE__ */ jsxs("div", {
36
- "data-slot": "conversation-item",
37
- "data-active": active || void 0,
38
- className: cn("group/conversation flex min-w-0 items-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", active && "bg-card text-foreground shadow-card hover:bg-card"),
39
- children: [/* @__PURE__ */ jsxs("button", {
40
- type: "button",
41
- "aria-current": active ? "page" : void 0,
42
- onClick: () => select(c.id),
43
- className: cn("flex min-w-0 flex-1 flex-col rounded-md py-2.25 pl-3 text-left font-medium outline-none focus-visible:ring-2 focus-visible:ring-ring/40", action ? "pr-1" : "pr-3"),
44
- children: [/* @__PURE__ */ jsx("span", {
45
- className: "truncate",
46
- children: c.title
47
- }), c.description !== void 0 && /* @__PURE__ */ jsxs("span", {
48
- className: "flex min-w-0 items-center gap-1.5 text-xs font-normal text-muted-foreground tabular-nums",
49
- children: [c.tone && /* @__PURE__ */ jsx(StatusDot, {
50
- tone: c.tone,
51
- pulse: c.pulse
52
- }), /* @__PURE__ */ jsx("span", {
43
+ children: [
44
+ visible.map((g) => /* @__PURE__ */ jsxs("div", {
45
+ className: "flex flex-col gap-0.5",
46
+ children: [/* @__PURE__ */ jsx("div", {
47
+ className: "px-3 pb-1.5 text-xs font-medium text-muted-foreground",
48
+ children: g.label
49
+ }), g.items.map((c) => {
50
+ const active = c.id === activeId;
51
+ const action = renderAction ? renderAction(c) : onDelete ? deleteButton(c) : null;
52
+ return /* @__PURE__ */ jsxs("div", {
53
+ "data-slot": "conversation-item",
54
+ "data-active": active || void 0,
55
+ className: cn("group/conversation flex min-w-0 items-center rounded-md text-muted-foreground transition-colors hover:bg-muted hover:text-foreground", active && "bg-card text-foreground shadow-card hover:bg-card"),
56
+ children: [/* @__PURE__ */ jsxs("button", {
57
+ type: "button",
58
+ "aria-current": active ? "page" : void 0,
59
+ onClick: () => select(c.id),
60
+ className: cn("flex min-w-0 flex-1 flex-col rounded-md py-2.25 pl-3 text-left font-medium outline-none focus-visible:ring-2 focus-visible:ring-ring/40", action ? "pr-1" : "pr-3"),
61
+ children: [/* @__PURE__ */ jsx("span", {
53
62
  className: "truncate",
54
- children: c.description
63
+ children: c.title
64
+ }), c.description !== void 0 && /* @__PURE__ */ jsxs("span", {
65
+ className: "flex min-w-0 items-center gap-1.5 text-xs font-normal text-muted-foreground tabular-nums",
66
+ children: [c.tone && /* @__PURE__ */ jsx(StatusDot, {
67
+ tone: c.tone,
68
+ pulse: c.pulse
69
+ }), /* @__PURE__ */ jsx("span", {
70
+ className: "truncate",
71
+ children: c.description
72
+ })]
55
73
  })]
74
+ }), action && /* @__PURE__ */ jsx("div", {
75
+ className: "mr-1 flex shrink-0 items-center [@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-hover/conversation:opacity-100 [@media(hover:hover)]:group-focus-within/conversation:opacity-100",
76
+ children: action
56
77
  })]
57
- }), action && /* @__PURE__ */ jsx("div", {
58
- className: "mr-1 flex shrink-0 items-center [@media(hover:hover)]:opacity-0 [@media(hover:hover)]:group-hover/conversation:opacity-100 [@media(hover:hover)]:group-focus-within/conversation:opacity-100",
59
- children: action
60
- })]
61
- }, c.id);
62
- })]
63
- }, g.label)), !visible.length && empty && /* @__PURE__ */ jsx(Empty, { children: /* @__PURE__ */ jsx(EmptyDescription, { children: empty }) })]
78
+ }, c.id);
79
+ })]
80
+ }, g.label)),
81
+ !visible.length && empty && /* @__PURE__ */ jsx(Empty, { children: /* @__PURE__ */ jsx(EmptyDescription, { children: empty }) }),
82
+ onDelete && /* @__PURE__ */ jsx(ConfirmDialog, {
83
+ open: confirmOpen,
84
+ onOpenChange: setConfirmOpen,
85
+ title: `Delete “${confirm?.title ?? ""}”?`,
86
+ description: deleteDescription,
87
+ confirmLabel: "Delete",
88
+ destructive: true,
89
+ onConfirm: () => {
90
+ if (confirm) onDelete(confirm);
91
+ }
92
+ })
93
+ ]
64
94
  });
65
95
  }
66
96
  /**
@@ -101,6 +131,27 @@ function groupByDate(items, getDate, toConversation, now = Date.now()) {
101
131
  return groups.filter((g) => g.items.length);
102
132
  }
103
133
  /**
134
+ * Short timestamp for lists and headers: the time today ("9:41 AM"), the date this year ("Nov 3"), else with the
135
+ * year ("Nov 3, 2025"). Uses the browser locale unless `locale` is given. Pass `now` for deterministic tests.
136
+ */
137
+ function formatWhen(date, now = Date.now(), locale) {
138
+ const d = new Date(date);
139
+ const n = new Date(now);
140
+ if (d.toDateString() === n.toDateString()) return d.toLocaleTimeString(locale, {
141
+ hour: "numeric",
142
+ minute: "2-digit"
143
+ });
144
+ if (d.getFullYear() === n.getFullYear()) return d.toLocaleDateString(locale, {
145
+ month: "short",
146
+ day: "numeric"
147
+ });
148
+ return d.toLocaleDateString(locale, {
149
+ month: "short",
150
+ day: "numeric",
151
+ year: "numeric"
152
+ });
153
+ }
154
+ /**
104
155
  * Full-width "New conversation" button for a sidebar header. In the icon rail it shrinks to an icon with a
105
156
  * tooltip; on mobile it closes the sidebar sheet after the click.
106
157
  */
@@ -136,4 +187,4 @@ function NewConversationButton({ label = "New conversation", icon = /* @__PURE__
136
187
  children: label
137
188
  })] });
138
189
  }
139
- export { ConversationList, NewConversationButton, groupByDate };
190
+ export { ConversationList, NewConversationButton, formatWhen, groupByDate };
@@ -7,6 +7,8 @@ export interface ModelOption {
7
7
  description?: React.ReactNode;
8
8
  /** Availability dot. Default "success". */
9
9
  status?: StatusTone;
10
+ /** Section heading in the menu, e.g. the provider. Models with the same group are listed together. */
11
+ group?: string;
10
12
  }
11
13
  export interface ModelPickerProps {
12
14
  models: ModelOption[];
@@ -16,6 +18,9 @@ export interface ModelPickerProps {
16
18
  className?: string;
17
19
  disabled?: boolean;
18
20
  }
19
- /** Pill button showing the active model with a status dot; opens a menu of models. */
21
+ /**
22
+ * Pill button showing the active model with a status dot; opens a menu of models, sectioned by `group`.
23
+ * A `value` missing from `models` is still listed (and checked) at the top.
24
+ */
20
25
  declare function ModelPicker({ models, value, onValueChange, label, className, disabled }: ModelPickerProps): React.JSX.Element;
21
26
  export { ModelPicker };
@@ -1,14 +1,27 @@
1
1
  "use client";
2
2
  import { StatusDot } from "../admin/status.js";
3
3
  import { Button } from "../ui/button.js";
4
- import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger } from "../ui/dropdown-menu.js";
4
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuSeparator, DropdownMenuTrigger } from "../ui/dropdown-menu.js";
5
5
  import { cn } from "../../lib/utils.js";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  import { CheckIcon, ChevronDownIcon } from "lucide-react";
8
8
  // src/components/ai/model-picker.tsx
9
- /** Pill button showing the active model with a status dot; opens a menu of models. */
9
+ /**
10
+ * Pill button showing the active model with a status dot; opens a menu of models, sectioned by `group`.
11
+ * A `value` missing from `models` is still listed (and checked) at the top.
12
+ */
10
13
  function ModelPicker({ models, value, onValueChange, label = "Model", className, disabled }) {
11
14
  const current = models.find((m) => m.id === value);
15
+ const all = current || !value ? models : [{ id: value }, ...models];
16
+ const groups = [];
17
+ for (const m of all) {
18
+ const g = groups.find((x) => x.name === m.group);
19
+ if (g) g.items.push(m);
20
+ else groups.push({
21
+ name: m.group,
22
+ items: [m]
23
+ });
24
+ }
12
25
  return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
13
26
  asChild: true,
14
27
  disabled,
@@ -29,27 +42,34 @@ function ModelPicker({ models, value, onValueChange, label = "Model", className,
29
42
  }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
30
43
  align: "end",
31
44
  className: "min-w-56",
32
- children: [/* @__PURE__ */ jsx(DropdownMenuLabel, { children: label }), models.map((m) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
33
- onSelect: () => onValueChange(m.id),
34
- className: "items-start gap-2.5",
35
- children: [
36
- /* @__PURE__ */ jsx(StatusDot, {
37
- tone: m.status ?? "success",
38
- className: "mt-1.5"
39
- }),
40
- /* @__PURE__ */ jsxs("div", {
41
- className: "flex min-w-0 flex-1 flex-col",
42
- children: [/* @__PURE__ */ jsx("span", {
43
- className: "font-mono text-xs",
44
- children: m.label ?? m.id
45
- }), m.description && /* @__PURE__ */ jsx("span", {
46
- className: "text-xs text-muted-foreground",
47
- children: m.description
48
- })]
49
- }),
50
- m.id === value && /* @__PURE__ */ jsx(CheckIcon, { className: "mt-0.5" })
51
- ]
52
- }, m.id))]
45
+ children: [/* @__PURE__ */ jsx(DropdownMenuLabel, { children: label }), groups.map((g, i) => /* @__PURE__ */ jsxs(DropdownMenuGroup, { children: [
46
+ i > 0 && /* @__PURE__ */ jsx(DropdownMenuSeparator, {}),
47
+ g.name && /* @__PURE__ */ jsx(DropdownMenuLabel, {
48
+ className: "text-xs font-medium text-muted-foreground",
49
+ children: g.name
50
+ }),
51
+ g.items.map((m) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
52
+ onSelect: () => onValueChange(m.id),
53
+ className: "items-start gap-2.5",
54
+ children: [
55
+ /* @__PURE__ */ jsx(StatusDot, {
56
+ tone: m.status ?? "success",
57
+ className: "mt-1.5"
58
+ }),
59
+ /* @__PURE__ */ jsxs("div", {
60
+ className: "flex min-w-0 flex-1 flex-col",
61
+ children: [/* @__PURE__ */ jsx("span", {
62
+ className: "font-mono text-xs",
63
+ children: m.label ?? m.id
64
+ }), m.description && /* @__PURE__ */ jsx("span", {
65
+ className: "text-xs text-muted-foreground",
66
+ children: m.description
67
+ })]
68
+ }),
69
+ m.id === value && /* @__PURE__ */ jsx(CheckIcon, { className: "mt-0.5" })
70
+ ]
71
+ }, m.id))
72
+ ] }, g.name ?? `group-${i}`))]
53
73
  })] });
54
74
  }
55
75
  export { ModelPicker };
@@ -4,7 +4,10 @@ declare const badgeVariants: (props?: ({
4
4
  variant?: "default" | "destructive" | "ghost" | "link" | "outline" | "secondary" | "soft" | "success" | "warning" | null | undefined;
5
5
  size?: "default" | "lg" | null | undefined;
6
6
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
7
- declare function Badge({ className, variant, size, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
7
+ type BadgeTone = "success" | "warning" | "danger" | "info" | "neutral";
8
+ declare function Badge({ className, variant: variantProp, tone, size, asChild, ...props }: React.ComponentProps<"span"> & VariantProps<typeof badgeVariants> & {
8
9
  asChild?: boolean;
10
+ /** harebear: color by status tone instead of variant. Wins over `variant`. */
11
+ tone?: BadgeTone;
9
12
  }): React.JSX.Element;
10
13
  export { Badge, badgeVariants };
@@ -28,8 +28,17 @@ const badgeVariants = cva("group/badge inline-flex h-6 w-fit shrink-0 items-cent
28
28
  size: "default"
29
29
  }
30
30
  });
31
- function Badge({ className, variant = "default", size = "default", asChild = false, ...props }) {
31
+ /** harebear: status tones (the same words as StatusBadge) mapped to Badge variants. */
32
+ const toneVariant = {
33
+ success: "success",
34
+ warning: "warning",
35
+ danger: "destructive",
36
+ info: "soft",
37
+ neutral: "secondary"
38
+ };
39
+ function Badge({ className, variant: variantProp = "default", tone, size = "default", asChild = false, ...props }) {
32
40
  const Comp = asChild ? Slot.Root : "span";
41
+ const variant = tone ? toneVariant[tone] : variantProp;
33
42
  return /* @__PURE__ */ jsx(Comp, {
34
43
  "data-slot": "badge",
35
44
  "data-variant": variant,
@@ -5,7 +5,9 @@ declare const buttonVariants: (props?: ({
5
5
  size?: "default" | "icon" | "icon-lg" | "icon-sm" | "icon-xs" | "lg" | "sm" | "xs" | null | undefined;
6
6
  shape?: "default" | "pill" | null | undefined;
7
7
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
8
- declare function Button({ className, variant, size, shape, asChild, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
8
+ declare function Button({ className, variant, size, shape, asChild, loading, disabled, children, ...props }: React.ComponentProps<"button"> & VariantProps<typeof buttonVariants> & {
9
9
  asChild?: boolean;
10
+ /** harebear: show a spinner and disable the button while an action runs. Icon buttons swap their icon for the spinner. */
11
+ loading?: boolean;
10
12
  }): React.JSX.Element;
11
13
  export { Button, buttonVariants };
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { cn } from "../../lib/utils.js";
3
- import { jsx } from "react/jsx-runtime";
3
+ import { Spinner } from "./spinner.js";
4
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
5
  import { cva } from "class-variance-authority";
5
6
  import { Slot } from "radix-ui";
6
7
  // src/components/ui/button.tsx
@@ -37,19 +38,28 @@ const buttonVariants = cva("group/button inline-flex shrink-0 items-center justi
37
38
  shape: "default"
38
39
  }
39
40
  });
40
- function Button({ className, variant = "default", size = "default", shape = "default", asChild = false, ...props }) {
41
+ function Button({ className, variant = "default", size = "default", shape = "default", asChild = false, loading = false, disabled, children, ...props }) {
41
42
  const Comp = asChild ? Slot.Root : "button";
43
+ const iconOnly = size?.startsWith("icon");
42
44
  return /* @__PURE__ */ jsx(Comp, {
43
45
  "data-slot": "button",
44
46
  "data-variant": variant,
45
47
  "data-size": size,
48
+ "data-loading": loading || void 0,
49
+ "aria-busy": loading || void 0,
50
+ disabled: disabled || loading,
46
51
  className: cn(buttonVariants({
47
52
  variant,
48
53
  size,
49
54
  shape,
50
55
  className
51
56
  })),
52
- ...props
57
+ ...props,
58
+ children: loading && !asChild ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Spinner, {
59
+ "aria-hidden": "true",
60
+ role: void 0,
61
+ "aria-label": void 0
62
+ }), !iconOnly && children] }) : children
53
63
  });
54
64
  }
55
65
  export { Button, buttonVariants };
@@ -1,5 +1,8 @@
1
1
  import { VariantProps } from "class-variance-authority";
2
- declare function Empty({ className, ...props }: React.ComponentProps<"div">): import("react").JSX.Element;
2
+ declare function Empty({ className, size, ...props }: React.ComponentProps<"div"> & {
3
+ /** harebear: "sm" is a compact empty for inside cards and panels (no flex-grow, 12px padding). */
4
+ size?: "default" | "sm";
5
+ }): import("react").JSX.Element;
3
6
  declare function EmptyHeader({ className, ...props }: React.ComponentProps<"div">): import("react").JSX.Element;
4
7
  declare const emptyMediaVariants: (props?: ({
5
8
  variant?: "default" | "icon" | null | undefined;
@@ -3,10 +3,11 @@ import { cn } from "../../lib/utils.js";
3
3
  import { jsx } from "react/jsx-runtime";
4
4
  import { cva } from "class-variance-authority";
5
5
  // src/components/ui/empty.tsx
6
- function Empty({ className, ...props }) {
6
+ function Empty({ className, size = "default", ...props }) {
7
7
  return /* @__PURE__ */ jsx("div", {
8
8
  "data-slot": "empty",
9
- className: cn("flex w-full min-w-0 flex-1 flex-col items-center justify-center gap-4 rounded-xl border-dashed p-6 text-center text-balance", className),
9
+ "data-size": size,
10
+ className: cn("flex w-full min-w-0 flex-col items-center justify-center rounded-xl border-dashed text-center text-balance", size === "sm" ? "gap-2 p-3" : "flex-1 gap-4 p-6", className),
10
11
  ...props
11
12
  });
12
13
  }
@@ -15,7 +15,10 @@ declare const itemMediaVariants: (props?: ({
15
15
  } & import("class-variance-authority/types").ClassProp) | undefined) => string;
16
16
  declare function ItemMedia({ className, variant, ...props }: React.ComponentProps<"div"> & VariantProps<typeof itemMediaVariants>): React.JSX.Element;
17
17
  declare function ItemContent({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
18
- declare function ItemTitle({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
18
+ declare function ItemTitle({ className, mono, onPointerEnter, ...props }: React.ComponentProps<"div"> & {
19
+ /** harebear: monospace, for commands, paths and IDs. */
20
+ mono?: boolean;
21
+ }): React.JSX.Element;
19
22
  declare function ItemDescription({ className, ...props }: React.ComponentProps<"p">): React.JSX.Element;
20
23
  declare function ItemActions({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
21
24
  declare function ItemHeader({ className, ...props }: React.ComponentProps<"div">): React.JSX.Element;
@@ -79,10 +79,15 @@ function ItemContent({ className, ...props }) {
79
79
  ...props
80
80
  });
81
81
  }
82
- function ItemTitle({ className, ...props }) {
82
+ function ItemTitle({ className, mono, onPointerEnter, ...props }) {
83
83
  return /* @__PURE__ */ jsx("div", {
84
84
  "data-slot": "item-title",
85
- className: cn("line-clamp-1 w-fit max-w-full text-sm leading-snug font-medium wrap-anywhere underline-offset-4", className),
85
+ className: cn("line-clamp-1 w-fit max-w-full text-sm leading-snug font-medium wrap-anywhere underline-offset-4", mono && "font-mono text-[13px]", className),
86
+ onPointerEnter: (e) => {
87
+ const el = e.currentTarget;
88
+ if (!props.title && el.scrollHeight > el.clientHeight) el.title = el.textContent ?? "";
89
+ onPointerEnter?.(e);
90
+ },
86
91
  ...props
87
92
  });
88
93
  }
package/dist/index.d.ts CHANGED
@@ -87,8 +87,8 @@ import { TrendChart, TrendChartProps, TrendLegend, TrendSeries } from "./compone
87
87
  import { ApprovalCard, ApprovalCardProps, ApprovalResult, ApprovalResultProps } from "./components/ai/approval.js";
88
88
  import { ChatPanel, ChatPanelProps, ChatShell, ChatShellProps } from "./components/ai/chat-shell.js";
89
89
  import { AssistantAvatar, ChatMessage, ChatMessageProps, ChatThread, ChatThreadProps, MessageActions, MessageActionsProps, ToolCall, ToolCallProps, TypingIndicator, TypingIndicatorProps } from "./components/ai/chat.js";
90
- import { CodeSnippet, CodeSnippetProps, InlineCode, Prose } from "./components/ai/code-block.js";
91
- import { Conversation, ConversationGroup, ConversationList, ConversationListProps, NewConversationButton, NewConversationButtonProps, groupByDate } from "./components/ai/conversation-list.js";
90
+ import { CodeSnippet, CodeSnippetProps, InlineCode, InlineCodeProps, Prose } from "./components/ai/code-block.js";
91
+ import { Conversation, ConversationGroup, ConversationList, ConversationListProps, NewConversationButton, NewConversationButtonProps, formatWhen, groupByDate } from "./components/ai/conversation-list.js";
92
92
  import { ModelOption, ModelPicker, ModelPickerProps } from "./components/ai/model-picker.js";
93
93
  import { PromptInput, PromptInputChip, PromptInputChipProps, PromptInputProps, PromptInputSelect, PromptInputSelectOption, PromptInputSelectProps } from "./components/ai/prompt-input.js";
94
94
  import { ToolGroup, ToolGroupProps, ToolStatus, ToolStatusIcon, ToolStep, ToolStepProps } from "./components/ai/tool-steps.js";
@@ -99,4 +99,4 @@ import { useMediaQuery } from "./hooks/use-media-query.js";
99
99
  import { useIsMobile } from "./hooks/use-mobile.js";
100
100
  import { highlightCode, loadHighlighter } from "./lib/highlighter.js";
101
101
  import { cn } from "./lib/utils.js";
102
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActivityFeed, type ActivityItem, Alert, AlertAction, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppBrand, type AppBrandProps, type AppNavItem, type AppNavSection, AppShell, type AppShellProps, AppleIcon, ApprovalCard, type ApprovalCardProps, ApprovalResult, type ApprovalResultProps, AspectRatio, AssistantAvatar, Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentGroup, AttachmentMedia, AttachmentTitle, AttachmentTrigger, AuthLayout, type AuthLayoutProps, type AuthProvider, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, BarList, type BarListItem, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Bubble, BubbleContent, BubbleGroup, BubbleReactions, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarDayButton, Callout, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, ChatMessage, type ChatMessageProps, ChatPanel, type ChatPanelProps, ChatShell, type ChatShellProps, ChatThread, type ChatThreadProps, Checkbox, CodeBlock, CodeBlockActions, CodeBlockContent, CodeBlockCopyButton, CodeBlockFooter, CodeBlockHeader, CodeBlockLine, CodeBlockTitle, CodeSnippet, type CodeSnippetProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, ComboboxTrigger, ComboboxValue, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, type Conversation, type ConversationGroup, ConversationList, type ConversationListProps, CopyField, type CopyFieldProps, DataTable, type DataTableColumnDef, type DataTableFeatures, type DataTableProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectionProvider, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, GitHubIcon, GoogleIcon, HoverCard, HoverCardContent, HoverCardTrigger, InlineCode, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, KeyValueGrid, type KeyValueItem, Label, LinkTile, type LinkTileProps, LoginForm, type LoginFormProps, type LoginValues, Marker, MarkerContent, MarkerIcon, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, Message, MessageActions, type MessageActionsProps, MessageAvatar, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, type ModelOption, ModelPicker, type ModelPickerProps, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewConversationButton, type NewConversationButtonProps, PageHeader, type PageHeaderProps, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, PromptInput, PromptInputChip, type PromptInputChipProps, type PromptInputProps, PromptInputSelect, type PromptInputSelectOption, type PromptInputSelectProps, Prose, Questionnaire, QuestionnaireActions, QuestionnaireChoice, QuestionnaireChoiceDescription, QuestionnaireChoices, QuestionnaireDescription, QuestionnaireError, QuestionnaireInput, QuestionnaireItem, QuestionnaireNext, QuestionnairePrevious, QuestionnaireProgress, QuestionnaireSkip, QuestionnaireSubmit, QuestionnaireTitle, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, type ResolvedThemeMode, ScrollArea, ScrollBar, SearchInput, type SearchInputProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarCollapseButton, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarLayout, type SidebarLayoutProps, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SignupForm, type SignupFormProps, type SignupValues, Skeleton, Slider, Sparkline, type SparklineProps, Spinner, StatCard, type StatCardProps, StatusBadge, type StatusBadgeProps, type StatusBarDatum, StatusBars, type StatusBarsProps, StatusDot, type StatusDotProps, type StatusTone, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThemeScript, ThemeToggle, Timeline, type TimelineItem, Toaster, Toggle, ToggleGroup, ToggleGroupItem, ToolCall, type ToolCallProps, ToolGroup, type ToolGroupProps, type ToolStatus, ToolStatusIcon, ToolStep, type ToolStepProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Trace, TraceCollapsible, TraceCollapsibleContent, TraceCollapsibleTrigger, TraceDescription, TraceIcon, TraceLine, TraceTitle, TrendChart, type TrendChartProps, TrendLegend, type TrendSeries, TypingIndicator, type TypingIndicatorProps, UsageMeter, type UsageMeterProps, UserChip, type UserChipProps, UserMenu, type UserMenuProps, badgeVariants, buttonGroupVariants, buttonVariants, cn, createDataTableColumnHelper, dataTableFeatures, groupByDate, highlightCode, initials, loadHighlighter, markerVariants, navigationMenuTriggerStyle, smoothPath, tabsListVariants, toggleVariants, useCarousel, useComboboxAnchor, useCopyToClipboard, useDirection, useHighlightedCode, useIsMobile, useMediaQuery, useMessageScroller, useMessageScrollerScrollable, useMessageScrollerVisibility, useSidebar, useSidebarOptional, useTheme };
102
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActivityFeed, type ActivityItem, Alert, AlertAction, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppBrand, type AppBrandProps, type AppNavItem, type AppNavSection, AppShell, type AppShellProps, AppleIcon, ApprovalCard, type ApprovalCardProps, ApprovalResult, type ApprovalResultProps, AspectRatio, AssistantAvatar, Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentGroup, AttachmentMedia, AttachmentTitle, AttachmentTrigger, AuthLayout, type AuthLayoutProps, type AuthProvider, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, BarList, type BarListItem, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Bubble, BubbleContent, BubbleGroup, BubbleReactions, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarDayButton, Callout, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, type CarouselApi, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, type ChartConfig, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, ChatMessage, type ChatMessageProps, ChatPanel, type ChatPanelProps, ChatShell, type ChatShellProps, ChatThread, type ChatThreadProps, Checkbox, CodeBlock, CodeBlockActions, CodeBlockContent, CodeBlockCopyButton, CodeBlockFooter, CodeBlockHeader, CodeBlockLine, CodeBlockTitle, CodeSnippet, type CodeSnippetProps, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, ComboboxTrigger, ComboboxValue, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, type ConfirmDialogProps, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, type Conversation, type ConversationGroup, ConversationList, type ConversationListProps, CopyField, type CopyFieldProps, DataTable, type DataTableColumnDef, type DataTableFeatures, type DataTableProps, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectionProvider, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, GitHubIcon, GoogleIcon, HoverCard, HoverCardContent, HoverCardTrigger, InlineCode, type InlineCodeProps, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, KeyValueGrid, type KeyValueItem, Label, LinkTile, type LinkTileProps, LoginForm, type LoginFormProps, type LoginValues, Marker, MarkerContent, MarkerIcon, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, Message, MessageActions, type MessageActionsProps, MessageAvatar, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, type ModelOption, ModelPicker, type ModelPickerProps, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewConversationButton, type NewConversationButtonProps, PageHeader, type PageHeaderProps, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, PromptInput, PromptInputChip, type PromptInputChipProps, type PromptInputProps, PromptInputSelect, type PromptInputSelectOption, type PromptInputSelectProps, Prose, Questionnaire, QuestionnaireActions, QuestionnaireChoice, QuestionnaireChoiceDescription, QuestionnaireChoices, QuestionnaireDescription, QuestionnaireError, QuestionnaireInput, QuestionnaireItem, QuestionnaireNext, QuestionnairePrevious, QuestionnaireProgress, QuestionnaireSkip, QuestionnaireSubmit, QuestionnaireTitle, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, type ResolvedThemeMode, ScrollArea, ScrollBar, SearchInput, type SearchInputProps, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarCollapseButton, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarLayout, type SidebarLayoutProps, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SignupForm, type SignupFormProps, type SignupValues, Skeleton, Slider, Sparkline, type SparklineProps, Spinner, StatCard, type StatCardProps, StatusBadge, type StatusBadgeProps, type StatusBarDatum, StatusBars, type StatusBarsProps, StatusDot, type StatusDotProps, type StatusTone, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, type ThemeContextValue, type ThemeMode, ThemeProvider, type ThemeProviderProps, ThemeScript, ThemeToggle, Timeline, type TimelineItem, Toaster, Toggle, ToggleGroup, ToggleGroupItem, ToolCall, type ToolCallProps, ToolGroup, type ToolGroupProps, type ToolStatus, ToolStatusIcon, ToolStep, type ToolStepProps, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Trace, TraceCollapsible, TraceCollapsibleContent, TraceCollapsibleTrigger, TraceDescription, TraceIcon, TraceLine, TraceTitle, TrendChart, type TrendChartProps, TrendLegend, type TrendSeries, TypingIndicator, type TypingIndicatorProps, UsageMeter, type UsageMeterProps, UserChip, type UserChipProps, UserMenu, type UserMenuProps, badgeVariants, buttonGroupVariants, buttonVariants, cn, createDataTableColumnHelper, dataTableFeatures, formatWhen, groupByDate, highlightCode, initials, loadHighlighter, markerVariants, navigationMenuTriggerStyle, smoothPath, tabsListVariants, toggleVariants, useCarousel, useComboboxAnchor, useCopyToClipboard, useDirection, useHighlightedCode, useIsMobile, useMediaQuery, useMessageScroller, useMessageScrollerScrollable, useMessageScrollerVisibility, useSidebar, useSidebarOptional, useTheme };
package/dist/index.js CHANGED
@@ -88,7 +88,7 @@ import { ApprovalCard, ApprovalResult } from "./components/ai/approval.js";
88
88
  import { ChatPanel, ChatShell } from "./components/ai/chat-shell.js";
89
89
  import { AssistantAvatar, ChatMessage, ChatThread, MessageActions, ToolCall, TypingIndicator } from "./components/ai/chat.js";
90
90
  import { CodeSnippet, InlineCode, Prose } from "./components/ai/code-block.js";
91
- import { ConversationList, NewConversationButton, groupByDate } from "./components/ai/conversation-list.js";
91
+ import { ConversationList, NewConversationButton, formatWhen, groupByDate } from "./components/ai/conversation-list.js";
92
92
  import { ModelPicker } from "./components/ai/model-picker.js";
93
93
  import { PromptInput, PromptInputChip, PromptInputSelect } from "./components/ai/prompt-input.js";
94
94
  import { ToolGroup, ToolStatusIcon, ToolStep } from "./components/ai/tool-steps.js";
@@ -99,4 +99,4 @@ import { useMediaQuery } from "./hooks/use-media-query.js";
99
99
  import { useIsMobile } from "./hooks/use-mobile.js";
100
100
  import { highlightCode, loadHighlighter } from "./lib/highlighter.js";
101
101
  import { cn } from "./lib/utils.js";
102
- export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActivityFeed, Alert, AlertAction, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppBrand, AppShell, AppleIcon, ApprovalCard, ApprovalResult, AspectRatio, AssistantAvatar, Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentGroup, AttachmentMedia, AttachmentTitle, AttachmentTrigger, AuthLayout, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, BarList, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Bubble, BubbleContent, BubbleGroup, BubbleReactions, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarDayButton, Callout, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, ChatMessage, ChatPanel, ChatShell, ChatThread, Checkbox, CodeBlock, CodeBlockActions, CodeBlockContent, CodeBlockCopyButton, CodeBlockFooter, CodeBlockHeader, CodeBlockLine, CodeBlockTitle, CodeSnippet, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, ComboboxTrigger, ComboboxValue, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, ConversationList, CopyField, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectionProvider, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, GitHubIcon, GoogleIcon, HoverCard, HoverCardContent, HoverCardTrigger, InlineCode, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, KeyValueGrid, Label, LinkTile, LoginForm, Marker, MarkerContent, MarkerIcon, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, Message, MessageActions, MessageAvatar, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, ModelPicker, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewConversationButton, PageHeader, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, PromptInput, PromptInputChip, PromptInputSelect, Prose, Questionnaire, QuestionnaireActions, QuestionnaireChoice, QuestionnaireChoiceDescription, QuestionnaireChoices, QuestionnaireDescription, QuestionnaireError, QuestionnaireInput, QuestionnaireItem, QuestionnaireNext, QuestionnairePrevious, QuestionnaireProgress, QuestionnaireSkip, QuestionnaireSubmit, QuestionnaireTitle, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, SearchInput, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarCollapseButton, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarLayout, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SignupForm, Skeleton, Slider, Sparkline, Spinner, StatCard, StatusBadge, StatusBars, StatusDot, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeProvider, ThemeScript, ThemeToggle, Timeline, Toaster, Toggle, ToggleGroup, ToggleGroupItem, ToolCall, ToolGroup, ToolStatusIcon, ToolStep, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Trace, TraceCollapsible, TraceCollapsibleContent, TraceCollapsibleTrigger, TraceDescription, TraceIcon, TraceLine, TraceTitle, TrendChart, TrendLegend, TypingIndicator, UsageMeter, UserChip, UserMenu, badgeVariants, buttonGroupVariants, buttonVariants, cn, createDataTableColumnHelper, dataTableFeatures, groupByDate, highlightCode, initials, loadHighlighter, markerVariants, navigationMenuTriggerStyle, smoothPath, tabsListVariants, toggleVariants, useCarousel, useComboboxAnchor, useCopyToClipboard, useDirection, useHighlightedCode, useIsMobile, useMediaQuery, useMessageScroller, useMessageScrollerScrollable, useMessageScrollerVisibility, useSidebar, useSidebarOptional, useTheme };
102
+ export { Accordion, AccordionContent, AccordionItem, AccordionTrigger, ActivityFeed, Alert, AlertAction, AlertDescription, AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogMedia, AlertDialogOverlay, AlertDialogPortal, AlertDialogTitle, AlertDialogTrigger, AlertTitle, AppBrand, AppShell, AppleIcon, ApprovalCard, ApprovalResult, AspectRatio, AssistantAvatar, Attachment, AttachmentAction, AttachmentActions, AttachmentContent, AttachmentDescription, AttachmentGroup, AttachmentMedia, AttachmentTitle, AttachmentTrigger, AuthLayout, Avatar, AvatarBadge, AvatarFallback, AvatarGroup, AvatarGroupCount, AvatarImage, Badge, BarList, Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator, Bubble, BubbleContent, BubbleGroup, BubbleReactions, Button, ButtonGroup, ButtonGroupSeparator, ButtonGroupText, Calendar, CalendarDayButton, Callout, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Carousel, CarouselContent, CarouselItem, CarouselNext, CarouselPrevious, ChartContainer, ChartLegend, ChartLegendContent, ChartStyle, ChartTooltip, ChartTooltipContent, ChatMessage, ChatPanel, ChatShell, ChatThread, Checkbox, CodeBlock, CodeBlockActions, CodeBlockContent, CodeBlockCopyButton, CodeBlockFooter, CodeBlockHeader, CodeBlockLine, CodeBlockTitle, CodeSnippet, Collapsible, CollapsibleContent, CollapsibleTrigger, Combobox, ComboboxChip, ComboboxChips, ComboboxChipsInput, ComboboxCollection, ComboboxContent, ComboboxEmpty, ComboboxGroup, ComboboxInput, ComboboxItem, ComboboxLabel, ComboboxList, ComboboxSeparator, ComboboxTrigger, ComboboxValue, Command, CommandDialog, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList, CommandSeparator, CommandShortcut, ConfirmDialog, ContextMenu, ContextMenuCheckboxItem, ContextMenuContent, ContextMenuGroup, ContextMenuItem, ContextMenuLabel, ContextMenuPortal, ContextMenuRadioGroup, ContextMenuRadioItem, ContextMenuSeparator, ContextMenuShortcut, ContextMenuSub, ContextMenuSubContent, ContextMenuSubTrigger, ContextMenuTrigger, ConversationList, CopyField, DataTable, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, DirectionProvider, Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger, DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, Empty, EmptyContent, EmptyDescription, EmptyHeader, EmptyMedia, EmptyTitle, Field, FieldContent, FieldDescription, FieldError, FieldGroup, FieldLabel, FieldLegend, FieldSeparator, FieldSet, FieldTitle, GitHubIcon, GoogleIcon, HoverCard, HoverCardContent, HoverCardTrigger, InlineCode, Input, InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGroupText, InputGroupTextarea, InputOTP, InputOTPGroup, InputOTPSeparator, InputOTPSlot, Item, ItemActions, ItemContent, ItemDescription, ItemFooter, ItemGroup, ItemHeader, ItemMedia, ItemSeparator, ItemTitle, Kbd, KbdGroup, KeyValueGrid, Label, LinkTile, LoginForm, Marker, MarkerContent, MarkerIcon, Menubar, MenubarCheckboxItem, MenubarContent, MenubarGroup, MenubarItem, MenubarLabel, MenubarMenu, MenubarPortal, MenubarRadioGroup, MenubarRadioItem, MenubarSeparator, MenubarShortcut, MenubarSub, MenubarSubContent, MenubarSubTrigger, MenubarTrigger, Message, MessageActions, MessageAvatar, MessageContent, MessageFooter, MessageGroup, MessageHeader, MessageScroller, MessageScrollerButton, MessageScrollerContent, MessageScrollerItem, MessageScrollerProvider, MessageScrollerViewport, ModelPicker, NativeSelect, NativeSelectOptGroup, NativeSelectOption, NavigationMenu, NavigationMenuContent, NavigationMenuIndicator, NavigationMenuItem, NavigationMenuLink, NavigationMenuList, NavigationMenuTrigger, NavigationMenuViewport, NewConversationButton, PageHeader, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Popover, PopoverAnchor, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger, Progress, PromptInput, PromptInputChip, PromptInputSelect, Prose, Questionnaire, QuestionnaireActions, QuestionnaireChoice, QuestionnaireChoiceDescription, QuestionnaireChoices, QuestionnaireDescription, QuestionnaireError, QuestionnaireInput, QuestionnaireItem, QuestionnaireNext, QuestionnairePrevious, QuestionnaireProgress, QuestionnaireSkip, QuestionnaireSubmit, QuestionnaireTitle, RadioGroup, RadioGroupItem, ResizableHandle, ResizablePanel, ResizablePanelGroup, ScrollArea, ScrollBar, SearchInput, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectScrollDownButton, SelectScrollUpButton, SelectSeparator, SelectTrigger, SelectValue, Separator, Sheet, SheetClose, SheetContent, SheetDescription, SheetFooter, SheetHeader, SheetTitle, SheetTrigger, Sidebar, SidebarCollapseButton, SidebarContent, SidebarFooter, SidebarGroup, SidebarGroupAction, SidebarGroupContent, SidebarGroupLabel, SidebarHeader, SidebarInput, SidebarInset, SidebarLayout, SidebarMenu, SidebarMenuAction, SidebarMenuBadge, SidebarMenuButton, SidebarMenuItem, SidebarMenuSkeleton, SidebarMenuSub, SidebarMenuSubButton, SidebarMenuSubItem, SidebarProvider, SidebarRail, SidebarSeparator, SidebarTrigger, SignupForm, Skeleton, Slider, Sparkline, Spinner, StatCard, StatusBadge, StatusBars, StatusDot, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsContent, TabsList, TabsTrigger, Textarea, ThemeProvider, ThemeScript, ThemeToggle, Timeline, Toaster, Toggle, ToggleGroup, ToggleGroupItem, ToolCall, ToolGroup, ToolStatusIcon, ToolStep, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, Trace, TraceCollapsible, TraceCollapsibleContent, TraceCollapsibleTrigger, TraceDescription, TraceIcon, TraceLine, TraceTitle, TrendChart, TrendLegend, TypingIndicator, UsageMeter, UserChip, UserMenu, badgeVariants, buttonGroupVariants, buttonVariants, cn, createDataTableColumnHelper, dataTableFeatures, formatWhen, groupByDate, highlightCode, initials, loadHighlighter, markerVariants, navigationMenuTriggerStyle, smoothPath, tabsListVariants, toggleVariants, useCarousel, useComboboxAnchor, useCopyToClipboard, useDirection, useHighlightedCode, useIsMobile, useMediaQuery, useMessageScroller, useMessageScrollerScrollable, useMessageScrollerVisibility, useSidebar, useSidebarOptional, useTheme };
@@ -38,70 +38,70 @@ Full working screens that combine these live in the repo under `playground/scree
38
38
 
39
39
  Every component in the shadcn registry is included. (shadcn's `form` item is an empty placeholder in the `radix-nova` style; use `Field`.) These are the shadcn/ui `radix-nova` components, restyled to the harebear tokens. API docs: https://ui.shadcn.com/docs/components. harebear-specific changes are noted.
40
40
 
41
- | Family | Exports | harebear notes |
42
- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
43
- | Accordion | `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent` | |
44
- | Alert | `Alert`, `AlertTitle`, `AlertDescription`, `AlertAction` | harebear adds `variant` `warning`, `success`, `info` (tinted, borderless). Descriptions wrap long words. |
45
- | Alert dialog | `AlertDialog`, `AlertDialogTrigger`, `AlertDialogContent`, `AlertDialogHeader`, `AlertDialogFooter`, `AlertDialogTitle`, `AlertDialogDescription`, `AlertDialogAction`, `AlertDialogCancel`, `AlertDialogMedia`, `AlertDialogOverlay`, `AlertDialogPortal` | Use for destructive confirmations. |
46
- | Aspect ratio | `AspectRatio` | |
47
- | Attachment | `Attachment`, `AttachmentGroup`, `AttachmentMedia`, `AttachmentContent`, `AttachmentTitle`, `AttachmentDescription`, `AttachmentActions`, `AttachmentAction`, `AttachmentTrigger` | File/image chips on messages and composers. `size`: `default`, `sm`, `xs`; `orientation`: `horizontal`, `vertical`. |
48
- | Avatar | `Avatar`, `AvatarImage`, `AvatarFallback`, `AvatarGroup`, `AvatarGroupCount`, `AvatarBadge` | `size`: `sm` 28px, `default` 36px, `lg` 56px. Fallback is tinted initials. |
49
- | 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). |
50
- | Bubble | `Bubble`, `BubbleGroup`, `BubbleContent`, `BubbleReactions` | Chat bubble. `variant`: `default` (primary), `secondary`, `muted`, `tinted`, `outline`, `ghost`, `destructive`; `align`: `start`, `end`. |
51
- | Breadcrumb | `Breadcrumb`, `BreadcrumbList`, `BreadcrumbItem`, `BreadcrumbLink`, `BreadcrumbPage`, `BreadcrumbSeparator`, `BreadcrumbEllipsis` | |
52
- | Button | `Button`, `buttonVariants` | 40px default. `variant`: `default`, `secondary`, `outline`, `ghost`, `soft`, `dashed`, `destructive`, `link`. `size`: `xs`, `sm` (32px), `default`, `lg`, `icon`, `icon-xs`, `icon-sm`, `icon-lg`. `shape`: `default`, `pill`. Icon-only buttons need `aria-label`. |
53
- | Button group | `ButtonGroup`, `ButtonGroupSeparator`, `ButtonGroupText`, `buttonGroupVariants` | |
54
- | Calendar | `Calendar`, `CalendarDayButton` | react-day-picker v10. Combine with `Popover` for a date picker. |
55
- | Card | `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardAction`, `CardContent`, `CardFooter` | Bordered, elevated (`shadow-card`), `rounded-xl`, 24px padding. `size="sm"` for 16px. `CardAction` puts a control top-right of the header. |
56
- | Code block | `CodeBlock`, `CodeBlockHeader`, `CodeBlockTitle`, `CodeBlockActions`, `CodeBlockCopyButton`, `CodeBlockContent`, `CodeBlockLine`, `CodeBlockFooter` | Composable code panel (muted fill). `CodeBlockContent` takes `lineNumbers`, `wrap`, `startLine`; `CodeBlockLine variant`: `added`, `removed`, `highlighted`. Pair with `useHighlightedCode` for shiki, or use `CodeSnippet`. |
57
- | Carousel | `Carousel`, `CarouselContent`, `CarouselItem`, `CarouselPrevious`, `CarouselNext`, `useCarousel`, type `CarouselApi` | embla. |
58
- | Chart | `ChartContainer`, `ChartTooltip`, `ChartTooltipContent`, `ChartLegend`, `ChartLegendContent`, `ChartStyle` | Recharts wrappers. Prefer `TrendChart` for line/area; use these for custom charts. |
59
- | Checkbox | `Checkbox` | |
60
- | Collapsible | `Collapsible`, `CollapsibleTrigger`, `CollapsibleContent` | |
61
- | 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
- | Command | `Command`, `CommandDialog`, `CommandInput`, `CommandList`, `CommandEmpty`, `CommandGroup`, `CommandItem`, `CommandShortcut`, `CommandSeparator` | Use for ⌘K palettes. |
63
- | Direction | `DirectionProvider`, `useDirection` | RTL/LTR context for Radix components. |
64
- | Context menu | `ContextMenu`, `ContextMenuTrigger`, `ContextMenuContent`, `ContextMenuItem`, `ContextMenuCheckboxItem`, `ContextMenuRadioItem`, `ContextMenuRadioGroup`, `ContextMenuLabel`, `ContextMenuSeparator`, `ContextMenuShortcut`, `ContextMenuGroup`, `ContextMenuPortal`, `ContextMenuSub`, `ContextMenuSubContent`, `ContextMenuSubTrigger` | |
65
- | Dialog | `Dialog`, `DialogTrigger`, `DialogContent`, `DialogHeader`, `DialogFooter`, `DialogTitle`, `DialogDescription`, `DialogClose`, `DialogOverlay`, `DialogPortal` | |
66
- | Drawer | `Drawer`, `DrawerTrigger`, `DrawerContent`, `DrawerHeader`, `DrawerFooter`, `DrawerTitle`, `DrawerDescription`, `DrawerClose`, `DrawerOverlay`, `DrawerPortal` | vaul. Mobile bottom sheets. |
67
- | Dropdown menu | `DropdownMenu`, `DropdownMenuTrigger`, `DropdownMenuContent`, `DropdownMenuItem`, `DropdownMenuCheckboxItem`, `DropdownMenuRadioGroup`, `DropdownMenuRadioItem`, `DropdownMenuLabel`, `DropdownMenuSeparator`, `DropdownMenuShortcut`, `DropdownMenuGroup`, `DropdownMenuPortal`, `DropdownMenuSub`, `DropdownMenuSubTrigger`, `DropdownMenuSubContent` | |
68
- | Empty state | `Empty`, `EmptyHeader`, `EmptyMedia`, `EmptyTitle`, `EmptyDescription`, `EmptyContent` | Use for zero-data screens. |
69
- | Field | `Field`, `FieldLabel`, `FieldDescription`, `FieldError`, `FieldGroup`, `FieldLegend`, `FieldSeparator`, `FieldSet`, `FieldContent`, `FieldTitle` | Form layout. Works with react-hook-form or plain state. |
70
- | Hover card | `HoverCard`, `HoverCardTrigger`, `HoverCardContent` | |
71
- | Input | `Input` | 40px, filled `bg-muted`, turns `bg-card` with a primary ring on focus. |
72
- | Input group | `InputGroup`, `InputGroupAddon`, `InputGroupButton`, `InputGroupText`, `InputGroupInput`, `InputGroupTextarea` | Inputs with icons, prefixes, buttons. |
73
- | Input OTP | `InputOTP`, `InputOTPGroup`, `InputOTPSlot`, `InputOTPSeparator` | |
74
- | Item | `Item`, `ItemMedia`, `ItemContent`, `ItemTitle`, `ItemDescription`, `ItemActions`, `ItemGroup`, `ItemSeparator`, `ItemHeader`, `ItemFooter` | Generic list rows. harebear fix: `ItemTitle` clamps to one line (long words break), `ItemContent` has `min-w-0`. |
75
- | Kbd | `Kbd`, `KbdGroup` | Mono keycap. |
76
- | Marker | `Marker`, `MarkerIcon`, `MarkerContent`, `markerVariants` | Inline status line in a thread ("Conversation saved"). `variant`: `default`, `separator` (date dividers), `border`. |
77
- | Label | `Label` | |
78
- | Menubar | `Menubar`, `MenubarMenu`, `MenubarTrigger`, `MenubarContent`, `MenubarItem`, `MenubarCheckboxItem`, `MenubarRadioGroup`, `MenubarRadioItem`, `MenubarLabel`, `MenubarSeparator`, `MenubarShortcut`, `MenubarGroup`, `MenubarPortal`, `MenubarSub`, `MenubarSubTrigger`, `MenubarSubContent` | |
79
- | Message | `Message`, `MessageGroup`, `MessageAvatar`, `MessageContent`, `MessageHeader`, `MessageFooter` | Chat message layout primitive. `align`: `start`, `end`. Put `Bubble`s inside `MessageContent`. |
80
- | Message scroller | `MessageScrollerProvider`, `MessageScroller`, `MessageScrollerViewport`, `MessageScrollerContent`, `MessageScrollerItem`, `MessageScrollerButton`, `useMessageScroller`, `useMessageScrollerScrollable`, `useMessageScrollerVisibility` | Stick-to-bottom scroll container with a jump-to-latest button. `ChatThread` is the simpler alternative. |
81
- | Navigation menu | `NavigationMenu`, `NavigationMenuList`, `NavigationMenuItem`, `NavigationMenuTrigger`, `NavigationMenuContent`, `NavigationMenuLink`, `NavigationMenuIndicator`, `NavigationMenuViewport`, `navigationMenuTriggerStyle` | Marketing-style top nav. |
82
- | Native select | `NativeSelect`, `NativeSelectOption`, `NativeSelectOptGroup` | Styled `<select>`; same filled look as `Input`. Use on mobile-heavy forms. |
83
- | Pagination | `Pagination`, `PaginationContent`, `PaginationItem`, `PaginationLink`, `PaginationPrevious`, `PaginationNext`, `PaginationEllipsis` | `DataTable` has its own pager. |
84
- | Popover | `Popover`, `PopoverTrigger`, `PopoverContent`, `PopoverAnchor`, `PopoverHeader`, `PopoverTitle`, `PopoverDescription` | |
85
- | Progress | `Progress` | 8px rounded meter. `UsageMeter` adds a label row. |
86
- | Questionnaire | `Questionnaire`, `QuestionnaireProgress`, `QuestionnaireItem`, `QuestionnaireTitle`, `QuestionnaireDescription`, `QuestionnaireChoices`, `QuestionnaireChoice`, `QuestionnaireChoiceDescription`, `QuestionnaireInput`, `QuestionnaireError`, `QuestionnaireActions`, `QuestionnairePrevious`, `QuestionnaireNext`, `QuestionnaireSkip`, `QuestionnaireSubmit` | Step-by-step multiple choice or input, one question at a time (e.g. an agent asking clarifying questions). `Questionnaire items={[{ name, required }]}`, each `QuestionnaireItem name` matches. |
87
- | Radio group | `RadioGroup`, `RadioGroupItem` | |
88
- | Resizable | `ResizablePanelGroup`, `ResizablePanel`, `ResizableHandle` | |
89
- | Scroll area | `ScrollArea`, `ScrollBar` | |
90
- | Select | `Select`, `SelectTrigger`, `SelectValue`, `SelectContent`, `SelectItem`, `SelectGroup`, `SelectLabel`, `SelectSeparator`, `SelectScrollUpButton`, `SelectScrollDownButton` | |
91
- | Separator | `Separator` | |
92
- | Sheet | `Sheet`, `SheetTrigger`, `SheetContent`, `SheetHeader`, `SheetFooter`, `SheetTitle`, `SheetDescription`, `SheetClose` | Side panels. |
93
- | Sidebar | `SidebarProvider`, `Sidebar`, `SidebarHeader`, `SidebarContent`, `SidebarFooter`, `SidebarGroup`, `SidebarGroupLabel`, `SidebarGroupAction`, `SidebarGroupContent`, `SidebarMenu`, `SidebarMenuItem`, `SidebarMenuButton`, `SidebarMenuAction`, `SidebarMenuBadge`, `SidebarMenuSkeleton`, `SidebarMenuSub`, `SidebarMenuSubItem`, `SidebarMenuSubButton`, `SidebarInput`, `SidebarInset`, `SidebarRail`, `SidebarSeparator`, `SidebarTrigger`, `useSidebar` | Active item is a raised card. Prefer `AppShell` unless you need a custom layout. harebear: no border by default (add `border-r` if you want one); in `collapsible="icon"` the content keeps its width while the rail widens. `useSidebarOptional()` returns null outside a provider. |
94
- | Skeleton | `Skeleton` | Loading placeholders. |
95
- | Slider | `Slider` | |
96
- | Spinner | `Spinner` | |
97
- | Switch | `Switch` | |
98
- | Table | `Table`, `TableHeader`, `TableBody`, `TableFooter`, `TableRow`, `TableHead`, `TableCell`, `TableCaption` | Borderless rows with rounded hover; quiet 12px headers. `data-state="selected"` tints a row. |
99
- | 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
- | Textarea | `Textarea` | Same filled style as `Input`, auto-grows. |
101
- | Toast | `Toaster` | sonner. Mount once; call `toast("Saved")` from `sonner`. Follows the theme mode. |
102
- | Toggle | `Toggle`, `toggleVariants`, `ToggleGroup`, `ToggleGroupItem` | |
103
- | Tooltip | `TooltipProvider`, `Tooltip`, `TooltipTrigger`, `TooltipContent` | Mount `TooltipProvider` once near the root. |
104
- | Trace | `Trace`, `TraceLine`, `TraceIcon`, `TraceTitle`, `TraceDescription`, `TraceCollapsible`, `TraceCollapsibleTrigger`, `TraceCollapsibleContent` | Agent step log (searched, read, ran). `TraceLine status`: `running` (shimmer), `error`, `pending`. |
41
+ | Family | Exports | harebear notes |
42
+ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
43
+ | Accordion | `Accordion`, `AccordionItem`, `AccordionTrigger`, `AccordionContent` | |
44
+ | Alert | `Alert`, `AlertTitle`, `AlertDescription`, `AlertAction` | harebear adds `variant` `warning`, `success`, `info` (tinted, borderless). Descriptions wrap long words. |
45
+ | Alert dialog | `AlertDialog`, `AlertDialogTrigger`, `AlertDialogContent`, `AlertDialogHeader`, `AlertDialogFooter`, `AlertDialogTitle`, `AlertDialogDescription`, `AlertDialogAction`, `AlertDialogCancel`, `AlertDialogMedia`, `AlertDialogOverlay`, `AlertDialogPortal` | Use for destructive confirmations. |
46
+ | Aspect ratio | `AspectRatio` | |
47
+ | Attachment | `Attachment`, `AttachmentGroup`, `AttachmentMedia`, `AttachmentContent`, `AttachmentTitle`, `AttachmentDescription`, `AttachmentActions`, `AttachmentAction`, `AttachmentTrigger` | File/image chips on messages and composers. `size`: `default`, `sm`, `xs`; `orientation`: `horizontal`, `vertical`. |
48
+ | Avatar | `Avatar`, `AvatarImage`, `AvatarFallback`, `AvatarGroup`, `AvatarGroupCount`, `AvatarBadge` | `size`: `sm` 28px, `default` 36px, `lg` 56px. Fallback is tinted initials. |
49
+ | 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`). |
50
+ | Bubble | `Bubble`, `BubbleGroup`, `BubbleContent`, `BubbleReactions` | Chat bubble. `variant`: `default` (primary), `secondary`, `muted`, `tinted`, `outline`, `ghost`, `destructive`; `align`: `start`, `end`. |
51
+ | Breadcrumb | `Breadcrumb`, `BreadcrumbList`, `BreadcrumbItem`, `BreadcrumbLink`, `BreadcrumbPage`, `BreadcrumbSeparator`, `BreadcrumbEllipsis` | |
52
+ | Button | `Button`, `buttonVariants` | 40px default. `variant`: `default`, `secondary`, `outline`, `ghost`, `soft`, `dashed`, `destructive`, `link`. `size`: `xs`, `sm` (32px), `default`, `lg`, `icon`, `icon-xs`, `icon-sm`, `icon-lg`. `shape`: `default`, `pill`. harebear adds `loading` (spinner, disabled, `aria-busy`; icon buttons swap the icon for the spinner). Icon-only buttons need `aria-label`. |
53
+ | Button group | `ButtonGroup`, `ButtonGroupSeparator`, `ButtonGroupText`, `buttonGroupVariants` | |
54
+ | Calendar | `Calendar`, `CalendarDayButton` | react-day-picker v10. Combine with `Popover` for a date picker. |
55
+ | Card | `Card`, `CardHeader`, `CardTitle`, `CardDescription`, `CardAction`, `CardContent`, `CardFooter` | Bordered, elevated (`shadow-card`), `rounded-xl`, 24px padding. `size="sm"` for 16px. `CardAction` puts a control top-right of the header. |
56
+ | Code block | `CodeBlock`, `CodeBlockHeader`, `CodeBlockTitle`, `CodeBlockActions`, `CodeBlockCopyButton`, `CodeBlockContent`, `CodeBlockLine`, `CodeBlockFooter` | Composable code panel (muted fill). `CodeBlockContent` takes `lineNumbers`, `wrap`, `startLine`; `CodeBlockLine variant`: `added`, `removed`, `highlighted`. Pair with `useHighlightedCode` for shiki, or use `CodeSnippet`. |
57
+ | Carousel | `Carousel`, `CarouselContent`, `CarouselItem`, `CarouselPrevious`, `CarouselNext`, `useCarousel`, type `CarouselApi` | embla. |
58
+ | Chart | `ChartContainer`, `ChartTooltip`, `ChartTooltipContent`, `ChartLegend`, `ChartLegendContent`, `ChartStyle` | Recharts wrappers. Prefer `TrendChart` for line/area; use these for custom charts. |
59
+ | Checkbox | `Checkbox` | |
60
+ | Collapsible | `Collapsible`, `CollapsibleTrigger`, `CollapsibleContent` | |
61
+ | 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
+ | Command | `Command`, `CommandDialog`, `CommandInput`, `CommandList`, `CommandEmpty`, `CommandGroup`, `CommandItem`, `CommandShortcut`, `CommandSeparator` | Use for ⌘K palettes. |
63
+ | Direction | `DirectionProvider`, `useDirection` | RTL/LTR context for Radix components. |
64
+ | Context menu | `ContextMenu`, `ContextMenuTrigger`, `ContextMenuContent`, `ContextMenuItem`, `ContextMenuCheckboxItem`, `ContextMenuRadioItem`, `ContextMenuRadioGroup`, `ContextMenuLabel`, `ContextMenuSeparator`, `ContextMenuShortcut`, `ContextMenuGroup`, `ContextMenuPortal`, `ContextMenuSub`, `ContextMenuSubContent`, `ContextMenuSubTrigger` | |
65
+ | Dialog | `Dialog`, `DialogTrigger`, `DialogContent`, `DialogHeader`, `DialogFooter`, `DialogTitle`, `DialogDescription`, `DialogClose`, `DialogOverlay`, `DialogPortal` | |
66
+ | Drawer | `Drawer`, `DrawerTrigger`, `DrawerContent`, `DrawerHeader`, `DrawerFooter`, `DrawerTitle`, `DrawerDescription`, `DrawerClose`, `DrawerOverlay`, `DrawerPortal` | vaul. Mobile bottom sheets. |
67
+ | Dropdown menu | `DropdownMenu`, `DropdownMenuTrigger`, `DropdownMenuContent`, `DropdownMenuItem`, `DropdownMenuCheckboxItem`, `DropdownMenuRadioGroup`, `DropdownMenuRadioItem`, `DropdownMenuLabel`, `DropdownMenuSeparator`, `DropdownMenuShortcut`, `DropdownMenuGroup`, `DropdownMenuPortal`, `DropdownMenuSub`, `DropdownMenuSubTrigger`, `DropdownMenuSubContent` | |
68
+ | Empty state | `Empty`, `EmptyHeader`, `EmptyMedia`, `EmptyTitle`, `EmptyDescription`, `EmptyContent` | Use for zero-data screens. harebear adds `size="sm"`: compact, no flex-grow, for empties inside cards and panels. |
69
+ | Field | `Field`, `FieldLabel`, `FieldDescription`, `FieldError`, `FieldGroup`, `FieldLegend`, `FieldSeparator`, `FieldSet`, `FieldContent`, `FieldTitle` | Form layout. Works with react-hook-form or plain state. |
70
+ | Hover card | `HoverCard`, `HoverCardTrigger`, `HoverCardContent` | |
71
+ | Input | `Input` | 40px, filled `bg-muted`, turns `bg-card` with a primary ring on focus. |
72
+ | Input group | `InputGroup`, `InputGroupAddon`, `InputGroupButton`, `InputGroupText`, `InputGroupInput`, `InputGroupTextarea` | Inputs with icons, prefixes, buttons. |
73
+ | Input OTP | `InputOTP`, `InputOTPGroup`, `InputOTPSlot`, `InputOTPSeparator` | |
74
+ | 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. |
75
+ | Kbd | `Kbd`, `KbdGroup` | Mono keycap. |
76
+ | Marker | `Marker`, `MarkerIcon`, `MarkerContent`, `markerVariants` | Inline status line in a thread ("Conversation saved"). `variant`: `default`, `separator` (date dividers), `border`. |
77
+ | Label | `Label` | |
78
+ | Menubar | `Menubar`, `MenubarMenu`, `MenubarTrigger`, `MenubarContent`, `MenubarItem`, `MenubarCheckboxItem`, `MenubarRadioGroup`, `MenubarRadioItem`, `MenubarLabel`, `MenubarSeparator`, `MenubarShortcut`, `MenubarGroup`, `MenubarPortal`, `MenubarSub`, `MenubarSubTrigger`, `MenubarSubContent` | |
79
+ | Message | `Message`, `MessageGroup`, `MessageAvatar`, `MessageContent`, `MessageHeader`, `MessageFooter` | Chat message layout primitive. `align`: `start`, `end`. Put `Bubble`s inside `MessageContent`. |
80
+ | Message scroller | `MessageScrollerProvider`, `MessageScroller`, `MessageScrollerViewport`, `MessageScrollerContent`, `MessageScrollerItem`, `MessageScrollerButton`, `useMessageScroller`, `useMessageScrollerScrollable`, `useMessageScrollerVisibility` | Stick-to-bottom scroll container with a jump-to-latest button. `ChatThread` is the simpler alternative. |
81
+ | Navigation menu | `NavigationMenu`, `NavigationMenuList`, `NavigationMenuItem`, `NavigationMenuTrigger`, `NavigationMenuContent`, `NavigationMenuLink`, `NavigationMenuIndicator`, `NavigationMenuViewport`, `navigationMenuTriggerStyle` | Marketing-style top nav. |
82
+ | Native select | `NativeSelect`, `NativeSelectOption`, `NativeSelectOptGroup` | Styled `<select>`; same filled look as `Input`. Use on mobile-heavy forms. |
83
+ | Pagination | `Pagination`, `PaginationContent`, `PaginationItem`, `PaginationLink`, `PaginationPrevious`, `PaginationNext`, `PaginationEllipsis` | `DataTable` has its own pager. |
84
+ | Popover | `Popover`, `PopoverTrigger`, `PopoverContent`, `PopoverAnchor`, `PopoverHeader`, `PopoverTitle`, `PopoverDescription` | |
85
+ | Progress | `Progress` | 8px rounded meter. `UsageMeter` adds a label row. |
86
+ | Questionnaire | `Questionnaire`, `QuestionnaireProgress`, `QuestionnaireItem`, `QuestionnaireTitle`, `QuestionnaireDescription`, `QuestionnaireChoices`, `QuestionnaireChoice`, `QuestionnaireChoiceDescription`, `QuestionnaireInput`, `QuestionnaireError`, `QuestionnaireActions`, `QuestionnairePrevious`, `QuestionnaireNext`, `QuestionnaireSkip`, `QuestionnaireSubmit` | Step-by-step multiple choice or input, one question at a time (e.g. an agent asking clarifying questions). `Questionnaire items={[{ name, required }]}`, each `QuestionnaireItem name` matches. |
87
+ | Radio group | `RadioGroup`, `RadioGroupItem` | |
88
+ | Resizable | `ResizablePanelGroup`, `ResizablePanel`, `ResizableHandle` | |
89
+ | Scroll area | `ScrollArea`, `ScrollBar` | |
90
+ | Select | `Select`, `SelectTrigger`, `SelectValue`, `SelectContent`, `SelectItem`, `SelectGroup`, `SelectLabel`, `SelectSeparator`, `SelectScrollUpButton`, `SelectScrollDownButton` | |
91
+ | Separator | `Separator` | |
92
+ | Sheet | `Sheet`, `SheetTrigger`, `SheetContent`, `SheetHeader`, `SheetFooter`, `SheetTitle`, `SheetDescription`, `SheetClose` | Side panels. |
93
+ | Sidebar | `SidebarProvider`, `Sidebar`, `SidebarHeader`, `SidebarContent`, `SidebarFooter`, `SidebarGroup`, `SidebarGroupLabel`, `SidebarGroupAction`, `SidebarGroupContent`, `SidebarMenu`, `SidebarMenuItem`, `SidebarMenuButton`, `SidebarMenuAction`, `SidebarMenuBadge`, `SidebarMenuSkeleton`, `SidebarMenuSub`, `SidebarMenuSubItem`, `SidebarMenuSubButton`, `SidebarInput`, `SidebarInset`, `SidebarRail`, `SidebarSeparator`, `SidebarTrigger`, `useSidebar` | Active item is a raised card. Prefer `AppShell` unless you need a custom layout. harebear: no border by default (add `border-r` if you want one); in `collapsible="icon"` the content keeps its width while the rail widens. `useSidebarOptional()` returns null outside a provider. |
94
+ | Skeleton | `Skeleton` | Loading placeholders. |
95
+ | Slider | `Slider` | |
96
+ | Spinner | `Spinner` | |
97
+ | Switch | `Switch` | |
98
+ | Table | `Table`, `TableHeader`, `TableBody`, `TableFooter`, `TableRow`, `TableHead`, `TableCell`, `TableCaption` | Borderless rows with rounded hover; quiet 12px headers. `data-state="selected"` tints a row. |
99
+ | 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
+ | Textarea | `Textarea` | Same filled style as `Input`, auto-grows. |
101
+ | Toast | `Toaster` | sonner. Mount once; call `toast("Saved")` from `sonner`. Follows the theme mode. |
102
+ | Toggle | `Toggle`, `toggleVariants`, `ToggleGroup`, `ToggleGroupItem` | |
103
+ | Tooltip | `TooltipProvider`, `Tooltip`, `TooltipTrigger`, `TooltipContent` | Mount `TooltipProvider` once near the root. |
104
+ | Trace | `Trace`, `TraceLine`, `TraceIcon`, `TraceTitle`, `TraceDescription`, `TraceCollapsible`, `TraceCollapsibleTrigger`, `TraceCollapsibleContent` | Agent step log (searched, read, ran). `TraceLine status`: `running` (shimmer), `error`, `pending`. |
105
105
 
106
106
  ## Admin and layout
107
107
 
@@ -191,7 +191,7 @@ Search field with icon. Props: all `<input>` props, `shortcut?` (display-only ke
191
191
 
192
192
  ### `StatusDot`, `StatusBadge`
193
193
 
194
- Dot or pill for status. Prop `tone`: `success | warning | danger | info | neutral`; `pulse` animates the dot for live states. `StatusBadge` takes Badge props (`variant="outline"` for a white pill, `size="lg"` in headers).
194
+ Dot or pill for status. Prop `tone`: `success | warning | danger | info | neutral`; `pulse` animates the dot for live states. `StatusBadge` takes Badge props (`variant="outline"` for a white pill, `size="lg"` in headers) and `compact` (below 640px only the dot shows; the label stays for screen readers).
195
195
 
196
196
  ### `UsageMeter`
197
197
 
@@ -327,7 +327,7 @@ Scrollable log that sticks to the bottom as content streams in (unless the user
327
327
 
328
328
  ### `ChatMessage`
329
329
 
330
- One turn. Props: `role: "user" | "assistant"` (matches AI SDK message roles), `avatar?` (assistant only, defaults to `AssistantAvatar`), `actions?` (assistant only, under the content), `variant?` (user bubble: `"muted"` default or `"soft"` accent tint), `children`. Long words wrap.
330
+ One turn. Props: `role: "user" | "assistant"` (matches AI SDK message roles), `avatar?` (assistant only, defaults to `AssistantAvatar`; `false` for none and full-width content, for agent threads where one turn is many blocks), `actions?` (assistant only, under the content), `variant?` (user bubble: `"muted"` default or `"soft"` accent tint), `children`. Long words wrap.
331
331
  User turns render as a right-aligned bubble with preserved newlines. Assistant turns render free-flowing: put `Prose`, `CodeBlock`, `ToolCall`, `TypingIndicator` inside.
332
332
 
333
333
  ```tsx
@@ -374,14 +374,15 @@ Composer chip that picks one mode from a menu (permission level, agent vs. ask).
374
374
 
375
375
  ### `ModelPicker`
376
376
 
377
- Pill showing the active model with a status dot, opening a menu. Props: `models: { id; label?; description?; status? }[]`, `value`, `onValueChange`, `label?`, `disabled?`.
377
+ Pill showing the active model with a status dot, opening a menu. Props: `models: { id; label?; description?; status?; group? }[]` (`group`, e.g. the provider, sections the menu), `value` (listed and checked even when missing from `models`), `onValueChange`, `label?`, `disabled?`.
378
378
 
379
379
  ### `ConversationList`
380
380
 
381
- Grouped thread list. Props: `groups: { label; items: Conversation[] }[]`, `activeId?`, `onSelect?(id)`, `renderAction?(conversation)` (trailing control, e.g. a delete button; on desktop it shows on hover/focus), `empty?`.
382
- `Conversation = { id; title; description?; tone?; pulse? }`: `description` is the second line (time, or a live state with a `tone` dot).
381
+ 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?`.
382
+ `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).
383
383
  Inside a `Sidebar` it closes the mobile sheet on select and hides in the icon rail.
384
384
  `groupByDate(items, getDate, toConversation, now?)` buckets items into Today / Yesterday / Previous 7 days / Earlier, newest first.
385
+ `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.
385
386
 
386
387
  ### `NewConversationButton`
387
388
 
@@ -410,13 +411,13 @@ Agent tool calls as a bordered, collapsible card. `ToolStatus = "queued" | "wait
410
411
 
411
412
  ### `ApprovalCard`, `ApprovalResult`
412
413
 
413
- `ApprovalCard`: warning-ringed card for anything the agent waits on the user for. Props: `title`, `description?`, `icon?` (default shield, `null` for none), `code?` + `codeLabel?` (wrapped code block with copy), `actions?` (buttons), `footer?`, `children` (body, e.g. the reason).
414
+ `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).
414
415
  `ApprovalResult`: one-line record in the thread. Props: `decision: "approved" | "denied"`, `time?`, `children`.
415
416
 
416
417
  ### `CodeSnippet`, `InlineCode`, `Prose`
417
418
 
418
419
  `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.
419
- `InlineCode`: monospace span.
420
+ `InlineCode`: monospace span. `truncate?: number` cuts longer string children with an ellipsis and puts the full text in the tooltip.
420
421
  `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`.
421
422
 
422
423
  ### Chat primitives vs. composites
package/llms.txt CHANGED
@@ -29,7 +29,7 @@
29
29
  Theme: ThemeProvider, useTheme, ThemeToggle, ThemeScript
30
30
  Layout/admin: SidebarLayout, SidebarCollapseButton, AppShell, AppBrand, PageHeader, StatCard, SearchInput, StatusDot, StatusBadge, UsageMeter, ActivityFeed, Timeline, KeyValueGrid, UserChip, UserMenu, Callout, LinkTile, ConfirmDialog, CopyField
31
31
  Data: DataTable, createDataTableColumnHelper, TrendChart, TrendLegend, BarList, Sparkline, StatusBars
32
- AI/chat composites: ChatShell, ChatPanel, ChatThread, ChatMessage, AssistantAvatar, MessageActions, PromptInput, PromptInputChip, PromptInputSelect, ModelPicker, ConversationList, NewConversationButton, groupByDate, ToolCall, ToolGroup, ToolStep, ToolStatusIcon, ApprovalCard, ApprovalResult, TypingIndicator, CodeSnippet, InlineCode, Prose
32
+ 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
33
33
  AI/chat primitives (shadcn): Message, Bubble, MessageScroller, Attachment, Trace, Marker, Questionnaire, CodeBlock
34
34
  Auth: AuthLayout, LoginForm, SignupForm, GitHubIcon, GoogleIcon, AppleIcon
35
35
  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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harebear-ui",
3
- "version": "0.5.0",
3
+ "version": "0.6.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",