@gram-ai/elements 1.23.0 → 1.24.1

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 (70) hide show
  1. package/README.md +61 -0
  2. package/dist/components/Chat/stories/MessageFeedback.stories.d.ts +28 -0
  3. package/dist/components/Chat/stories/Thread.stories.d.ts +15 -0
  4. package/dist/components/Replay.d.ts +11 -0
  5. package/dist/components/Replay.stories.d.ts +34 -0
  6. package/dist/components/assistant-ui/follow-on-suggestions.d.ts +6 -0
  7. package/dist/components/assistant-ui/message-feedback.d.ts +9 -0
  8. package/dist/components/ui/popover.d.ts +3 -1
  9. package/dist/contexts/ReplayContext.d.ts +6 -0
  10. package/dist/elements.cjs +1 -1
  11. package/dist/elements.css +1 -1
  12. package/dist/elements.js +10 -8
  13. package/dist/hooks/useFollowOnSuggestions.d.ts +14 -0
  14. package/dist/hooks/useMCPTools.d.ts +4 -3
  15. package/dist/hooks/useRecordCassette.d.ts +32 -0
  16. package/dist/{index-D-QXb5EF.js → index-BdS8cb9a.js} +12083 -10638
  17. package/dist/index-BdS8cb9a.js.map +1 -0
  18. package/dist/index-ChnOovCM.cjs +178 -0
  19. package/dist/index-ChnOovCM.cjs.map +1 -0
  20. package/dist/{index-vM3v0unX.js → index-CtyV0c-T.js} +5477 -5450
  21. package/dist/index-CtyV0c-T.js.map +1 -0
  22. package/dist/{index-Co05S1C8.cjs → index-iUSSoKFz.cjs} +12 -12
  23. package/dist/index-iUSSoKFz.cjs.map +1 -0
  24. package/dist/index.d.ts +3 -0
  25. package/dist/lib/cassette.d.ts +46 -0
  26. package/dist/plugins.cjs +1 -1
  27. package/dist/plugins.js +1 -1
  28. package/dist/{profiler-Dshm-O8k.cjs → profiler-DLQjMw2x.cjs} +2 -2
  29. package/dist/{profiler-Dshm-O8k.cjs.map → profiler-DLQjMw2x.cjs.map} +1 -1
  30. package/dist/{profiler-D8-vgPGn.js → profiler-zOZcyzDP.js} +2 -2
  31. package/dist/{profiler-D8-vgPGn.js.map → profiler-zOZcyzDP.js.map} +1 -1
  32. package/dist/{startRecording-DnWeZRhl.js → startRecording-BwSGOvz9.js} +2 -2
  33. package/dist/{startRecording-DnWeZRhl.js.map → startRecording-BwSGOvz9.js.map} +1 -1
  34. package/dist/{startRecording-2p7-xVUh.cjs → startRecording-D7lN7PSs.cjs} +2 -2
  35. package/dist/{startRecording-2p7-xVUh.cjs.map → startRecording-D7lN7PSs.cjs.map} +1 -1
  36. package/dist/types/index.d.ts +37 -0
  37. package/package.json +5 -4
  38. package/src/components/Chat/stories/MessageFeedback.stories.tsx +169 -0
  39. package/src/components/Chat/stories/Thread.stories.tsx +78 -0
  40. package/src/components/Chat/stories/Variants.stories.tsx +5 -1
  41. package/src/components/Replay.stories.tsx +326 -0
  42. package/src/components/Replay.tsx +241 -0
  43. package/src/components/assistant-ui/follow-on-suggestions.tsx +122 -0
  44. package/src/components/assistant-ui/markdown-text.tsx +6 -7
  45. package/src/components/assistant-ui/message-feedback.tsx +177 -0
  46. package/src/components/assistant-ui/thread-list.tsx +6 -6
  47. package/src/components/assistant-ui/thread.tsx +322 -83
  48. package/src/components/assistant-ui/tool-fallback.tsx +1 -1
  49. package/src/components/assistant-ui/tool-group.tsx +27 -16
  50. package/src/components/ui/popover.tsx +18 -11
  51. package/src/components/ui/tool-ui.tsx +107 -32
  52. package/src/components/ui/tooltip.tsx +2 -2
  53. package/src/contexts/ElementsProvider.tsx +7 -2
  54. package/src/contexts/ReplayContext.ts +7 -0
  55. package/src/global.css +14 -8
  56. package/src/hooks/useAuth.ts +3 -0
  57. package/src/hooks/useFollowOnSuggestions.ts +237 -0
  58. package/src/hooks/useMCPTools.ts +32 -12
  59. package/src/hooks/useRecordCassette.ts +79 -0
  60. package/src/index.ts +10 -0
  61. package/src/lib/cassette.ts +260 -0
  62. package/src/plugins/chart/component.tsx +48 -11
  63. package/src/plugins/components/PluginLoadingState.tsx +2 -2
  64. package/src/types/index.ts +40 -0
  65. package/src/vite-env.d.ts +1 -0
  66. package/dist/index-CVYyyxfm.cjs +0 -147
  67. package/dist/index-CVYyyxfm.cjs.map +0 -1
  68. package/dist/index-Co05S1C8.cjs.map +0 -1
  69. package/dist/index-D-QXb5EF.js.map +0 -1
  70. package/dist/index-vM3v0unX.js.map +0 -1
package/README.md CHANGED
@@ -263,6 +263,67 @@ To create your own plugins, see the comprehensive [Plugin Development Guide](./s
263
263
  - Real-world examples
264
264
  - Troubleshooting tips
265
265
 
266
+ ## Replay
267
+
268
+ Replay lets you play back a pre-recorded conversation with streaming animations — no auth, MCP, or network calls required. This is useful for marketing demos, documentation, and testing.
269
+
270
+ ### Recording a cassette
271
+
272
+ A cassette is a JSON file that captures a conversation. To record one from a live chat session, enable the built-in recorder by setting this environment variable:
273
+
274
+ ```
275
+ VITE_ELEMENTS_ENABLE_CASSETTE_RECORDING=true
276
+ ```
277
+
278
+ This adds a record button to the composer. Click it to open the recorder popover, then start recording. Chat normally, and when you're done, click **Stop & Download** to save the cassette as a `.cassette.json` file.
279
+
280
+ You can also record programmatically using the `useRecordCassette` hook:
281
+
282
+ ```tsx
283
+ import {
284
+ GramElementsProvider,
285
+ Chat,
286
+ useRecordCassette,
287
+ } from '@gram-ai/elements'
288
+
289
+ function RecordableChat() {
290
+ const { isRecording, startRecording, download } = useRecordCassette()
291
+ return (
292
+ <>
293
+ <Chat />
294
+ <button onClick={startRecording}>Record</button>
295
+ <button onClick={() => download('demo')}>Save</button>
296
+ </>
297
+ )
298
+ }
299
+ ```
300
+
301
+ ### Playing back a cassette
302
+
303
+ Use the `<Replay>` component, which replaces `GramElementsProvider` entirely:
304
+
305
+ ```tsx
306
+ import { Replay, Chat } from '@gram-ai/elements'
307
+ import cassette from './demo.cassette.json'
308
+
309
+ function MarketingDemo() {
310
+ return (
311
+ <Replay cassette={cassette} config={{ variant: 'standalone' }}>
312
+ <Chat />
313
+ </Replay>
314
+ )
315
+ }
316
+ ```
317
+
318
+ `<Replay>` accepts optional timing props to control the playback speed:
319
+
320
+ | Prop | Default | Description |
321
+ | --------------------- | ------- | ----------------------------------------------- |
322
+ | `typingSpeed` | `15` | Milliseconds per character for streaming |
323
+ | `userMessageDelay` | `800` | Milliseconds before each user message appears |
324
+ | `assistantStartDelay` | `400` | Milliseconds before the assistant starts typing |
325
+ | `onComplete` | — | Callback when replay finishes |
326
+
266
327
  ## Contributing
267
328
 
268
329
  We welcome pull requests to Elements. Please read the contributing guide.
@@ -0,0 +1,28 @@
1
+ import { Chat } from '..';
2
+ import { Meta, StoryFn } from '@storybook/react-vite';
3
+ declare const meta: Meta<typeof Chat>;
4
+ export default meta;
5
+ type Story = StoryFn<typeof Chat>;
6
+ /**
7
+ * The feedback buttons appear on the last assistant message after it finishes streaming.
8
+ * Send a message to see the feedback UI animate in.
9
+ */
10
+ export declare const Default: Story;
11
+ /**
12
+ * Widget variant with feedback buttons.
13
+ */
14
+ export declare const Widget: Story;
15
+ /**
16
+ * Sidecar variant with feedback buttons.
17
+ */
18
+ export declare const Sidecar: Story;
19
+ /**
20
+ * Demonstrates feedback UI combined with follow-up suggestions.
21
+ * After the assistant responds, you'll see both AI-generated follow-up questions
22
+ * and feedback buttons (like/dislike) to mark the conversation as resolved.
23
+ */
24
+ export declare const WithFollowUpSuggestions: Story;
25
+ /**
26
+ * Standalone component demo showing the feedback buttons in isolation.
27
+ */
28
+ export declare const ComponentOnly: StoryFn;
@@ -0,0 +1,15 @@
1
+ import { Meta, StoryFn } from '@storybook/react-vite';
2
+ import { Chat } from '..';
3
+ declare const meta: Meta<typeof Chat>;
4
+ export default meta;
5
+ type Story = StoryFn<typeof Chat>;
6
+ /**
7
+ * Demonstrates follow-up suggestions that appear after the assistant responds.
8
+ * Send a message and watch as AI-generated follow-up questions appear below the response.
9
+ */
10
+ export declare const FollowUpSuggestions: Story;
11
+ /**
12
+ * Shows the thread with follow-up suggestions disabled.
13
+ * No suggestions will appear after the assistant responds.
14
+ */
15
+ export declare const FollowUpSuggestionsDisabled: Story;
@@ -0,0 +1,11 @@
1
+ import { Cassette, ReplayOptions } from '../lib/cassette';
2
+ import { ElementsConfig } from '../types';
3
+ import { ReactNode } from 'react';
4
+ export interface ReplayProps extends ReplayOptions {
5
+ /** The recorded cassette to replay. */
6
+ cassette: Cassette;
7
+ children: ReactNode;
8
+ /** Optional ElementsConfig for visual customization (theme, variant, etc.) */
9
+ config?: Partial<ElementsConfig>;
10
+ }
11
+ export declare const Replay: ({ cassette, children, config: partialConfig, typingSpeed, userMessageDelay, assistantStartDelay, onComplete, }: ReplayProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,34 @@
1
+ import { StoryFn } from '@storybook/react-vite';
2
+ import { Replay } from './Replay';
3
+ declare const meta: any;
4
+ export default meta;
5
+ type Story = StoryFn<typeof Replay>;
6
+ /**
7
+ * Basic text conversation replay. Messages stream in character-by-character
8
+ * with a typing effect, just like a real chat session.
9
+ */
10
+ export declare const TextConversation: Story;
11
+ /**
12
+ * Replay with tool calls. The assistant invokes tools with visible
13
+ * arguments and results, demonstrating the tool call rendering pipeline.
14
+ */
15
+ export declare const ToolCalls: Story;
16
+ /**
17
+ * Replay with reasoning (chain-of-thought) content. The assistant's
18
+ * internal reasoning is shown before the final response.
19
+ */
20
+ export declare const Reasoning: Story;
21
+ /**
22
+ * Multi-turn conversation with multiple user/assistant exchanges,
23
+ * demonstrating extended conversations with rich markdown formatting.
24
+ */
25
+ export declare const MultiTurn: Story;
26
+ /**
27
+ * Replay rendered in the widget (modal) variant, showing how replays
28
+ * work inside a modal container.
29
+ */
30
+ export declare const WidgetVariant: Story;
31
+ /**
32
+ * Fast replay with minimal delays — useful for quick demos or testing.
33
+ */
34
+ export declare const FastReplay: Story;
@@ -0,0 +1,6 @@
1
+ import { FC } from 'react';
2
+ /**
3
+ * Displays follow-on suggestions after the assistant finishes responding.
4
+ * These are dynamically generated based on the conversation context.
5
+ */
6
+ export declare const FollowOnSuggestions: FC;
@@ -0,0 +1,9 @@
1
+ import { FC } from 'react';
2
+ export type FeedbackType = 'dislike' | 'like';
3
+ interface MessageFeedbackProps {
4
+ onFeedback?: (type: FeedbackType) => void;
5
+ onResolved?: () => void;
6
+ className?: string;
7
+ }
8
+ export declare const MessageFeedback: FC<MessageFeedbackProps>;
9
+ export {};
@@ -2,6 +2,8 @@ import * as React from 'react';
2
2
  import * as PopoverPrimitive from '@radix-ui/react-popover';
3
3
  declare function Popover({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Root>): import("react/jsx-runtime").JSX.Element;
4
4
  declare function PopoverTrigger({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Trigger>): import("react/jsx-runtime").JSX.Element;
5
- declare function PopoverContent({ className, align, sideOffset, ...props }: React.ComponentProps<typeof PopoverPrimitive.Content>): import("react/jsx-runtime").JSX.Element;
5
+ declare function PopoverContent({ className, align, sideOffset, container, ...props }: React.ComponentProps<typeof PopoverPrimitive.Content> & {
6
+ container?: HTMLElement | null;
7
+ }): import("react/jsx-runtime").JSX.Element;
6
8
  declare function PopoverAnchor({ ...props }: React.ComponentProps<typeof PopoverPrimitive.Anchor>): import("react/jsx-runtime").JSX.Element;
7
9
  export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
@@ -0,0 +1,6 @@
1
+ export declare const ReplayContext: import('react').Context<{
2
+ isReplay: boolean;
3
+ } | null>;
4
+ export declare function useReplayContext(): {
5
+ isReplay: boolean;
6
+ } | null;
package/dist/elements.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-CVYyyxfm.cjs"),r=require("./index-Co05S1C8.cjs");exports.Chat=e.Chat;exports.ChatHistory=e.ChatHistory;exports.ElementsProvider=e.ElementsProvider;exports.GramElementsProvider=e.ElementsProvider;exports.MODELS=e.MODELS;exports.ShareButton=e.ShareButton;exports.defineFrontendTool=e.defineFrontendTool;exports.trackError=e.trackError;exports.useThreadId=e.useThreadId;exports.useElements=r.useElements;exports.useGramElements=r.useElements;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./index-ChnOovCM.cjs"),r=require("./index-iUSSoKFz.cjs");exports.Chat=e.Chat;exports.ChatHistory=e.ChatHistory;exports.ElementsProvider=e.ElementsProvider;exports.GramElementsProvider=e.ElementsProvider;exports.MODELS=e.MODELS;exports.Replay=e.Replay;exports.ShareButton=e.ShareButton;exports.defineFrontendTool=e.defineFrontendTool;exports.trackError=e.trackError;exports.useRecordCassette=e.useRecordCassette;exports.useThreadId=e.useThreadId;exports.useElements=r.useElements;exports.useGramElements=r.useElements;
2
2
  //# sourceMappingURL=elements.cjs.map