An open API service indexing awesome lists of open source software.

https://github.com/extedcoud/smart-components

Headless React components powered by LLM behaviors.
https://github.com/extedcoud/smart-components

ai anthropic autocomplete copilot headless-ui llm openai react react-hooks typescript ui-components

Last synced: 27 days ago
JSON representation

Headless React components powered by LLM behaviors.

Awesome Lists containing this project

README

          

# @extedcoud/smart-components

[![npm](https://img.shields.io/npm/v/@extedcoud/smart-components?color=cb3837&logo=npm)](https://www.npmjs.com/package/@extedcoud/smart-components)
[![bundle size](https://img.shields.io/bundlephobia/minzip/@extedcoud/smart-components?label=min%2Bgzip)](https://bundlephobia.com/package/@extedcoud/smart-components)
[![license](https://img.shields.io/npm/l/@extedcoud/smart-components?color=blue)](./LICENSE)

Headless React components with the AI wiring already done. You bring an LLM client and your own styles; the library handles the fiddly parts — debouncing, aborting stale requests, ghost-text positioning, keyboard handling.

### 📖 [Documentation & live demos](https://extedcoud.github.io/smart-components/)

### 🎮 [Component playground (Storybook)](https://extedcoud.github.io/smart-components/storybook/)

## Install

```sh
pnpm add @extedcoud/smart-components react react-dom
```

No runtime dependencies beyond React. Every adapter is built on plain `fetch`.

## Quick start

```tsx
import { SmartProvider, SmartTextbox, SmartSuggestion } from '@extedcoud/smart-components';
import { createProxyClient } from '@extedcoud/smart-components/adapters/proxy';
import '@extedcoud/smart-components/style.css';

// In production, point this at your own backend so the API key stays server-side.
const client = createProxyClient({ url: '/api/smart' });

export function App() {
const [v, setV] = useState('');
return (


console.log('picked', s)}
context="naming a new project"
/>

);
}
```

## Components

| Component | What it does |
| --- | --- |
| `` | Single-line input with Copilot-style ghost completion. ArrowRight accepts (configurable), Esc dismisses. |
| `` | Multiline ghost completion via a mirror div, with multiline stops and optional auto-resize. |
| `` | Combobox with an AI-generated dropdown. Arrow keys to move, Enter to pick. |
| `` | Render-prop rewrite primitive. Ships with Shorter / Formal / Casual / Fix grammar presets. |

Everything is headless: minimal default DOM, render slots (`renderItem`, `renderGhost`, render-props), and native input attributes pass straight through.

### Styling the ghost text

The ghost defaults to `opacity: 0.4` and inherits the input's color. To recolor it, pass `ghostClassName` or `ghostStyle`:

```tsx

```

For richer markup (icons, badges) use the `renderGhost` render-prop. To style globally, target `[data-testid="smart-textbox-ghost"]` / `[data-testid="smart-textarea-ghost"]`.

## Mobile

Touch is a first-class target, not an afterthought. Things to know:

- **The accept key is configurable.** It defaults to `ArrowRight`, which most soft keyboards lack — on mobile, remap `acceptKey` or trigger accept imperatively via the field ref.
- Wrappers use `touch-action: manipulation` to drop the 300ms tap delay.
- `SmartSuggestion` selection runs on pointer events (mouse, touch, pen). Give items `min-height: 44px` to hit the WCAG touch target.
- Inputs below `16px` font size make iOS Safari zoom on focus — keep `SmartTextbox` / `SmartTextarea` at 16px or larger.
- Known limit: the `SmartSuggestion` dropdown can sit under the soft keyboard on short viewports. Portal the list or use a fullscreen picker there.

## AI clients

`SmartClient` is a capability-based interface. Use an adapter or implement your own:

| Adapter | Import | When |
| --- | --- | --- |
| `createProxyClient` | `/adapters/proxy` | Production. POSTs to your backend; the key stays on the server. |
| `createOpenAIClient` | `/adapters/openai` | Dev and demos only — never ship a key to the browser. |
| `createAnthropicClient` | `/adapters/anthropic` | Anthropic Messages API (`complete` + `stream`). |
| `createMockClient` | `/adapters/mock` | Tests and Storybook. |

Rolling your own is a few lines:

```ts
import { SMART_CLIENT_PROTOCOL_VERSION, type SmartClient } from '@extedcoud/smart-components';

const myClient: SmartClient = {
protocolVersion: SMART_CLIENT_PROTOCOL_VERSION,
id: 'my-backend',
capabilities: new Set(['complete', 'stream']),
async complete(req) { /* ... */ return text; },
async *stream(req) { /* yield chunks */ },
};
```

## Hooks

The components are thin wrappers over hooks. Reach for these to build your own on the same plumbing:

```ts
import {
useGhostCompletion,
useSuggestionList,
useRewrite,
useSmartState,
} from '@extedcoud/smart-components';
```

### `useSmartState` — useState that an LLM can fill

A drop-in `useState` with one extra: `ai.generate(context?)`. The shape is read from your initial value, so the model is constrained to matching JSON — no schema, no parsing.

```tsx
const [user, setUser, ai] = useSmartState(
{ name: '', age: 0, bio: '' },
'a fictitious cyberpunk character',
);

ai.generate(); // → { name: 'Kael-9', age: 28, bio: '…' }
setUser({ ... }); // still plain useState
```

When the seed is empty (`null`, `[]`), pass `options.shape` so it knows what to ask for:

```tsx
const [tags, , ai] = useSmartState([], 'tags for a sci-fi blog post', {
shape: { type: 'array', item: 'string' },
});
```

A few things worth knowing:

- Calling `setValue` mid-generate cancels the in-flight request — the user's edit wins.
- An empty inner array (`{ tags: [] }`) throws at mount; seed it or pass `shape`. Same for `Date`, `Map`, `Set`, functions — JSON-serializable values only.
- Results are cached LRU(16) by `(shape, context)`. Opt out with `{ cache: false }`.
- Generate is atomic (no streaming) and needs a client with the `complete` capability.

Full walkthrough — form autofill, text extraction, palettes — is in the [docs](https://extedcoud.github.io/smart-components/).

## Develop

A pnpm workspace: the root is the library, `docs/` is the public site (Next.js + Fumadocs on GitHub Pages).

```sh
pnpm install
pnpm storybook # :6006 — internal dev surface
pnpm test # vitest watch
pnpm lint
pnpm typecheck
pnpm build # lib → dist/

# Docs site (build the lib first — it consumes dist/)
pnpm --filter @extedcoud/smart-components build
pnpm --filter docs dev # :3000
```

Docs deploy to GitHub Pages via `.github/workflows/deploy-docs.yml` on push to `main`.

## Stack

**Library:** Vite (lib mode), TypeScript, CSS Modules, ESLint 9, Prettier, Vitest + RTL, Storybook.
**Docs:** Next.js 15 (static export), Fumadocs UI, Tailwind v4, MDX.