Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
208f000
feat: add agent loading states
starc007 Jul 30, 2026
4fe69d6
feat: integrate agent loading states
starc007 Jul 31, 2026
c7bea42
feat: add collapsible agent reasoning
starc007 Jul 31, 2026
e52d2b5
feat: integrate agent reasoning
starc007 Jul 31, 2026
d9acbea
fix: refine agent reasoning preview
starc007 Jul 31, 2026
6e5899c
fix: integrate agent reasoning refinements
starc007 Jul 31, 2026
baca6d7
docs: keep agent guide project-focused
starc007 Jul 31, 2026
41e804b
fix: restore thinking state labels
starc007 Jul 31, 2026
6d2b3f3
fix: follow streaming reasoning output
starc007 Jul 31, 2026
46f5787
docs: extend agent reasoning preview
starc007 Jul 31, 2026
26dd759
fix: smooth agent reasoning stream
starc007 Jul 31, 2026
eae556d
feat: add streaming agent activity states
starc007 Jul 31, 2026
9ff23f9
fix: hide attribution note on agent pages
starc007 Jul 31, 2026
9046f19
feat: add agent response approval and sources
starc007 Aug 1, 2026
871328d
feat: refine tool approval presentation
starc007 Aug 1, 2026
43f8794
feat: refine citations and streaming response
starc007 Aug 1, 2026
4426055
feat: integrate sources into streaming responses
starc007 Aug 1, 2026
8eb1fcb
feat: add tool result and file diff
starc007 Aug 1, 2026
8803a8c
feat: add structured agent trace
starc007 Aug 1, 2026
e1bcc88
feat: add approval card
starc007 Aug 1, 2026
90ac286
feat: add agent code block
starc007 Aug 1, 2026
79f8f4b
feat: add agent todo list
starc007 Aug 1, 2026
84247ce
style: soften component page heading
starc007 Aug 1, 2026
6092d49
feat: add agent prompt input
starc007 Aug 2, 2026
1a4974f
feat: add message components
starc007 Aug 2, 2026
b7b4f5a
feat: add message scroller and interactive chat previews
starc007 Aug 2, 2026
805d779
docs: improve agent component guides
starc007 Aug 2, 2026
5a5c3fa
feat: add interactive image generation state
starc007 Aug 2, 2026
ef22c04
feat: add message navigation rail
starc007 Aug 2, 2026
254d0e5
feat: add message rail previews
starc007 Aug 2, 2026
6abbbbe
fix: show public agent usage compositions
starc007 Aug 2, 2026
fbfa0c6
feat: add ai sidebar agent component
starc007 Aug 2, 2026
afd9d0a
fix: refine ai sidebar collapse motion
starc007 Aug 2, 2026
9cc2b31
feat: add complete agent chat app
starc007 Aug 2, 2026
f6d4b01
fix: harden agent components for release
starc007 Aug 2, 2026
c5b328d
feat: schedule agent component launch
starc007 Aug 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 26 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ Prefer `typecheck` + `lint` for quick verification. Do not start the dev server

## Layout

- `components/motion/` — the library. One file per component; multi-file widgets get a folder (`swap/`, `button/`).
- `components/previews/` — demo per component, registered in `components/previews/index.tsx`. Previews ship through the registry too.
- `components/motion/` and `components/agents/` — the library. One file per component; multi-file widgets get a folder (`swap/`, `button/`, `loading-states/`).
- `components/previews/` — demo per component, registered in `components/previews/index.tsx`. Previews ship through the registry too. When an interactive preview uses internal demo helpers, set the registry entry's `usageFile` to a separate public composition so the Usage tab stays copyable.
- `components/app/` — site chrome (header, hero, dock, code blocks). Not part of the library.
- `lib/registry.ts` — component catalog (slugs, files, examples). Two categories: `motion` (display name "Components", primitives) and `blocks` (composed widgets: swap, dynamic island, command palette, expandable action bar). Blocks emit `registry:block` shadcn items. Preview files live under `components/previews/<category>/`. `lib/registry-server.ts` builds registry items by following each file's `@/` and relative imports and bundling everything it finds. Internal imports are therefore safe and encouraged; a component that imports `@/lib/ease` ships `lib/ease.ts` with it.
- `lib/registry.ts` — component catalog (slugs, files, examples). Three categories: `motion` (display name "Components", primitives), `agents` (AI and agent interface primitives), and `blocks` (composed widgets: swap, dynamic island, command palette, expandable action bar). Blocks emit `registry:block` shadcn items. Preview files live under `components/previews/<category>/`. `lib/registry-server.ts` builds registry items by following each file's `@/` and relative imports and bundling everything it finds. Internal imports are therefore safe and encouraged; a component that imports `@/lib/ease` ships `lib/ease.ts` with it.
- `app/r/*` — registry endpoints (shadcn items, raw source, index). beUI is listed in shadcn's official registry directory as the `@beui` namespace with URL template `https://beui.dev/r/{name}.json` — that path shape and existing install slugs are public contract; never break or rename them.
- `lib/ease.ts` — all motion tokens.
- `scripts/check-registry.ts` — validates the catalog.
Expand All @@ -46,7 +46,7 @@ Before building a new component, check this list. If it exists, import it. If it
| `shared-layout-bg` | `components/motion/shared-layout-bg.tsx` | Pill that glides between hovered items via shared layout |
| `bounce-sidebar` | `components/motion/bounce-sidebar.tsx` | Vertical navigation whose active dot jumps between rows on a curved spring path; controlled/uncontrolled, links or buttons, reduced-motion safe |
| `animated-sidebar` | `components/motion/animated-sidebar.tsx` | Shadcn-style application sidebar with provider-managed desktop/mobile state, icon or off-canvas collapse, morphing nested-menu primitives, animated content inset, toggle rail, keyboard shortcut and a focus-managed mobile sheet |
| `preview-rail` | `components/motion/preview-rail.tsx` | Vertical or horizontal navigation ticks that form a pyramid around the hovered item with a gliding preview card |
| `preview-rail` | `components/motion/preview-rail.tsx` | Vertical or horizontal link/button navigation ticks that form a pyramid around the hovered item with an optionally positioned gliding preview card |
| `dock` | `components/motion/dock.tsx` | macOS-style dock with grouped actions and gliding active pill |
| `tooltip` | `components/motion/tooltip.tsx` | Hover/focus tooltip with blur enter/exit and spring spawn |
| `context-menu` | `components/motion/context-menu.tsx` | Composable right-click/long-press menu with a pointer-origin clip morph, a spring-gliding active row, checkbox/radio choices, keyboard navigation and typeahead |
Expand All @@ -70,6 +70,28 @@ Before building a new component, check this list. If it exists, import it. If it
| `magnetic` | `components/motion/magnetic.tsx` | Cursor-attracted magnetic pull wrapper |
| `scroll-animation` | `components/motion/smooth-scroll.tsx`, `scroll-progress.tsx`, `parallax.tsx`, `scroll-to.tsx`, `scroll-reveal.tsx` | Scroll-driven motion group (variants install as `@beui/smooth-scroll`, `@beui/scroll-progress`, `@beui/parallax`, `@beui/scroll-to`, `@beui/scroll-reveal`). **Smooth Scroll**: Lenis provider (`root` page / `root={false}` contained) + `useSmoothScroll` hook (offset/progress/velocity, `scrollTo`), reduced-motion native. **Scroll Progress**: bar or ring reading `useSmoothScroll().progress`. **Parallax**: drifts children at a speed factor across the viewport, either axis. **Scroll To**: button that smooth-scrolls to a target via the provider. **Scroll Reveal**: spring slide + blur reveal on viewport enter |

### AI Agents (`agents` category — agent interface primitives)

| slug | file | what it does |
|---|---|---|
| `chat-app` | `components/agents/chat-app.tsx` | Composable agent workspace shell (`ChatApp`) backed by the animated sidebar provider; its complete usage example combines navigation, messages, streaming, planning, approvals, tool results, code, diffs, generated media, sources, and prompt input |
| `ai-sidebar` | `components/agents/ai-sidebar.tsx` | Collapsible AI workspace sidebar (`AISidebar`) for folders, projects, files, and bookmarks with full-row drag and keyboard moves, optimistic rollback, inline rename, persistent menu hover, open-folder icons, and overflow-only marquee labels |
| `message-bubble` | `components/agents/message-bubble.tsx` | Focused conversational surface (`MessageBubble`) with six visual treatments, independent alignment, an opt-in mount-only surface pop, compact grouping, polymorphic links/buttons, and `MessageBubbleCollapsible` for long responses; streaming geometry updates immediately |
| `message` | `components/agents/message.tsx` | Composable conversation message (`Message`) with bubble, avatar, header, footer, group, marker, and typing primitives plus an opt-in mount-only trailing-edge pop-up for newly sent rows; re-exports the independently installable `MessageScroller` for compatibility |
| `message-scroller` | `components/agents/message-scroller.tsx` | Reader-aware conversation viewport (`MessageScroller`) that follows streamed growth only at the live edge, releases on deliberate navigation, and can add a compact message rail that previews, tracks, and scrolls to rendered messages |
| `prompt-input` | `components/agents/prompt-input.tsx` | Auto-growing agent composer (`PromptInput`) with controlled/uncontrolled prompt and model state, a configurable animated actions menu, model selection, Enter-to-send, multiline input, and send/stop actions |
| `todo-list` | `components/agents/todo-list.tsx` | Collapsible agent task plan (`TodoList`) with pending/in-progress/completed/cancelled states, morphing progress-to-check marks, a completion count, stable streaming rows, bounded smooth following, and compact per-task metadata |
| `code-block` | `components/agents/code-block.tsx` | Syntax-highlighted agent code surface (`CodeBlock`) with stable streamed updates, optional line numbers and focused lines, bounded smooth following, filename/language metadata, and copy feedback |
| `approval-card` | `components/agents/approval-card/` | Human-in-the-loop decision surface (`ApprovalCard`) for approval/rejection/revision actions and single-choice, multiple-choice, freeform, or multi-step questions; single choices advance by default, with controlled/uncontrolled answers and step state, reduced-motion safe transitions, and collapsed submitted outcomes |
| `file-diff` | `components/agents/file-diff.tsx` | Progressive syntax-highlighted file change disclosure (`FileDiff`) with stable line rows, live addition/deletion counts, bounded smooth following, copy support, and completion collapse |
| `tool-result` | `components/agents/tool-result.tsx` | Lightweight execution disclosure (`ToolResult`) for syntax-highlighted terminal output and request responses; bounded auto-following output, success/error/cancelled states, completion collapse, copy/retry actions, and the reusable `ToolResultOutput` renderer |
| `loading-states` | `components/agents/loading-states/` | Three agent loading states: `ThinkingShimmer`, compact live-timed `AgentProgress`, and `ReasoningText` with an ASCII loader, shimmering phrases, and cascade/swap/scramble styles; each variant is independently installable and reduced-motion safe |
| `agent-activity` | `components/agents/agent-activity/` | Adaptive agent activity disclosure (`AgentActivity`): renders compact streaming text, reasoning steps, search results, tool calls, structured execution traces, or a chronological mix; derives a matching active/completed summary, smoothly follows entries in a capped viewport, then collapses into a reopenable disclosure |
| `streaming-response` | `components/agents/streaming-response.tsx` | Renderer-agnostic streamed answer surface (`StreamingResponse`) with completion-only copy, retry, feedback, an optional expandable source summary, and controls for actions and nested live-region announcements |
| `image-generation` | `components/agents/image-generation.tsx` | Stable generated-media canvas (`ImageGeneration`) with queued, generating, refining, complete, and recoverable error states; progressively resolves supplied media without remounting or shifting the surrounding conversation |
| `tool-approval` | `components/agents/tool-approval.tsx` | Human-in-the-loop permission card (`ToolApproval`) with controlled execution states, expandable parameters, allow-once/always-allow/deny actions, optional Shiki-powered `ToolApprovalCode` values, and reduced-motion behavior |
| `citations` | `components/agents/citations.tsx` | Collapsible progressive citation collection (`Citations`) paired with inline `Citation` links; derives real favicons from each URL via `lib/favicon.ts` and renders compact numbered title/domain rows with controlled disclosure and reduced motion |

### Blocks (`blocks` category — composed product widgets)

| slug | file | what it does |
Expand Down
65 changes: 51 additions & 14 deletions app/components/[category]/[slug]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from "@/components/motion/tabs";
import { NewBadge } from "@/components/app/docs/new-badge";
import { ComponentCard } from "@/components/app/docs/component-card";
import { ComponentGuide } from "@/components/app/docs/component-guide";
import { CopyPage } from "@/components/app/docs/copy-page";
import { JsonLd } from "@/components/app/analytics/json-ld";
import { getPreview, previews } from "@/components/previews";
Expand Down Expand Up @@ -65,7 +66,7 @@ export async function generateMetadata({
? `/${installSlugs[0]}.json`
: `/${comp.slug}.json`;

const title = `${comp.name} · React motion component`;
const title = comp.guide?.seo.title ?? `${comp.name} · React motion component`;
const ogTitle = `${title} · beUI`;
const pageUrl = `/components/${cat.slug}/${comp.slug}`;
const imageUrl = `/api/og?component=${comp.slug}`;
Expand Down Expand Up @@ -137,19 +138,24 @@ export default async function ComponentPage({
const hasMultipleVariants = (comp.examples?.length ?? 0) > 1;
const hasVariantInstallCommands =
comp.examples?.some((example) => example.installSlug) ?? false;
const examplesShareSource =
(comp.examples?.length ?? 0) > 1 &&
new Set(comp.examples?.map((example) => example.file)).size === 1;
const shouldShowExampleApi = (index: number) =>
!examplesShareSource || index === (comp.examples?.length ?? 0) - 1;
const dates = componentDates(cat.slug, comp.slug);
const related = relatedComponents(cat.slug, comp.slug, 3);
const propsDocs = comp.examples?.length ? [] : getComponentProps(comp.file);
const variantNavItems: PageNavItem[] =
comp.examples?.map((example) => ({
comp.examples?.map((example, index) => ({
id: example.slug,
label: example.name,
children: [
{ id: `${example.slug}-preview`, label: "Preview" },
...(example.installSlug
? [{ id: `${example.slug}-install`, label: "Install" }]
: []),
...(getComponentProps(example.file).length
...(shouldShowExampleApi(index) && getComponentProps(example.file).length
? [
{
id: `${example.slug}-api-reference`,
Expand All @@ -161,7 +167,18 @@ export default async function ComponentPage({
})) ?? [];
const pageNavItems: PageNavItem[] = [
...(variantNavItems.length
? variantNavItems
? [
...variantNavItems,
...(!hasVariantInstallCommands
? [{ id: "install", label: "Install" }]
: []),
...(comp.guide
? [
{ id: "composition", label: "Composition" },
{ id: "behavior", label: "How it works" },
]
: []),
]
: [
{
id: "overview",
Expand All @@ -174,6 +191,12 @@ export default async function ComponentPage({
...(propsDocs.length
? [{ id: "api-reference", label: "API Reference" }]
: []),
...(comp.guide
? [
{ id: "composition", label: "Composition" },
{ id: "behavior", label: "How it works" },
]
: []),
],
},
]),
Expand Down Expand Up @@ -211,7 +234,7 @@ export default async function ComponentPage({
</nav>
<div className="mt-4 flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
<div className="flex items-center gap-3">
<h1 className="text-3xl font-semibold tracking-tight text-foreground">
<h1 className="text-3xl font-medium tracking-tight text-foreground">
{comp.name}
</h1>
{comp.badge === "new" && !hasMultipleVariants ? (
Expand All @@ -231,17 +254,23 @@ export default async function ComponentPage({

{comp.examples?.length ? (
<div className="mt-10 flex flex-col gap-12">
{comp.examples.map((ex) => (
{comp.examples.map((ex, index) => (
<ExampleBlock
key={ex.slug}
category={cat.slug}
pageSlug={comp.slug}
example={ex}
showApiReference={shouldShowExampleApi(index)}
/>
))}
</div>
) : (
<DefaultTabs category={category} slug={slug} file={comp.file} />
<DefaultTabs
category={category}
slug={slug}
file={comp.file}
usageFile={comp.usageFile}
/>
)}

{!hasVariantInstallCommands ? (
Expand Down Expand Up @@ -275,6 +304,8 @@ export default async function ComponentPage({
</section>
) : null}

{comp.guide ? <ComponentGuide guide={comp.guide} /> : null}

{related.length ? (
<section
id="related-components"
Expand Down Expand Up @@ -316,9 +347,9 @@ export default async function ComponentPage({
.
</p>
</section>
) : (
) : cat.slug !== "agents" ? (
<KeepInMind />
)}
) : null}
<p className="mt-6 text-xs text-muted-foreground">
Updated{" "}
<time dateTime={dates.updatedAt}>
Expand All @@ -338,18 +369,21 @@ async function ExampleBlock({
category,
pageSlug,
example,
showApiReference,
}: {
category: string;
pageSlug: string;
example: ComponentExample;
showApiReference: boolean;
}) {
const Preview = previews[example.previewKey];
const usageFile = example.usageFile ?? example.previewFile;
const [source, usage] = await Promise.all([
loadSource(example.file),
loadSource(example.previewFile),
loadSource(usageFile),
]);
const installSlug = example.installSlug ?? null;
const propsDocs = getComponentProps(example.file);
const propsDocs = showApiReference ? getComponentProps(example.file) : [];

return (
<section id={example.slug} className="scroll-mt-24">
Expand Down Expand Up @@ -384,7 +418,7 @@ async function ExampleBlock({
</div>
</TabsContent>
<TabsContent value="usage" className="mt-4">
<CodeBlock code={usage} filename={example.previewFile} />
<CodeBlock code={usage} filename={usageFile} />
</TabsContent>
<TabsContent value="source" className="mt-4">
<CodeBlock
Expand Down Expand Up @@ -430,16 +464,19 @@ async function DefaultTabs({
category,
slug,
file,
usageFile,
}: {
category: string;
slug: string;
file: string;
usageFile?: string;
}) {
const Preview = getPreview(category, slug);
const previewFile = `components/previews/${category}/${slug}.preview.tsx`;
const resolvedUsageFile = usageFile ?? previewFile;
const [source, usage] = await Promise.all([
loadSource(file),
loadSource(previewFile),
loadSource(resolvedUsageFile),
]);

return (
Expand All @@ -457,7 +494,7 @@ async function DefaultTabs({
</div>
</TabsContent>
<TabsContent value="usage" className="mt-4">
<CodeBlock code={usage} filename={previewFile} />
<CodeBlock code={usage} filename={resolvedUsageFile} />
</TabsContent>
<TabsContent value="source" className="mt-4">
<CodeBlock
Expand Down
Loading
Loading