@gram-ai/elements 1.12.0 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +159 -70
- package/dist/components/ui/button.d.ts +1 -1
- package/dist/components/ui/buttonVariants.d.ts +1 -1
- package/dist/elements.cjs +44 -30
- package/dist/elements.css +1 -1
- package/dist/elements.js +30905 -7594
- package/dist/types/index.d.ts +59 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -110,6 +110,7 @@ The `ElementsConfig` object accepts the following configuration options:
|
|
|
110
110
|
| `environment` | `Record<string, unknown>` | No | ✅ Implemented | `undefined` | Custom environment variable overrides for the MCP server. See [Gram documentation](https://www.speakeasy.com/docs/gram/host-mcp/public-private-servers#pass-through-authentication) for pass-through authentication |
|
|
111
111
|
| `variant` | `'widget' \| 'sidecar' \| 'standalone'` | No | ✅ Implemented | `'widget'` | The layout variant for the chat interface. `widget` is a popup modal, `sidecar` is a side panel, `standalone` is a full-page experience |
|
|
112
112
|
| `plugins` | [`Plugin[]`](#plugins) | No | ✅ Implemented | `[]` | Array of plugins to extend rendering capabilities. See [Plugins section](#plugins) for details |
|
|
113
|
+
| `components` | [`ComponentOverrides`](#component-overrides) | No | ✅ Implemented | `undefined` | Override default UI components with custom implementations. See [Component Overrides section](#component-overrides) for details |
|
|
113
114
|
| `theme` | [`ThemeConfig`](#theme-configuration-themeconfig) | No | ✅ Implemented | `undefined` | Visual appearance configuration options |
|
|
114
115
|
| `welcome` | [`WelcomeConfig`](#welcome-configuration-welcomeconfig) | Yes | ✅ Implemented | - | Configuration for the welcome message and initial suggestions |
|
|
115
116
|
| `composer` | [`ComposerConfig`](#composer-configuration-composerconfig) | No | ✅ Implemented | `undefined` | Configuration for the composer input |
|
|
@@ -220,6 +221,160 @@ The following models are currently supported:
|
|
|
220
221
|
| ------------ | ---------------------------------------------- | -------- | -------------- | ----------- | ------------------------------------------------------------------------------------------ |
|
|
221
222
|
| `components` | `Record<string, ToolCallMessagePartComponent>` | No | ✅ Implemented | `undefined` | Override default React components for specific tool results. Tool names must match exactly |
|
|
222
223
|
|
|
224
|
+
## Component Overrides
|
|
225
|
+
|
|
226
|
+
The `components` property in `ElementsConfig` allows you to override default UI components with your own custom implementations. This provides fine-grained control over the appearance and behavior of different parts of the chat interface.
|
|
227
|
+
|
|
228
|
+
### Available Component Overrides
|
|
229
|
+
|
|
230
|
+
| Component | Type | Description |
|
|
231
|
+
| ------------------ | ------------------------------- | ------------------------------------------------------------ |
|
|
232
|
+
| `Composer` | `ComponentType` | The composer input area where users type messages |
|
|
233
|
+
| `UserMessage` | `ComponentType` | The entire user message bubble/container |
|
|
234
|
+
| `EditComposer` | `ComponentType` | The composer shown when editing a user message |
|
|
235
|
+
| `AssistantMessage` | `ComponentType` | The entire assistant message bubble/container |
|
|
236
|
+
| `ThreadWelcome` | `ComponentType` | The welcome screen shown when the thread is empty |
|
|
237
|
+
| `Text` | `TextMessagePartComponent` | Text content within messages (supports Markdown by default) |
|
|
238
|
+
| `Image` | `ImageMessagePartComponent` | Image attachments within messages |
|
|
239
|
+
| `ToolFallback` | `ToolCallMessagePartComponent` | Default component for tool results without custom components |
|
|
240
|
+
| `Reasoning` | `ReasoningMessagePartComponent` | Individual reasoning steps shown in assistant messages |
|
|
241
|
+
| `ReasoningGroup` | `ReasoningGroupComponent` | Container for grouped reasoning steps |
|
|
242
|
+
| `ToolGroup` | `ComponentType` | Container for grouped tool calls |
|
|
243
|
+
|
|
244
|
+
### Component Override Examples
|
|
245
|
+
|
|
246
|
+
#### Basic Text Override
|
|
247
|
+
|
|
248
|
+
Override how text is rendered in assistant messages:
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
import { ElementsConfig } from '@gram-ai/elements'
|
|
252
|
+
import { useAssistantState } from '@assistant-ui/react'
|
|
253
|
+
|
|
254
|
+
const config: ElementsConfig = {
|
|
255
|
+
projectSlug: 'my-project',
|
|
256
|
+
mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
|
|
257
|
+
welcome: {
|
|
258
|
+
title: 'Hello!',
|
|
259
|
+
subtitle: 'How can I help you today?',
|
|
260
|
+
},
|
|
261
|
+
components: {
|
|
262
|
+
Text: () => {
|
|
263
|
+
const message = useAssistantState(({ message }) => message)
|
|
264
|
+
const text = message.parts
|
|
265
|
+
.map((part) => (part.type === 'text' ? part.text : ''))
|
|
266
|
+
.join('')
|
|
267
|
+
|
|
268
|
+
return (
|
|
269
|
+
<div className="custom-text">
|
|
270
|
+
{text}
|
|
271
|
+
</div>
|
|
272
|
+
)
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
#### Custom Welcome Screen
|
|
279
|
+
|
|
280
|
+
Override the welcome screen with your own design:
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
import { ElementsConfig } from '@gram-ai/elements'
|
|
284
|
+
|
|
285
|
+
const CustomWelcome = () => {
|
|
286
|
+
return (
|
|
287
|
+
<div className="flex flex-col items-center justify-center h-full">
|
|
288
|
+
<h1 className="text-4xl font-bold mb-4">Welcome to My AI Assistant!</h1>
|
|
289
|
+
<p className="text-gray-600">Start chatting below</p>
|
|
290
|
+
</div>
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const config: ElementsConfig = {
|
|
295
|
+
projectSlug: 'my-project',
|
|
296
|
+
mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
|
|
297
|
+
welcome: {
|
|
298
|
+
title: 'Hello!',
|
|
299
|
+
subtitle: 'How can I help you today?',
|
|
300
|
+
},
|
|
301
|
+
components: {
|
|
302
|
+
ThreadWelcome: CustomWelcome,
|
|
303
|
+
},
|
|
304
|
+
}
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
#### Custom Message Containers
|
|
308
|
+
|
|
309
|
+
Override the entire message container for more control:
|
|
310
|
+
|
|
311
|
+
```typescript
|
|
312
|
+
import { ElementsConfig } from '@gram-ai/elements'
|
|
313
|
+
import { MessagePrimitive } from '@assistant-ui/react'
|
|
314
|
+
|
|
315
|
+
const CustomUserMessage = () => {
|
|
316
|
+
return (
|
|
317
|
+
<MessagePrimitive.Root>
|
|
318
|
+
<div className="my-custom-user-message">
|
|
319
|
+
<div className="message-avatar">👤</div>
|
|
320
|
+
<div className="message-content">
|
|
321
|
+
<MessagePrimitive.Parts />
|
|
322
|
+
</div>
|
|
323
|
+
</div>
|
|
324
|
+
</MessagePrimitive.Root>
|
|
325
|
+
)
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
const config: ElementsConfig = {
|
|
329
|
+
projectSlug: 'my-project',
|
|
330
|
+
mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
|
|
331
|
+
welcome: {
|
|
332
|
+
title: 'Hello!',
|
|
333
|
+
subtitle: 'How can I help you today?',
|
|
334
|
+
},
|
|
335
|
+
components: {
|
|
336
|
+
UserMessage: CustomUserMessage,
|
|
337
|
+
},
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
#### Combining Multiple Overrides
|
|
342
|
+
|
|
343
|
+
You can override multiple components at once:
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import { ElementsConfig } from '@gram-ai/elements'
|
|
347
|
+
import {
|
|
348
|
+
CustomComposer,
|
|
349
|
+
CustomUserMessage,
|
|
350
|
+
CustomAssistantMessage,
|
|
351
|
+
CustomText,
|
|
352
|
+
} from './components'
|
|
353
|
+
|
|
354
|
+
const config: ElementsConfig = {
|
|
355
|
+
projectSlug: 'my-project',
|
|
356
|
+
mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
|
|
357
|
+
welcome: {
|
|
358
|
+
title: 'Hello!',
|
|
359
|
+
subtitle: 'How can I help you today?',
|
|
360
|
+
},
|
|
361
|
+
components: {
|
|
362
|
+
Composer: CustomComposer,
|
|
363
|
+
UserMessage: CustomUserMessage,
|
|
364
|
+
AssistantMessage: CustomAssistantMessage,
|
|
365
|
+
Text: CustomText,
|
|
366
|
+
},
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
### Notes on Component Overrides
|
|
371
|
+
|
|
372
|
+
- Component overrides give you full control over rendering, but you're responsible for maintaining the expected behavior
|
|
373
|
+
- When overriding message containers (`UserMessage`, `AssistantMessage`), make sure to include `MessagePrimitive.Root` and `MessagePrimitive.Parts` to maintain compatibility with the assistant-ui runtime
|
|
374
|
+
- For text content overrides, the default `Text` component supports Markdown rendering. If you override it, you'll need to implement your own Markdown support if needed
|
|
375
|
+
- Component overrides are applied globally across your chat interface
|
|
376
|
+
- For building custom components from scratch, refer to the [assistant-ui Context API documentation](https://www.assistant-ui.com/docs/guides/context-api) which provides detailed information about the state management system, available actions, and hooks like `useAssistantState`, `useAssistantApi`, and `useAssistantEvent`
|
|
377
|
+
|
|
223
378
|
### Configuration Examples
|
|
224
379
|
|
|
225
380
|
#### Minimal Configuration
|
|
@@ -243,6 +398,7 @@ const config: ElementsConfig = {
|
|
|
243
398
|
import { ElementsConfig } from '@gram-ai/elements'
|
|
244
399
|
import { recommended } from '@gram-ai/elements/plugins'
|
|
245
400
|
import { WeatherComponent } from './components/WeatherComponent'
|
|
401
|
+
import { CustomText } from './components/CustomText'
|
|
246
402
|
|
|
247
403
|
const config: ElementsConfig = {
|
|
248
404
|
systemPrompt: 'You are a helpful AI assistant.',
|
|
@@ -251,6 +407,9 @@ const config: ElementsConfig = {
|
|
|
251
407
|
chatEndpoint: '/api/chat',
|
|
252
408
|
variant: 'widget',
|
|
253
409
|
plugins: recommended,
|
|
410
|
+
components: {
|
|
411
|
+
Text: CustomText,
|
|
412
|
+
},
|
|
254
413
|
theme: {
|
|
255
414
|
colorScheme: 'system',
|
|
256
415
|
density: 'normal',
|
|
@@ -308,76 +467,6 @@ const config: ElementsConfig = {
|
|
|
308
467
|
}
|
|
309
468
|
```
|
|
310
469
|
|
|
311
|
-
#### Widget Variant with Custom Modal Icon
|
|
312
|
-
|
|
313
|
-
```typescript
|
|
314
|
-
import { ElementsConfig } from '@gram-ai/elements'
|
|
315
|
-
import { MessageSquare, X } from 'lucide-react'
|
|
316
|
-
|
|
317
|
-
const config: ElementsConfig = {
|
|
318
|
-
projectSlug: 'my-project',
|
|
319
|
-
mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
|
|
320
|
-
variant: 'widget',
|
|
321
|
-
welcome: {
|
|
322
|
-
title: 'Chat with us!',
|
|
323
|
-
subtitle: 'Ask anything',
|
|
324
|
-
},
|
|
325
|
-
modal: {
|
|
326
|
-
defaultOpen: true,
|
|
327
|
-
icon: (state) => (state === 'open' ? <X /> : <MessageSquare />),
|
|
328
|
-
},
|
|
329
|
-
}
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
#### Standalone Variant with Model Picker
|
|
333
|
-
|
|
334
|
-
```typescript
|
|
335
|
-
import { ElementsConfig } from '@gram-ai/elements'
|
|
336
|
-
|
|
337
|
-
const config: ElementsConfig = {
|
|
338
|
-
projectSlug: 'my-project',
|
|
339
|
-
mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
|
|
340
|
-
variant: 'standalone',
|
|
341
|
-
welcome: {
|
|
342
|
-
title: 'AI Assistant',
|
|
343
|
-
subtitle: 'Choose a model and start chatting',
|
|
344
|
-
},
|
|
345
|
-
composer: {
|
|
346
|
-
placeholder: 'Ask me anything...',
|
|
347
|
-
},
|
|
348
|
-
model: {
|
|
349
|
-
showModelPicker: true,
|
|
350
|
-
defaultModel: 'openai/gpt-4o',
|
|
351
|
-
},
|
|
352
|
-
}
|
|
353
|
-
```
|
|
354
|
-
|
|
355
|
-
#### Sidecar Variant with Custom Theme
|
|
356
|
-
|
|
357
|
-
```typescript
|
|
358
|
-
import { ElementsConfig } from '@gram-ai/elements'
|
|
359
|
-
|
|
360
|
-
const config: ElementsConfig = {
|
|
361
|
-
projectSlug: 'my-project',
|
|
362
|
-
mcp: 'https://app.getgram.ai/mcp/my-mcp-slug',
|
|
363
|
-
variant: 'sidecar',
|
|
364
|
-
theme: {
|
|
365
|
-
colorScheme: 'dark',
|
|
366
|
-
density: 'compact',
|
|
367
|
-
radius: 'round',
|
|
368
|
-
},
|
|
369
|
-
welcome: {
|
|
370
|
-
title: 'Support Chat',
|
|
371
|
-
subtitle: "We're here to help",
|
|
372
|
-
},
|
|
373
|
-
sidecar: {
|
|
374
|
-
title: 'Customer Support',
|
|
375
|
-
width: '450px',
|
|
376
|
-
expandedWidth: '900px',
|
|
377
|
-
},
|
|
378
|
-
}
|
|
379
|
-
```
|
|
380
|
-
|
|
381
470
|
## Plugins
|
|
382
471
|
|
|
383
472
|
Plugins extend the Gram Elements library with custom rendering capabilities for specific content types. They allow you to transform markdown code blocks into rich, interactive visualizations and components.
|
|
@@ -2,7 +2,7 @@ import { VariantProps } from 'class-variance-authority';
|
|
|
2
2
|
import * as React from 'react';
|
|
3
3
|
declare const Button: React.ForwardRefExoticComponent<Omit<React.ClassAttributes<HTMLButtonElement> & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<(props?: ({
|
|
4
4
|
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
5
|
-
size?: "icon" | "
|
|
5
|
+
size?: "icon" | "sm" | "lg" | "default" | "icon-sm" | "icon-lg" | null | undefined;
|
|
6
6
|
} & import('class-variance-authority/types').ClassProp) | undefined) => string> & {
|
|
7
7
|
asChild?: boolean;
|
|
8
8
|
}, "ref"> & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export declare const buttonVariants: (props?: ({
|
|
2
2
|
variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
|
|
3
|
-
size?: "icon" | "
|
|
3
|
+
size?: "icon" | "sm" | "lg" | "default" | "icon-sm" | "icon-lg" | null | undefined;
|
|
4
4
|
} & import('class-variance-authority/types').ClassProp) | undefined) => string;
|