harebear-ui 0.0.0-stage → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (198) hide show
  1. package/AGENTS.md +66 -0
  2. package/LICENSE +21 -0
  3. package/README.md +92 -2
  4. package/bin/harebear-ui.mjs +125 -0
  5. package/dist/components/admin/activity-feed.d.ts +15 -0
  6. package/dist/components/admin/activity-feed.js +50 -0
  7. package/dist/components/admin/app-shell.d.ts +47 -0
  8. package/dist/components/admin/app-shell.js +108 -0
  9. package/dist/components/admin/callout.d.ts +7 -0
  10. package/dist/components/admin/callout.js +18 -0
  11. package/dist/components/admin/key-value-grid.d.ts +11 -0
  12. package/dist/components/admin/key-value-grid.js +23 -0
  13. package/dist/components/admin/link-tile.d.ts +17 -0
  14. package/dist/components/admin/link-tile.js +36 -0
  15. package/dist/components/admin/page-header.d.ts +14 -0
  16. package/dist/components/admin/page-header.js +41 -0
  17. package/dist/components/admin/search-input.d.ts +12 -0
  18. package/dist/components/admin/search-input.js +32 -0
  19. package/dist/components/admin/stat-card.d.ts +20 -0
  20. package/dist/components/admin/stat-card.js +53 -0
  21. package/dist/components/admin/status.d.ts +12 -0
  22. package/dist/components/admin/status.js +32 -0
  23. package/dist/components/admin/timeline.d.ts +13 -0
  24. package/dist/components/admin/timeline.js +36 -0
  25. package/dist/components/admin/usage-meter.d.ts +17 -0
  26. package/dist/components/admin/usage-meter.js +43 -0
  27. package/dist/components/admin/user-chip.d.ts +14 -0
  28. package/dist/components/admin/user-chip.js +38 -0
  29. package/dist/components/ai/chat.d.ts +44 -0
  30. package/dist/components/ai/chat.js +151 -0
  31. package/dist/components/ai/code-block.d.ts +27 -0
  32. package/dist/components/ai/code-block.js +63 -0
  33. package/dist/components/ai/conversation-list.d.ts +18 -0
  34. package/dist/components/ai/conversation-list.js +30 -0
  35. package/dist/components/ai/model-picker.d.ts +21 -0
  36. package/dist/components/ai/model-picker.js +55 -0
  37. package/dist/components/ai/prompt-input.d.ts +27 -0
  38. package/dist/components/ai/prompt-input.js +99 -0
  39. package/dist/components/auth/auth.d.ts +85 -0
  40. package/dist/components/auth/auth.js +325 -0
  41. package/dist/components/data/bar-list.d.ts +14 -0
  42. package/dist/components/data/bar-list.js +27 -0
  43. package/dist/components/data/data-table.d.ts +70 -0
  44. package/dist/components/data/data-table.js +208 -0
  45. package/dist/components/data/sparkline.d.ts +16 -0
  46. package/dist/components/data/sparkline.js +72 -0
  47. package/dist/components/data/status-bars.d.ts +17 -0
  48. package/dist/components/data/status-bars.js +37 -0
  49. package/dist/components/data/trend-chart.d.ts +31 -0
  50. package/dist/components/data/trend-chart.js +136 -0
  51. package/dist/components/theme/theme-provider.d.ts +42 -0
  52. package/dist/components/theme/theme-provider.js +110 -0
  53. package/dist/components/theme/theme-toggle.d.ts +5 -0
  54. package/dist/components/theme/theme-toggle.js +21 -0
  55. package/dist/components/ui/accordion.d.ts +7 -0
  56. package/dist/components/ui/accordion.js +53 -0
  57. package/dist/components/ui/alert-dialog.d.ts +18 -0
  58. package/dist/components/ui/alert-dialog.js +99 -0
  59. package/dist/components/ui/alert.d.ts +10 -0
  60. package/dist/components/ui/alert.js +42 -0
  61. package/dist/components/ui/aspect-ratio.d.ts +3 -0
  62. package/dist/components/ui/aspect-ratio.js +11 -0
  63. package/dist/components/ui/attachment.d.ts +24 -0
  64. package/dist/components/ui/attachment.js +100 -0
  65. package/dist/components/ui/avatar.d.ts +11 -0
  66. package/dist/components/ui/avatar.js +49 -0
  67. package/dist/components/ui/badge.d.ts +9 -0
  68. package/dist/components/ui/badge.js +30 -0
  69. package/dist/components/ui/breadcrumb.d.ts +11 -0
  70. package/dist/components/ui/breadcrumb.js +70 -0
  71. package/dist/components/ui/bubble.d.ts +17 -0
  72. package/dist/components/ui/bubble.js +71 -0
  73. package/dist/components/ui/button-group.d.ts +11 -0
  74. package/dist/components/ui/button-group.js +39 -0
  75. package/dist/components/ui/button.d.ts +11 -0
  76. package/dist/components/ui/button.js +55 -0
  77. package/dist/components/ui/calendar.d.ts +10 -0
  78. package/dist/components/ui/calendar.js +108 -0
  79. package/dist/components/ui/card.d.ts +11 -0
  80. package/dist/components/ui/card.js +55 -0
  81. package/dist/components/ui/carousel.d.ts +28 -0
  82. package/dist/components/ui/carousel.js +131 -0
  83. package/dist/components/ui/chart.d.ts +44 -0
  84. package/dist/components/ui/chart.js +148 -0
  85. package/dist/components/ui/checkbox.d.ts +4 -0
  86. package/dist/components/ui/checkbox.js +19 -0
  87. package/dist/components/ui/code-block.d.ts +26 -0
  88. package/dist/components/ui/code-block.js +123 -0
  89. package/dist/components/ui/collapsible.d.ts +5 -0
  90. package/dist/components/ui/collapsible.js +23 -0
  91. package/dist/components/ui/combobox.d.ts +24 -0
  92. package/dist/components/ui/combobox.js +162 -0
  93. package/dist/components/ui/command.d.ts +18 -0
  94. package/dist/components/ui/command.js +86 -0
  95. package/dist/components/ui/context-menu.d.ts +31 -0
  96. package/dist/components/ui/context-menu.js +123 -0
  97. package/dist/components/ui/dialog.d.ts +17 -0
  98. package/dist/components/ui/dialog.js +94 -0
  99. package/dist/components/ui/direction.d.ts +7 -0
  100. package/dist/components/ui/direction.js +12 -0
  101. package/dist/components/ui/drawer.d.ts +13 -0
  102. package/dist/components/ui/drawer.js +76 -0
  103. package/dist/components/ui/dropdown-menu.d.ts +29 -0
  104. package/dist/components/ui/dropdown-menu.js +126 -0
  105. package/dist/components/ui/empty.d.ts +11 -0
  106. package/dist/components/ui/empty.js +59 -0
  107. package/dist/components/ui/field.d.ts +24 -0
  108. package/dist/components/ui/field.js +109 -0
  109. package/dist/components/ui/hover-card.d.ts +6 -0
  110. package/dist/components/ui/hover-card.js +30 -0
  111. package/dist/components/ui/input-group.d.ts +16 -0
  112. package/dist/components/ui/input-group.js +77 -0
  113. package/dist/components/ui/input-otp.d.ts +11 -0
  114. package/dist/components/ui/input-otp.js +46 -0
  115. package/dist/components/ui/input.d.ts +3 -0
  116. package/dist/components/ui/input.js +13 -0
  117. package/dist/components/ui/item.d.ts +23 -0
  118. package/dist/components/ui/item.js +117 -0
  119. package/dist/components/ui/kbd.d.ts +3 -0
  120. package/dist/components/ui/kbd.js +19 -0
  121. package/dist/components/ui/label.d.ts +4 -0
  122. package/dist/components/ui/label.js +13 -0
  123. package/dist/components/ui/marker.d.ts +11 -0
  124. package/dist/components/ui/marker.js +39 -0
  125. package/dist/components/ui/menubar.d.ts +30 -0
  126. package/dist/components/ui/menubar.js +133 -0
  127. package/dist/components/ui/message-scroller.d.ts +10 -0
  128. package/dist/components/ui/message-scroller.js +59 -0
  129. package/dist/components/ui/message.d.ts +10 -0
  130. package/dist/components/ui/message.js +48 -0
  131. package/dist/components/ui/native-select.d.ts +8 -0
  132. package/dist/components/ui/native-select.js +37 -0
  133. package/dist/components/ui/navigation-menu.d.ts +14 -0
  134. package/dist/components/ui/navigation-menu.js +79 -0
  135. package/dist/components/ui/pagination.d.ts +17 -0
  136. package/dist/components/ui/pagination.js +79 -0
  137. package/dist/components/ui/popover.d.ts +10 -0
  138. package/dist/components/ui/popover.js +54 -0
  139. package/dist/components/ui/progress.d.ts +4 -0
  140. package/dist/components/ui/progress.js +18 -0
  141. package/dist/components/ui/questionnaire.d.ts +19 -0
  142. package/dist/components/ui/questionnaire.js +168 -0
  143. package/dist/components/ui/radio-group.d.ts +5 -0
  144. package/dist/components/ui/radio-group.js +25 -0
  145. package/dist/components/ui/resizable.d.ts +7 -0
  146. package/dist/components/ui/resizable.js +27 -0
  147. package/dist/components/ui/scroll-area.d.ts +5 -0
  148. package/dist/components/ui/scroll-area.js +35 -0
  149. package/dist/components/ui/select.d.ts +15 -0
  150. package/dist/components/ui/select.js +98 -0
  151. package/dist/components/ui/separator.d.ts +4 -0
  152. package/dist/components/ui/separator.js +15 -0
  153. package/dist/components/ui/sheet.d.ts +14 -0
  154. package/dist/components/ui/sheet.js +88 -0
  155. package/dist/components/ui/sidebar.d.ts +69 -0
  156. package/dist/components/ui/sidebar.js +377 -0
  157. package/dist/components/ui/skeleton.d.ts +2 -0
  158. package/dist/components/ui/skeleton.js +12 -0
  159. package/dist/components/ui/slider.d.ts +4 -0
  160. package/dist/components/ui/slider.js +35 -0
  161. package/dist/components/ui/sonner.d.ts +3 -0
  162. package/dist/components/ui/sonner.js +29 -0
  163. package/dist/components/ui/spinner.d.ts +2 -0
  164. package/dist/components/ui/spinner.js +15 -0
  165. package/dist/components/ui/switch.d.ts +6 -0
  166. package/dist/components/ui/switch.js +18 -0
  167. package/dist/components/ui/table.d.ts +10 -0
  168. package/dist/components/ui/table.js +65 -0
  169. package/dist/components/ui/tabs.d.ts +11 -0
  170. package/dist/components/ui/tabs.js +45 -0
  171. package/dist/components/ui/textarea.d.ts +3 -0
  172. package/dist/components/ui/textarea.js +12 -0
  173. package/dist/components/ui/toggle-group.d.ts +10 -0
  174. package/dist/components/ui/toggle-group.js +50 -0
  175. package/dist/components/ui/toggle.d.ts +9 -0
  176. package/dist/components/ui/toggle.js +35 -0
  177. package/dist/components/ui/tooltip.d.ts +7 -0
  178. package/dist/components/ui/tooltip.js +34 -0
  179. package/dist/components/ui/trace.d.ts +18 -0
  180. package/dist/components/ui/trace.js +74 -0
  181. package/dist/hooks/use-copy-to-clipboard.d.ts +5 -0
  182. package/dist/hooks/use-copy-to-clipboard.js +24 -0
  183. package/dist/hooks/use-highlighted-code.d.ts +2 -0
  184. package/dist/hooks/use-highlighted-code.js +54 -0
  185. package/dist/hooks/use-mobile.d.ts +1 -0
  186. package/dist/hooks/use-mobile.js +17 -0
  187. package/dist/index.d.ts +94 -0
  188. package/dist/index.js +94 -0
  189. package/dist/lib/highlighter.d.ts +9 -0
  190. package/dist/lib/highlighter.js +77 -0
  191. package/dist/lib/utils.d.ts +3 -0
  192. package/dist/lib/utils.js +8 -0
  193. package/dist/shadcn-base.css +638 -0
  194. package/dist/styles.css +188 -0
  195. package/docs/COMPONENTS.md +405 -0
  196. package/llms.txt +36 -0
  197. package/package.json +119 -4
  198. package/skills/harebear-ui/SKILL.md +34 -0
@@ -0,0 +1,63 @@
1
+ "use client";
2
+ import { Button } from "../ui/button.js";
3
+ import { CodeBlock, CodeBlockContent, CodeBlockHeader, CodeBlockLine, CodeBlockTitle } from "../ui/code-block.js";
4
+ import { useCopyToClipboard } from "../../hooks/use-copy-to-clipboard.js";
5
+ import { useHighlightedCode } from "../../hooks/use-highlighted-code.js";
6
+ import { cn } from "../../lib/utils.js";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ import { CheckIcon, CopyIcon } from "lucide-react";
9
+ // src/components/ai/code-block.tsx
10
+ /**
11
+ * One-prop code panel: language label, copy button, shiki highlighting (loaded
12
+ * lazily per language). Built on the CodeBlock primitives; use those directly
13
+ * for diffs, highlighted lines, or custom headers.
14
+ */
15
+ function CodeSnippet({ code, language, highlight = true, lineNumbers, hideCopy, className, ...props }) {
16
+ const { copied, copy } = useCopyToClipboard();
17
+ const lines = useHighlightedCode(code, highlight && language ? language : "text");
18
+ return /* @__PURE__ */ jsxs(CodeBlock, {
19
+ "data-slot": "code-snippet",
20
+ className,
21
+ ...props,
22
+ children: [(language || !hideCopy) && /* @__PURE__ */ jsxs(CodeBlockHeader, {
23
+ className: "min-h-10",
24
+ children: [/* @__PURE__ */ jsx(CodeBlockTitle, {
25
+ className: "font-mono text-xs text-muted-foreground",
26
+ children: language
27
+ }), !hideCopy && /* @__PURE__ */ jsxs(Button, {
28
+ type: "button",
29
+ variant: "ghost",
30
+ size: "sm",
31
+ className: "ms-auto",
32
+ onClick: () => copy(code),
33
+ "aria-label": "Copy code",
34
+ children: [copied ? /* @__PURE__ */ jsx(CheckIcon, {}) : /* @__PURE__ */ jsx(CopyIcon, {}), copied ? "Copied" : "Copy"]
35
+ })]
36
+ }), /* @__PURE__ */ jsx(CodeBlockContent, {
37
+ lineNumbers,
38
+ className: "pb-4.5",
39
+ children: lines.map((line, i) => /* @__PURE__ */ jsx(CodeBlockLine, { children: line }, i))
40
+ })]
41
+ });
42
+ }
43
+ /** Inline monospace span for commands and identifiers. */
44
+ function InlineCode({ className, ...props }) {
45
+ return /* @__PURE__ */ jsx("code", {
46
+ "data-slot": "inline-code",
47
+ className: cn("rounded-[6px] bg-muted px-1.5 py-0.5 font-mono text-[12.5px]", className),
48
+ ...props
49
+ });
50
+ }
51
+ /**
52
+ * Typography for long-form and model output. Styles plain HTML children
53
+ * (p, ul, ol, li, strong, a, code, pre, h1-h4, blockquote, table), so it works
54
+ * with react-markdown or any HTML renderer.
55
+ */
56
+ function Prose({ className, ...props }) {
57
+ return /* @__PURE__ */ jsx("div", {
58
+ "data-slot": "prose",
59
+ className: cn("flex flex-col gap-3.5 text-[15px] leading-[1.65] text-foreground", "[&_ol]:flex [&_ol]:list-decimal [&_ol]:flex-col [&_ol]:gap-2 [&_ol]:pl-5.5", "[&_ul]:flex [&_ul]:list-disc [&_ul]:flex-col [&_ul]:gap-2 [&_ul]:pl-5.5", "[&_strong]:font-semibold [&_a]:text-primary [&_a]:underline-offset-4 hover:[&_a]:underline", "[&_h1]:text-xl [&_h1]:font-semibold [&_h2]:text-lg [&_h2]:font-semibold [&_h3]:font-semibold [&_h4]:font-semibold", "[&_blockquote]:border-l-2 [&_blockquote]:pl-4 [&_blockquote]:text-muted-foreground", "[&_:not(pre)>code]:rounded-[6px] [&_:not(pre)>code]:bg-muted [&_:not(pre)>code]:px-1.5 [&_:not(pre)>code]:py-0.5 [&_:not(pre)>code]:font-mono [&_:not(pre)>code]:text-[12.5px]", "[&_pre]:overflow-x-auto [&_pre]:rounded-lg [&_pre]:bg-muted [&_pre]:p-4.5 [&_pre]:font-mono [&_pre]:text-[13px]", "[&_table]:w-full [&_table]:text-sm [&_td]:border-b [&_td]:py-2 [&_th]:border-b [&_th]:py-2 [&_th]:text-left [&_th]:font-medium", className),
60
+ ...props
61
+ });
62
+ }
63
+ export { CodeSnippet, InlineCode, Prose };
@@ -0,0 +1,18 @@
1
+ import * as React from "react";
2
+ export interface Conversation {
3
+ id: string;
4
+ title: string;
5
+ }
6
+ export interface ConversationGroup {
7
+ /** e.g. "Today", "Yesterday", "Previous 7 days". */
8
+ label: string;
9
+ items: Conversation[];
10
+ }
11
+ export interface ConversationListProps extends Omit<React.ComponentProps<"nav">, "onSelect"> {
12
+ groups: ConversationGroup[];
13
+ activeId?: string;
14
+ onSelect?: (id: string) => void;
15
+ }
16
+ /** Grouped list of chat threads for a sidebar. */
17
+ declare function ConversationList({ groups, activeId, onSelect, className, ...props }: ConversationListProps): React.JSX.Element;
18
+ export { ConversationList };
@@ -0,0 +1,30 @@
1
+ "use client";
2
+ import { cn } from "../../lib/utils.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ // src/components/ai/conversation-list.tsx
5
+ /** Grouped list of chat threads for a sidebar. */
6
+ function ConversationList({ groups, activeId, onSelect, className, ...props }) {
7
+ return /* @__PURE__ */ jsx("nav", {
8
+ "data-slot": "conversation-list",
9
+ "aria-label": "Conversations",
10
+ className: cn("flex flex-col gap-4.5", className),
11
+ ...props,
12
+ children: groups.map((g) => /* @__PURE__ */ jsxs("div", {
13
+ className: "flex flex-col gap-0.5",
14
+ children: [/* @__PURE__ */ jsx("div", {
15
+ className: "px-3 pb-1.5 text-xs font-medium text-muted-foreground",
16
+ children: g.label
17
+ }), g.items.map((c) => {
18
+ const active = c.id === activeId;
19
+ return /* @__PURE__ */ jsx("button", {
20
+ type: "button",
21
+ "aria-current": active ? "page" : void 0,
22
+ onClick: () => onSelect?.(c.id),
23
+ className: cn("w-full truncate rounded-md px-3 py-2.25 text-left font-medium text-muted-foreground transition-colors outline-none hover:bg-muted hover:text-foreground focus-visible:ring-2 focus-visible:ring-ring/40", active && "bg-card text-foreground shadow-card hover:bg-card"),
24
+ children: c.title
25
+ }, c.id);
26
+ })]
27
+ }, g.label))
28
+ });
29
+ }
30
+ export { ConversationList };
@@ -0,0 +1,21 @@
1
+ import { StatusTone } from "../admin/status.js";
2
+ import * as React from "react";
3
+ export interface ModelOption {
4
+ id: string;
5
+ /** Display name. Defaults to id. Rendered monospace. */
6
+ label?: string;
7
+ description?: React.ReactNode;
8
+ /** Availability dot. Default "success". */
9
+ status?: StatusTone;
10
+ }
11
+ export interface ModelPickerProps {
12
+ models: ModelOption[];
13
+ value: string;
14
+ onValueChange: (id: string) => void;
15
+ label?: React.ReactNode;
16
+ className?: string;
17
+ disabled?: boolean;
18
+ }
19
+ /** Pill button showing the active model with a status dot; opens a menu of models. */
20
+ declare function ModelPicker({ models, value, onValueChange, label, className, disabled }: ModelPickerProps): React.JSX.Element;
21
+ export { ModelPicker };
@@ -0,0 +1,55 @@
1
+ "use client";
2
+ import { StatusDot } from "../admin/status.js";
3
+ import { Button } from "../ui/button.js";
4
+ import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuLabel, DropdownMenuTrigger } from "../ui/dropdown-menu.js";
5
+ import { cn } from "../../lib/utils.js";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import { CheckIcon, ChevronDownIcon } from "lucide-react";
8
+ // src/components/ai/model-picker.tsx
9
+ /** Pill button showing the active model with a status dot; opens a menu of models. */
10
+ function ModelPicker({ models, value, onValueChange, label = "Model", className, disabled }) {
11
+ const current = models.find((m) => m.id === value);
12
+ return /* @__PURE__ */ jsxs(DropdownMenu, { children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, {
13
+ asChild: true,
14
+ disabled,
15
+ children: /* @__PURE__ */ jsxs(Button, {
16
+ variant: "outline",
17
+ size: "sm",
18
+ shape: "pill",
19
+ className: cn("gap-2 px-3", className),
20
+ children: [
21
+ /* @__PURE__ */ jsx(StatusDot, { tone: current?.status ?? "success" }),
22
+ /* @__PURE__ */ jsx("span", {
23
+ className: "font-mono text-xs",
24
+ children: current?.label ?? value
25
+ }),
26
+ /* @__PURE__ */ jsx(ChevronDownIcon, { className: "text-muted-foreground" })
27
+ ]
28
+ })
29
+ }), /* @__PURE__ */ jsxs(DropdownMenuContent, {
30
+ align: "end",
31
+ 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))]
53
+ })] });
54
+ }
55
+ export { ModelPicker };
@@ -0,0 +1,27 @@
1
+ import { Button } from "../ui/button.js";
2
+ import * as React from "react";
3
+ export interface PromptInputProps extends Omit<React.ComponentProps<"form">, "onSubmit" | "onChange"> {
4
+ value: string;
5
+ onValueChange: (value: string) => void;
6
+ /** Called with the trimmed text on Enter or the send button. Shift+Enter inserts a newline. */
7
+ onSubmit: (value: string) => void;
8
+ placeholder?: string;
9
+ /** While true, the send button becomes a stop button. */
10
+ loading?: boolean;
11
+ onStop?: () => void;
12
+ /** Shows a paperclip button. */
13
+ onAttach?: () => void;
14
+ /** Chips/toggles between the attach and send buttons, e.g. <PromptInputChip>. */
15
+ tools?: React.ReactNode;
16
+ /** Small text under the box, e.g. a disclaimer. */
17
+ footer?: React.ReactNode;
18
+ disabled?: boolean;
19
+ autoFocus?: boolean;
20
+ }
21
+ /** Chat composer: auto-growing textarea with attach, tool chips, and send/stop. */
22
+ declare function PromptInput({ value, onValueChange, onSubmit, placeholder, loading, onStop, onAttach, tools, footer, disabled, autoFocus, className, ...props }: PromptInputProps): React.JSX.Element;
23
+ /** Toggleable pill for the composer toolbar (web search, a knowledge source…). */
24
+ declare function PromptInputChip({ active, className, ...props }: React.ComponentProps<typeof Button> & {
25
+ active?: boolean;
26
+ }): React.JSX.Element;
27
+ export { PromptInput, PromptInputChip };
@@ -0,0 +1,99 @@
1
+ "use client";
2
+ import { Button } from "../ui/button.js";
3
+ import { cn } from "../../lib/utils.js";
4
+ import * as React from "react";
5
+ import { jsx, jsxs } from "react/jsx-runtime";
6
+ import { ArrowUpIcon, PaperclipIcon, SquareIcon } from "lucide-react";
7
+ // src/components/ai/prompt-input.tsx
8
+ /** Chat composer: auto-growing textarea with attach, tool chips, and send/stop. */
9
+ function PromptInput({ value, onValueChange, onSubmit, placeholder = "Send a message…", loading, onStop, onAttach, tools, footer, disabled, autoFocus, className, ...props }) {
10
+ const id = React.useId();
11
+ const canSend = value.trim().length > 0 && !disabled;
12
+ const submit = () => {
13
+ if (canSend && !loading) onSubmit(value.trim());
14
+ };
15
+ return /* @__PURE__ */ jsxs("form", {
16
+ "data-slot": "prompt-input",
17
+ className: cn("mx-auto flex w-full max-w-190 flex-col gap-2.5", className),
18
+ onSubmit: (e) => {
19
+ e.preventDefault();
20
+ submit();
21
+ },
22
+ ...props,
23
+ children: [/* @__PURE__ */ jsxs("div", {
24
+ className: "flex flex-col gap-2 rounded-[calc(var(--radius-xl)*1.2)] bg-muted pt-3 pr-3 pb-2.5 pl-3.5 transition-shadow focus-within:ring-4 focus-within:ring-primary/12",
25
+ children: [
26
+ /* @__PURE__ */ jsx("label", {
27
+ htmlFor: id,
28
+ className: "sr-only",
29
+ children: "Message"
30
+ }),
31
+ /* @__PURE__ */ jsx("textarea", {
32
+ id,
33
+ rows: 2,
34
+ value,
35
+ disabled,
36
+ autoFocus,
37
+ placeholder,
38
+ onChange: (e) => onValueChange(e.target.value),
39
+ onKeyDown: (e) => {
40
+ if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
41
+ e.preventDefault();
42
+ submit();
43
+ }
44
+ },
45
+ className: "field-sizing-content max-h-60 min-h-13 w-full resize-none border-0 bg-transparent px-1.5 py-1 text-[15px] leading-normal text-foreground outline-none placeholder:text-muted-foreground"
46
+ }),
47
+ /* @__PURE__ */ jsxs("div", {
48
+ className: "flex items-center gap-1.5",
49
+ children: [
50
+ onAttach && /* @__PURE__ */ jsx(Button, {
51
+ type: "button",
52
+ variant: "ghost",
53
+ size: "icon-sm",
54
+ shape: "pill",
55
+ "aria-label": "Attach file",
56
+ onClick: onAttach,
57
+ children: /* @__PURE__ */ jsx(PaperclipIcon, {})
58
+ }),
59
+ tools,
60
+ /* @__PURE__ */ jsx("div", { className: "flex-1" }),
61
+ loading && onStop ? /* @__PURE__ */ jsx(Button, {
62
+ type: "button",
63
+ size: "icon",
64
+ shape: "pill",
65
+ className: "size-9",
66
+ "aria-label": "Stop generating",
67
+ onClick: onStop,
68
+ children: /* @__PURE__ */ jsx(SquareIcon, { className: "fill-current" })
69
+ }) : /* @__PURE__ */ jsx(Button, {
70
+ type: "submit",
71
+ size: "icon",
72
+ shape: "pill",
73
+ className: "size-9",
74
+ "aria-label": "Send message",
75
+ disabled: !canSend || loading,
76
+ children: /* @__PURE__ */ jsx(ArrowUpIcon, {})
77
+ })
78
+ ]
79
+ })
80
+ ]
81
+ }), footer && /* @__PURE__ */ jsx("p", {
82
+ className: "text-center text-xs text-muted-foreground",
83
+ children: footer
84
+ })]
85
+ });
86
+ }
87
+ /** Toggleable pill for the composer toolbar (web search, a knowledge source…). */
88
+ function PromptInputChip({ active, className, ...props }) {
89
+ return /* @__PURE__ */ jsx(Button, {
90
+ type: "button",
91
+ size: "sm",
92
+ shape: "pill",
93
+ variant: active ? "soft" : "outline",
94
+ "aria-pressed": active,
95
+ className: cn("h-8", className),
96
+ ...props
97
+ });
98
+ }
99
+ export { PromptInput, PromptInputChip };
@@ -0,0 +1,85 @@
1
+ import * as React from "react";
2
+ export interface AuthLayoutProps {
3
+ /**
4
+ * - "centered": form in a card, centered on the page (shadcn login-01 / signup-01)
5
+ * - "muted": same on a muted page background (login-03 / signup-03)
6
+ * - "split": two columns, form left and a cover image right; no card (login-02 / signup-02)
7
+ * - "card-image": one wide card with the form and an image side by side (login-04 / signup-04)
8
+ */
9
+ variant?: "centered" | "muted" | "split" | "card-image";
10
+ /** Logo/product name shown above the form (top-left in "split"). Usually <AppBrand />. */
11
+ brand?: React.ReactNode;
12
+ /** Cover image for "split" and "card-image". */
13
+ image?: {
14
+ src: string;
15
+ alt: string;
16
+ };
17
+ /** Small print under the form, e.g. terms links. */
18
+ footer?: React.ReactNode;
19
+ className?: string;
20
+ children: React.ReactNode;
21
+ }
22
+ /** Full-page wrapper for sign-in and sign-up screens. Put LoginForm or SignupForm inside. */
23
+ declare function AuthLayout({ variant, brand, image, footer, className, children }: AuthLayoutProps): React.JSX.Element;
24
+ export interface AuthProvider {
25
+ /** Passed to onProviderClick, e.g. "github". */
26
+ id: string;
27
+ /** Display name, e.g. "GitHub". */
28
+ label: string;
29
+ icon?: React.ReactNode;
30
+ }
31
+ /** GitHub mark, for AuthProvider icons. */
32
+ declare function GitHubIcon(props: React.ComponentProps<"svg">): React.JSX.Element;
33
+ declare function GoogleIcon(props: React.ComponentProps<"svg">): React.JSX.Element;
34
+ /** Apple mark, for AuthProvider icons. */
35
+ declare function AppleIcon(props: React.ComponentProps<"svg">): React.JSX.Element;
36
+ interface AuthFormBase extends Omit<React.ComponentProps<"form">, "onSubmit" | "title"> {
37
+ title?: React.ReactNode;
38
+ description?: React.ReactNode;
39
+ /** Social/SSO buttons shown under the main button. */
40
+ providers?: AuthProvider[];
41
+ onProviderClick?: (id: string) => void;
42
+ /** Shows a spinner on the submit button and disables the form. */
43
+ loading?: boolean;
44
+ /** Form-level error, e.g. "Invalid email or password". */
45
+ error?: React.ReactNode;
46
+ /** Put the provider buttons above the email form instead of below. */
47
+ providersFirst?: boolean;
48
+ }
49
+ export interface LoginValues {
50
+ email: string;
51
+ /** Absent in "email-only" mode. */
52
+ password?: string;
53
+ }
54
+ export interface LoginFormProps extends AuthFormBase {
55
+ /** Called with the entered values. Omit to let the form submit natively (e.g. to an `action`). */
56
+ onSubmit?: (values: LoginValues) => void | Promise<void>;
57
+ /** "email-only" drops the password field for magic-link or OTP flows (shadcn login-05). */
58
+ mode?: "password" | "email-only";
59
+ forgotPasswordHref?: string;
60
+ signupHref?: string;
61
+ submitLabel?: React.ReactNode;
62
+ }
63
+ /** Email + password sign-in form with optional SSO buttons. Pair with AuthLayout. */
64
+ declare function LoginForm({ title, description, onSubmit, mode, providers, onProviderClick, providersFirst, forgotPasswordHref, signupHref, submitLabel, loading, error, className, ...props }: LoginFormProps): React.JSX.Element;
65
+ export interface SignupValues {
66
+ name?: string;
67
+ email: string;
68
+ password: string;
69
+ }
70
+ export interface SignupFormProps extends AuthFormBase {
71
+ onSubmit?: (values: SignupValues) => void | Promise<void>;
72
+ /** Ask for a full name. Default true. */
73
+ nameField?: boolean;
74
+ /** Ask for the password twice; mismatches are reported before onSubmit. Default true. */
75
+ confirmPassword?: boolean;
76
+ /** Hint under the password field. */
77
+ passwordHint?: React.ReactNode;
78
+ /** Minimum password length enforced by the browser. Default 8. */
79
+ minPasswordLength?: number;
80
+ loginHref?: string;
81
+ submitLabel?: React.ReactNode;
82
+ }
83
+ /** Account creation form: name, email, password (+ confirm), optional SSO. Pair with AuthLayout. */
84
+ declare function SignupForm({ title, description, onSubmit, nameField, confirmPassword, passwordHint, minPasswordLength, providers, onProviderClick, providersFirst, loginHref, submitLabel, loading, error, className, ...props }: SignupFormProps): React.JSX.Element;
85
+ export { AppleIcon, AuthLayout, GitHubIcon, GoogleIcon, LoginForm, SignupForm };