@elabs-ai/components-ai 4.0.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/LICENSE +21 -0
- package/README.md +133 -0
- package/dist/_audio-player-media-chrome-KA5DY54G.js +81 -0
- package/dist/_audio-player-media-chrome-KA5DY54G.js.map +1 -0
- package/dist/_flow-boundary-D63PJ65S.js +186 -0
- package/dist/_flow-boundary-D63PJ65S.js.map +1 -0
- package/dist/_interactive-terminal-xterm-ATJ5EW3G.js +11 -0
- package/dist/_interactive-terminal-xterm-ATJ5EW3G.js.map +1 -0
- package/dist/_persona-rive-RFR2EUWP.js +164 -0
- package/dist/_persona-rive-RFR2EUWP.js.map +1 -0
- package/dist/index.d.ts +4079 -0
- package/dist/index.js +11770 -0
- package/dist/index.js.map +1 -0
- package/package.json +87 -0
- package/src/_audio-player-media-chrome.tsx +146 -0
- package/src/_chat-shell-rail.tsx +18 -0
- package/src/_code-block-theme.test.ts +134 -0
- package/src/_code-block-theme.ts +184 -0
- package/src/_flow-boundary.tsx +237 -0
- package/src/_flow-lazy.ts +34 -0
- package/src/_interactive-terminal-xterm.ts +32 -0
- package/src/_lazy-mermaid.test.ts +101 -0
- package/src/_lazy-mermaid.ts +117 -0
- package/src/_persona-rive.tsx +252 -0
- package/src/_streamdown-i18n.ts +119 -0
- package/src/agent-timeline.stories.tsx +66 -0
- package/src/agent-timeline.test.tsx +74 -0
- package/src/agent-timeline.tsx +106 -0
- package/src/agent.tsx +113 -0
- package/src/agentic-workspace.stories.tsx +1099 -0
- package/src/artifact.stories.tsx +62 -0
- package/src/artifact.test.tsx +112 -0
- package/src/artifact.tsx +167 -0
- package/src/asset-preview.stories.tsx +100 -0
- package/src/asset-preview.test.tsx +126 -0
- package/src/asset-preview.tsx +218 -0
- package/src/attachments.tsx +393 -0
- package/src/audio-player.stories.tsx +99 -0
- package/src/audio-player.tsx +170 -0
- package/src/blocks-ai-composer.stories.tsx +83 -0
- package/src/canvas.stories.tsx +142 -0
- package/src/canvas.tsx +29 -0
- package/src/chain-of-thought.tsx +193 -0
- package/src/chat-greeting.stories.tsx +96 -0
- package/src/chat-greeting.test.tsx +91 -0
- package/src/chat-greeting.tsx +91 -0
- package/src/chat-shell.stories.tsx +123 -0
- package/src/chat-shell.test.tsx +113 -0
- package/src/chat-shell.tsx +97 -0
- package/src/chat.stories.tsx +99 -0
- package/src/checkpoint.tsx +54 -0
- package/src/code-block.stories.tsx +81 -0
- package/src/code-block.test.tsx +191 -0
- package/src/code-block.tsx +673 -0
- package/src/commit.tsx +343 -0
- package/src/composer.stories.tsx +188 -0
- package/src/composer.test.tsx +182 -0
- package/src/composer.tsx +202 -0
- package/src/confirmation.stories.tsx +61 -0
- package/src/confirmation.test.tsx +136 -0
- package/src/confirmation.tsx +273 -0
- package/src/connection.tsx +23 -0
- package/src/context-panel.stories.tsx +137 -0
- package/src/context-panel.test.tsx +198 -0
- package/src/context-panel.tsx +609 -0
- package/src/context.stories.tsx +16 -0
- package/src/context.tsx +363 -0
- package/src/controls.tsx +20 -0
- package/src/conversation.stories.tsx +26 -0
- package/src/conversation.test.tsx +123 -0
- package/src/conversation.tsx +143 -0
- package/src/dark-theme-variant.test.ts +47 -0
- package/src/edge.tsx +33 -0
- package/src/environment-variables.tsx +304 -0
- package/src/file-tree.stories.tsx +55 -0
- package/src/file-tree.test.tsx +101 -0
- package/src/file-tree.tsx +390 -0
- package/src/gallery.stories.tsx +182 -0
- package/src/gallery.test.tsx +150 -0
- package/src/gallery.tsx +737 -0
- package/src/grouped-parts.stories.tsx +104 -0
- package/src/grouped-parts.test.tsx +167 -0
- package/src/grouped-parts.tsx +247 -0
- package/src/image.stories.tsx +67 -0
- package/src/image.test.tsx +105 -0
- package/src/image.tsx +115 -0
- package/src/index.ts +93 -0
- package/src/inline-citation.stories.tsx +91 -0
- package/src/inline-citation.test.tsx +96 -0
- package/src/inline-citation.tsx +314 -0
- package/src/interactive-terminal.stories.tsx +165 -0
- package/src/interactive-terminal.test.tsx +448 -0
- package/src/interactive-terminal.tsx +444 -0
- package/src/jsx-preview.stories.tsx +265 -0
- package/src/jsx-preview.test.tsx +75 -0
- package/src/jsx-preview.tsx +409 -0
- package/src/markdown-view.stories.tsx +57 -0
- package/src/markdown-view.test.tsx +36 -0
- package/src/markdown-view.tsx +113 -0
- package/src/message-edit.stories.tsx +150 -0
- package/src/message-edit.test.tsx +115 -0
- package/src/message-edit.tsx +336 -0
- package/src/message-feedback.stories.tsx +53 -0
- package/src/message-feedback.test.tsx +62 -0
- package/src/message-feedback.tsx +117 -0
- package/src/message-form-spec.ts +349 -0
- package/src/message-form.stories.tsx +182 -0
- package/src/message-form.test.tsx +227 -0
- package/src/message-form.tsx +845 -0
- package/src/message-table-spec.ts +281 -0
- package/src/message-table.stories.tsx +176 -0
- package/src/message-table.test.tsx +144 -0
- package/src/message-table.tsx +366 -0
- package/src/message.stories.tsx +262 -0
- package/src/message.test.tsx +508 -0
- package/src/message.tsx +619 -0
- package/src/mic-selector.tsx +339 -0
- package/src/microcopy.test.tsx +123 -0
- package/src/model-selector.stories.tsx +73 -0
- package/src/model-selector.test.tsx +55 -0
- package/src/model-selector.tsx +225 -0
- package/src/motion-config.tsx +49 -0
- package/src/node.tsx +71 -0
- package/src/open-in-chat.tsx +340 -0
- package/src/package-info.tsx +205 -0
- package/src/panel.tsx +20 -0
- package/src/part-groups.ts +258 -0
- package/src/persona-sources.ts +59 -0
- package/src/persona.stories.tsx +111 -0
- package/src/persona.test.tsx +67 -0
- package/src/persona.tsx +148 -0
- package/src/plan.tsx +135 -0
- package/src/prompt-input.stories.tsx +261 -0
- package/src/prompt-input.test.tsx +392 -0
- package/src/prompt-input.tsx +1668 -0
- package/src/queue.tsx +237 -0
- package/src/reasoning.stories.tsx +81 -0
- package/src/reasoning.test.tsx +50 -0
- package/src/reasoning.tsx +229 -0
- package/src/sandbox.stories.tsx +62 -0
- package/src/sandbox.test.tsx +42 -0
- package/src/sandbox.tsx +149 -0
- package/src/schema-display.tsx +412 -0
- package/src/selection-toolbar.stories.tsx +86 -0
- package/src/selection-toolbar.test.tsx +89 -0
- package/src/selection-toolbar.tsx +192 -0
- package/src/shimmer.stories.tsx +10 -0
- package/src/shimmer.tsx +81 -0
- package/src/snippet.stories.tsx +19 -0
- package/src/snippet.test.tsx +116 -0
- package/src/snippet.tsx +138 -0
- package/src/sources.stories.tsx +34 -0
- package/src/sources.test.tsx +129 -0
- package/src/sources.tsx +93 -0
- package/src/speech-input.tsx +312 -0
- package/src/stack-trace.tsx +479 -0
- package/src/streamdown-i18n.test.tsx +163 -0
- package/src/suggestion.stories.tsx +75 -0
- package/src/suggestion.test.tsx +72 -0
- package/src/suggestion.tsx +120 -0
- package/src/task.stories.tsx +22 -0
- package/src/task.test.tsx +36 -0
- package/src/task.tsx +89 -0
- package/src/templates-ai-assistant.stories.tsx +142 -0
- package/src/terminal.tsx +244 -0
- package/src/test-results.stories.tsx +177 -0
- package/src/test-results.test.tsx +241 -0
- package/src/test-results.tsx +408 -0
- package/src/tool-result-card.stories.tsx +143 -0
- package/src/tool-result-card.test.tsx +72 -0
- package/src/tool-result-card.tsx +86 -0
- package/src/tool.stories.tsx +60 -0
- package/src/tool.test.tsx +63 -0
- package/src/tool.tsx +235 -0
- package/src/toolbar.tsx +44 -0
- package/src/transcription.tsx +118 -0
- package/src/voice-selector.tsx +469 -0
- package/src/web-preview.stories.tsx +67 -0
- package/src/web-preview.test.tsx +117 -0
- package/src/web-preview.tsx +283 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Manuel Reimitz
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
<!-- brand-ui:gen:readme:start -->
|
|
2
|
+
<!-- Generated by scripts/gen-package-readmes.mjs — do not edit inside these markers. -->
|
|
3
|
+
|
|
4
|
+
# `@elabs-ai/components-ai`
|
|
5
|
+
|
|
6
|
+
> ChatShell, Conversation, Message, PromptInput, Tool, Reasoning, citations.
|
|
7
|
+
|
|
8
|
+
Part of **brand-ui**, a source-owned, token-driven React component system.
|
|
9
|
+
These packages are **private** and are not published to any registry — they are
|
|
10
|
+
consumed from this workspace. See `docs/CONSUMING.md`.
|
|
11
|
+
|
|
12
|
+
## Install
|
|
13
|
+
|
|
14
|
+
Inside this monorepo the packages resolve as workspace dependencies:
|
|
15
|
+
|
|
16
|
+
```json
|
|
17
|
+
"@elabs-ai/components-ai": "workspace:*"
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Set up styling (do not skip)
|
|
21
|
+
|
|
22
|
+
Components are Tailwind v4 classes backed by semantic tokens. Two lines in
|
|
23
|
+
your CSS entry, or **everything renders unstyled** — the single most common
|
|
24
|
+
mistake:
|
|
25
|
+
|
|
26
|
+
```css
|
|
27
|
+
@import "@elabs-ai/components-tokens/styles.css";
|
|
28
|
+
@source "../node_modules/@elabs-ai/components-ai/dist";
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The `@source` line is required because Tailwind ignores `node_modules`. Add
|
|
32
|
+
one per brand-ui package you render. Then wrap your app once:
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { ThemeProvider } from "@elabs-ai/components-tokens";
|
|
36
|
+
|
|
37
|
+
<ThemeProvider defaultTheme="light">{children}</ThemeProvider>;
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## This package specifically
|
|
41
|
+
|
|
42
|
+
- `ai` (Vercel AI SDK) `^6` is a **types-only** peer — your app owns the model calls.
|
|
43
|
+
- `@xyflow/react` is a peer too, if you render the agent canvas.
|
|
44
|
+
|
|
45
|
+
## What's in it
|
|
46
|
+
|
|
47
|
+
443 exported components — including `Agent`, `AgentContent`, `AgentHeader`, `AgentInstructions`, `AgentMessage`.
|
|
48
|
+
|
|
49
|
+
Don't guess the API — ask the CLI:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pnpm add -D @elabs-ai/components-cli
|
|
53
|
+
pnpm exec brand-ui search <query> # find a component
|
|
54
|
+
pnpm exec brand-ui docs <Name> # its real props, from source
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Using an AI coding agent?
|
|
58
|
+
|
|
59
|
+
For Claude Code, install the plugin from this repo's checkout:
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
/plugin marketplace add .
|
|
63
|
+
/plugin install brand-ui
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`brand-ui docs <Name>` returns intent, composition, state→token mappings and
|
|
67
|
+
anti-patterns — tell your agent to run it instead of guessing a prop. The CLI
|
|
68
|
+
also runs as an MCP server (`brand-ui mcp`).
|
|
69
|
+
|
|
70
|
+
## Full guide
|
|
71
|
+
|
|
72
|
+
Tailwind and Next.js wiring, per-package extras, agent enablement and a
|
|
73
|
+
prompt for migrating an existing project: `docs/CONSUMING.md`.
|
|
74
|
+
|
|
75
|
+
## License
|
|
76
|
+
|
|
77
|
+
UNLICENSED — private.
|
|
78
|
+
|
|
79
|
+
<!-- brand-ui:gen:readme:end -->
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Package detail
|
|
84
|
+
|
|
85
|
+
Presentational AI/chat components — `ChatShell`, `Conversation`, `Message`,
|
|
86
|
+
`PromptInput`/`Composer`, `Tool`, `Reasoning`, `Sources`, `Artifact`,
|
|
87
|
+
`ContextPanel`, and the workspace/agent set.
|
|
88
|
+
|
|
89
|
+
The components render the AI SDK `UIMessage` data model. **Your app owns the model
|
|
90
|
+
calls** (`useChat`, transport, providers) — `@elabs-ai/components-ai` imports the `ai` SDK as
|
|
91
|
+
**types only**, never at runtime (D6 / ADR-0008). See `docs/DECISIONS.md` §D5.
|
|
92
|
+
|
|
93
|
+
Usage, props and composition patterns live in Storybook and
|
|
94
|
+
`docs/component-inventory.md`. This file covers only what you need to know when
|
|
95
|
+
**deploying** it.
|
|
96
|
+
|
|
97
|
+
## Network egress
|
|
98
|
+
|
|
99
|
+
Two components reach third-party origins at runtime, and several link out. Under a
|
|
100
|
+
restrictive CSP these fail — usually silently.
|
|
101
|
+
|
|
102
|
+
| What | Origin | Directive | Escape hatch |
|
|
103
|
+
| ---------------------------------- | ------------------------------------------------------------- | ----------------- | --------------------------------------------------------------- |
|
|
104
|
+
| `ModelSelectorLogo` provider logos | `models.dev` | `img-src` | `src` for a self-hosted asset, or `fallback` |
|
|
105
|
+
| `Persona` Rive artwork | `*.public.blob.vercel-storage.com` | `connect-src` | self-host and pass `src`; blocked loads render a fallback orb |
|
|
106
|
+
| `OpenIn*` deep links | chatgpt.com, claude.ai, cursor.com, scira.ai, t3.chat, v0.app | none (navigation) | don't render the component — note the prompt travels in the URL |
|
|
107
|
+
|
|
108
|
+
Full detail, the exact CSP snippet, and the offline checklist:
|
|
109
|
+
**[`docs/CSP-AND-NETWORK.md`](../../docs/CSP-AND-NETWORK.md)**.
|
|
110
|
+
|
|
111
|
+
## Trusted Types
|
|
112
|
+
|
|
113
|
+
Under `require-trusted-types-for 'script'`, two transitive markdown dependencies
|
|
114
|
+
resolve to `innerHTML`/`DOMParser` builds and blank content (a message containing
|
|
115
|
+
`&` renders empty), and Mermaid's DOMPurify installs a pass-through policy
|
|
116
|
+
named `dompurify`.
|
|
117
|
+
|
|
118
|
+
A library cannot fix this for you — it is export-condition selection in **your**
|
|
119
|
+
bundler. The copy-pasteable alias snippet and the CSP directives are in
|
|
120
|
+
[`docs/CSP-AND-NETWORK.md`](../../docs/CSP-AND-NETWORK.md) §2, and this repo
|
|
121
|
+
dogfoods them in `apps/playground` and `apps/docs`.
|
|
122
|
+
|
|
123
|
+
## Bundle size
|
|
124
|
+
|
|
125
|
+
Heavy engines load on demand rather than riding in your entry chunk:
|
|
126
|
+
|
|
127
|
+
- **Mermaid** (plus d3 and DOMPurify) loads on the first diagram render. Call
|
|
128
|
+
`preloadMermaid()` to warm it early on a surface you know renders diagrams.
|
|
129
|
+
- **The Rive WebGL2 runtime** loads only when a `Persona` mounts.
|
|
130
|
+
|
|
131
|
+
Both are enforced by `pnpm heavy-deps:check`. See ADR 0019. The remaining eager
|
|
132
|
+
engines (React Flow, xterm, media-chrome) are tracked in that gate's baseline
|
|
133
|
+
(the React Flow canvas set is a separate, intentional surface — see ADR 0018).
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
|
|
4
|
+
// src/_audio-player-media-chrome.tsx
|
|
5
|
+
import { Button, ButtonGroup, ButtonGroupText } from "@elabs-ai/components-ui";
|
|
6
|
+
import { cn } from "@elabs-ai/components-ui/lib/cn";
|
|
7
|
+
import {
|
|
8
|
+
MediaControlBar,
|
|
9
|
+
MediaController,
|
|
10
|
+
MediaDurationDisplay,
|
|
11
|
+
MediaMuteButton,
|
|
12
|
+
MediaPlayButton,
|
|
13
|
+
MediaSeekBackwardButton,
|
|
14
|
+
MediaSeekForwardButton,
|
|
15
|
+
MediaTimeDisplay,
|
|
16
|
+
MediaTimeRange,
|
|
17
|
+
MediaVolumeRange
|
|
18
|
+
} from "media-chrome/react";
|
|
19
|
+
import { jsx } from "react/jsx-runtime";
|
|
20
|
+
var AudioPlayer = ({ children, style, ...props }) => /* @__PURE__ */ jsx(
|
|
21
|
+
MediaController,
|
|
22
|
+
{
|
|
23
|
+
audio: true,
|
|
24
|
+
style: {
|
|
25
|
+
"--media-background-color": "transparent",
|
|
26
|
+
"--media-button-icon-height": "1rem",
|
|
27
|
+
"--media-button-icon-width": "1rem",
|
|
28
|
+
"--media-control-background": "transparent",
|
|
29
|
+
"--media-control-hover-background": "var(--color-accent)",
|
|
30
|
+
"--media-control-padding": "0",
|
|
31
|
+
"--media-font": "var(--font-sans)",
|
|
32
|
+
"--media-font-size": "10px",
|
|
33
|
+
"--media-icon-color": "currentColor",
|
|
34
|
+
"--media-preview-time-background": "var(--color-background)",
|
|
35
|
+
"--media-preview-time-border-radius": "var(--radius-md)",
|
|
36
|
+
"--media-preview-time-text-shadow": "none",
|
|
37
|
+
"--media-primary-color": "var(--color-primary)",
|
|
38
|
+
"--media-range-bar-color": "var(--color-primary)",
|
|
39
|
+
"--media-range-track-background": "var(--color-secondary)",
|
|
40
|
+
"--media-secondary-color": "var(--color-secondary)",
|
|
41
|
+
"--media-text-color": "var(--color-foreground)",
|
|
42
|
+
"--media-tooltip-arrow-display": "none",
|
|
43
|
+
"--media-tooltip-background": "var(--color-background)",
|
|
44
|
+
"--media-tooltip-border-radius": "var(--radius-md)",
|
|
45
|
+
...style
|
|
46
|
+
},
|
|
47
|
+
...props,
|
|
48
|
+
children
|
|
49
|
+
}
|
|
50
|
+
);
|
|
51
|
+
var AudioPlayerControlBar = ({ children, ...props }) => /* @__PURE__ */ jsx(MediaControlBar, { ...props, children: /* @__PURE__ */ jsx(ButtonGroup, { orientation: "horizontal", children }) });
|
|
52
|
+
var AudioPlayerPlayButton = ({ className, ...props }) => /* @__PURE__ */ jsx(Button, { asChild: true, size: "icon-sm", variant: "outline", children: /* @__PURE__ */ jsx(MediaPlayButton, { className: cn("bg-transparent", className), ...props }) });
|
|
53
|
+
var AudioPlayerSeekBackwardButton = ({
|
|
54
|
+
seekOffset = 10,
|
|
55
|
+
...props
|
|
56
|
+
}) => /* @__PURE__ */ jsx(Button, { asChild: true, size: "icon-sm", variant: "outline", children: /* @__PURE__ */ jsx(MediaSeekBackwardButton, { seekOffset, ...props }) });
|
|
57
|
+
var AudioPlayerSeekForwardButton = ({
|
|
58
|
+
seekOffset = 10,
|
|
59
|
+
...props
|
|
60
|
+
}) => /* @__PURE__ */ jsx(Button, { asChild: true, size: "icon-sm", variant: "outline", children: /* @__PURE__ */ jsx(MediaSeekForwardButton, { seekOffset, ...props }) });
|
|
61
|
+
var AudioPlayerTimeDisplay = ({ className, ...props }) => /* @__PURE__ */ jsx(ButtonGroupText, { asChild: true, className: "bg-transparent", children: /* @__PURE__ */ jsx(MediaTimeDisplay, { className: cn("tabular-nums", className), ...props }) });
|
|
62
|
+
var AudioPlayerTimeRange = ({ className, ...props }) => /* @__PURE__ */ jsx(ButtonGroupText, { asChild: true, className: "bg-transparent", children: /* @__PURE__ */ jsx(MediaTimeRange, { className: cn("", className), ...props }) });
|
|
63
|
+
var AudioPlayerDurationDisplay = ({
|
|
64
|
+
className,
|
|
65
|
+
...props
|
|
66
|
+
}) => /* @__PURE__ */ jsx(ButtonGroupText, { asChild: true, className: "bg-transparent", children: /* @__PURE__ */ jsx(MediaDurationDisplay, { className: cn("tabular-nums", className), ...props }) });
|
|
67
|
+
var AudioPlayerMuteButton = ({ className, ...props }) => /* @__PURE__ */ jsx(ButtonGroupText, { asChild: true, className: "bg-transparent", children: /* @__PURE__ */ jsx(MediaMuteButton, { className: cn("", className), ...props }) });
|
|
68
|
+
var AudioPlayerVolumeRange = ({ className, ...props }) => /* @__PURE__ */ jsx(ButtonGroupText, { asChild: true, className: "bg-transparent", children: /* @__PURE__ */ jsx(MediaVolumeRange, { className: cn("", className), ...props }) });
|
|
69
|
+
export {
|
|
70
|
+
AudioPlayer,
|
|
71
|
+
AudioPlayerControlBar,
|
|
72
|
+
AudioPlayerDurationDisplay,
|
|
73
|
+
AudioPlayerMuteButton,
|
|
74
|
+
AudioPlayerPlayButton,
|
|
75
|
+
AudioPlayerSeekBackwardButton,
|
|
76
|
+
AudioPlayerSeekForwardButton,
|
|
77
|
+
AudioPlayerTimeDisplay,
|
|
78
|
+
AudioPlayerTimeRange,
|
|
79
|
+
AudioPlayerVolumeRange
|
|
80
|
+
};
|
|
81
|
+
//# sourceMappingURL=_audio-player-media-chrome-KA5DY54G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/_audio-player-media-chrome.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * The media-chrome half of `AudioPlayer`, split out so it can be `lazy()`-loaded.\n *\n * `media-chrome` declares no `sideEffects`, so a static import from\n * `audio-player.tsx` put the whole custom-element library (and the\n * `media-chrome/react` wrappers that register it) into the entry chunk of every\n * `@elabs-ai/components-ai` consumer — including the vast majority that\n * never render an `AudioPlayer`. Keeping every media-chrome *value* import in\n * this module, reached only through\n * `lazy(() => import(\"./_audio-player-media-chrome\"))`, confines it to its own\n * chunk. `audio-player.tsx` still owns the public prop types and imports the\n * media-chrome element types with `import type` (types erase).\n *\n * See ADR 0019 and `pnpm heavy-deps:check`.\n *\n * @lazy-boundary This module must only ever be reached via `import()`. The gate\n * fails if anything imports it statically, which would put media-chrome back in\n * the entry chunk and make the `lazy()` pointless.\n */\nimport { Button, ButtonGroup, ButtonGroupText } from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport {\n MediaControlBar,\n MediaController,\n MediaDurationDisplay,\n MediaMuteButton,\n MediaPlayButton,\n MediaSeekBackwardButton,\n MediaSeekForwardButton,\n MediaTimeDisplay,\n MediaTimeRange,\n MediaVolumeRange,\n} from \"media-chrome/react\";\nimport type { CSSProperties } from \"react\";\n\nimport type {\n AudioPlayerControlBarProps,\n AudioPlayerDurationDisplayProps,\n AudioPlayerMuteButtonProps,\n AudioPlayerPlayButtonProps,\n AudioPlayerProps,\n AudioPlayerSeekBackwardButtonProps,\n AudioPlayerSeekForwardButtonProps,\n AudioPlayerTimeDisplayProps,\n AudioPlayerTimeRangeProps,\n AudioPlayerVolumeRangeProps,\n} from \"./audio-player\";\n\nexport const AudioPlayer = ({ children, style, ...props }: AudioPlayerProps) => (\n <MediaController\n audio\n style={\n {\n \"--media-background-color\": \"transparent\",\n \"--media-button-icon-height\": \"1rem\",\n \"--media-button-icon-width\": \"1rem\",\n \"--media-control-background\": \"transparent\",\n \"--media-control-hover-background\": \"var(--color-accent)\",\n \"--media-control-padding\": \"0\",\n \"--media-font\": \"var(--font-sans)\",\n \"--media-font-size\": \"10px\",\n \"--media-icon-color\": \"currentColor\",\n \"--media-preview-time-background\": \"var(--color-background)\",\n \"--media-preview-time-border-radius\": \"var(--radius-md)\",\n \"--media-preview-time-text-shadow\": \"none\",\n \"--media-primary-color\": \"var(--color-primary)\",\n \"--media-range-bar-color\": \"var(--color-primary)\",\n \"--media-range-track-background\": \"var(--color-secondary)\",\n \"--media-secondary-color\": \"var(--color-secondary)\",\n \"--media-text-color\": \"var(--color-foreground)\",\n \"--media-tooltip-arrow-display\": \"none\",\n \"--media-tooltip-background\": \"var(--color-background)\",\n \"--media-tooltip-border-radius\": \"var(--radius-md)\",\n ...style,\n } as CSSProperties\n }\n {...props}\n >\n {children}\n </MediaController>\n);\n\nexport const AudioPlayerControlBar = ({ children, ...props }: AudioPlayerControlBarProps) => (\n <MediaControlBar {...props}>\n <ButtonGroup orientation=\"horizontal\">{children}</ButtonGroup>\n </MediaControlBar>\n);\n\nexport const AudioPlayerPlayButton = ({ className, ...props }: AudioPlayerPlayButtonProps) => (\n <Button asChild size=\"icon-sm\" variant=\"outline\">\n <MediaPlayButton className={cn(\"bg-transparent\", className)} {...props} />\n </Button>\n);\n\nexport const AudioPlayerSeekBackwardButton = ({\n seekOffset = 10,\n ...props\n}: AudioPlayerSeekBackwardButtonProps) => (\n <Button asChild size=\"icon-sm\" variant=\"outline\">\n <MediaSeekBackwardButton seekOffset={seekOffset} {...props} />\n </Button>\n);\n\nexport const AudioPlayerSeekForwardButton = ({\n seekOffset = 10,\n ...props\n}: AudioPlayerSeekForwardButtonProps) => (\n <Button asChild size=\"icon-sm\" variant=\"outline\">\n <MediaSeekForwardButton seekOffset={seekOffset} {...props} />\n </Button>\n);\n\nexport const AudioPlayerTimeDisplay = ({ className, ...props }: AudioPlayerTimeDisplayProps) => (\n <ButtonGroupText asChild className=\"bg-transparent\">\n <MediaTimeDisplay className={cn(\"tabular-nums\", className)} {...props} />\n </ButtonGroupText>\n);\n\nexport const AudioPlayerTimeRange = ({ className, ...props }: AudioPlayerTimeRangeProps) => (\n <ButtonGroupText asChild className=\"bg-transparent\">\n <MediaTimeRange className={cn(\"\", className)} {...props} />\n </ButtonGroupText>\n);\n\nexport const AudioPlayerDurationDisplay = ({\n className,\n ...props\n}: AudioPlayerDurationDisplayProps) => (\n <ButtonGroupText asChild className=\"bg-transparent\">\n <MediaDurationDisplay className={cn(\"tabular-nums\", className)} {...props} />\n </ButtonGroupText>\n);\n\nexport const AudioPlayerMuteButton = ({ className, ...props }: AudioPlayerMuteButtonProps) => (\n <ButtonGroupText asChild className=\"bg-transparent\">\n <MediaMuteButton className={cn(\"\", className)} {...props} />\n </ButtonGroupText>\n);\n\nexport const AudioPlayerVolumeRange = ({ className, ...props }: AudioPlayerVolumeRangeProps) => (\n <ButtonGroupText asChild className=\"bg-transparent\">\n <MediaVolumeRange className={cn(\"\", className)} {...props} />\n </ButtonGroupText>\n);\n"],"mappings":";;;;AAqBA,SAAS,QAAQ,aAAa,uBAAuB;AACrD,SAAS,UAAU;AACnB;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAiBL;AADK,IAAM,cAAc,CAAC,EAAE,UAAU,OAAO,GAAG,MAAM,MACtD;AAAA,EAAC;AAAA;AAAA,IACC,OAAK;AAAA,IACL,OACE;AAAA,MACE,4BAA4B;AAAA,MAC5B,8BAA8B;AAAA,MAC9B,6BAA6B;AAAA,MAC7B,8BAA8B;AAAA,MAC9B,oCAAoC;AAAA,MACpC,2BAA2B;AAAA,MAC3B,gBAAgB;AAAA,MAChB,qBAAqB;AAAA,MACrB,sBAAsB;AAAA,MACtB,mCAAmC;AAAA,MACnC,sCAAsC;AAAA,MACtC,oCAAoC;AAAA,MACpC,yBAAyB;AAAA,MACzB,2BAA2B;AAAA,MAC3B,kCAAkC;AAAA,MAClC,2BAA2B;AAAA,MAC3B,sBAAsB;AAAA,MACtB,iCAAiC;AAAA,MACjC,8BAA8B;AAAA,MAC9B,iCAAiC;AAAA,MACjC,GAAG;AAAA,IACL;AAAA,IAED,GAAG;AAAA,IAEH;AAAA;AACH;AAGK,IAAM,wBAAwB,CAAC,EAAE,UAAU,GAAG,MAAM,MACzD,oBAAC,mBAAiB,GAAG,OACnB,8BAAC,eAAY,aAAY,cAAc,UAAS,GAClD;AAGK,IAAM,wBAAwB,CAAC,EAAE,WAAW,GAAG,MAAM,MAC1D,oBAAC,UAAO,SAAO,MAAC,MAAK,WAAU,SAAQ,WACrC,8BAAC,mBAAgB,WAAW,GAAG,kBAAkB,SAAS,GAAI,GAAG,OAAO,GAC1E;AAGK,IAAM,gCAAgC,CAAC;AAAA,EAC5C,aAAa;AAAA,EACb,GAAG;AACL,MACE,oBAAC,UAAO,SAAO,MAAC,MAAK,WAAU,SAAQ,WACrC,8BAAC,2BAAwB,YAAyB,GAAG,OAAO,GAC9D;AAGK,IAAM,+BAA+B,CAAC;AAAA,EAC3C,aAAa;AAAA,EACb,GAAG;AACL,MACE,oBAAC,UAAO,SAAO,MAAC,MAAK,WAAU,SAAQ,WACrC,8BAAC,0BAAuB,YAAyB,GAAG,OAAO,GAC7D;AAGK,IAAM,yBAAyB,CAAC,EAAE,WAAW,GAAG,MAAM,MAC3D,oBAAC,mBAAgB,SAAO,MAAC,WAAU,kBACjC,8BAAC,oBAAiB,WAAW,GAAG,gBAAgB,SAAS,GAAI,GAAG,OAAO,GACzE;AAGK,IAAM,uBAAuB,CAAC,EAAE,WAAW,GAAG,MAAM,MACzD,oBAAC,mBAAgB,SAAO,MAAC,WAAU,kBACjC,8BAAC,kBAAe,WAAW,GAAG,IAAI,SAAS,GAAI,GAAG,OAAO,GAC3D;AAGK,IAAM,6BAA6B,CAAC;AAAA,EACzC;AAAA,EACA,GAAG;AACL,MACE,oBAAC,mBAAgB,SAAO,MAAC,WAAU,kBACjC,8BAAC,wBAAqB,WAAW,GAAG,gBAAgB,SAAS,GAAI,GAAG,OAAO,GAC7E;AAGK,IAAM,wBAAwB,CAAC,EAAE,WAAW,GAAG,MAAM,MAC1D,oBAAC,mBAAgB,SAAO,MAAC,WAAU,kBACjC,8BAAC,mBAAgB,WAAW,GAAG,IAAI,SAAS,GAAI,GAAG,OAAO,GAC5D;AAGK,IAAM,yBAAyB,CAAC,EAAE,WAAW,GAAG,MAAM,MAC3D,oBAAC,mBAAgB,SAAO,MAAC,WAAU,kBACjC,8BAAC,oBAAiB,WAAW,GAAG,IAAI,SAAS,GAAI,GAAG,OAAO,GAC7D;","names":[]}
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
|
|
4
|
+
// src/_flow-boundary.tsx
|
|
5
|
+
import { Card } from "@elabs-ai/components-ui";
|
|
6
|
+
import { cn } from "@elabs-ai/components-ui/lib/cn";
|
|
7
|
+
import {
|
|
8
|
+
Background,
|
|
9
|
+
BaseEdge,
|
|
10
|
+
Controls as ControlsPrimitive,
|
|
11
|
+
getBezierPath,
|
|
12
|
+
getSimpleBezierPath,
|
|
13
|
+
Handle,
|
|
14
|
+
NodeToolbar,
|
|
15
|
+
Panel as PanelPrimitive,
|
|
16
|
+
Position,
|
|
17
|
+
ReactFlow,
|
|
18
|
+
useInternalNode
|
|
19
|
+
} from "@xyflow/react";
|
|
20
|
+
import "@xyflow/react/dist/style.css";
|
|
21
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
22
|
+
var deleteKeyCode = ["Backspace", "Delete"];
|
|
23
|
+
var proOptions = { hideAttribution: true };
|
|
24
|
+
var Canvas = ({ children, ...props }) => /* @__PURE__ */ jsxs(
|
|
25
|
+
ReactFlow,
|
|
26
|
+
{
|
|
27
|
+
deleteKeyCode,
|
|
28
|
+
fitView: true,
|
|
29
|
+
panOnDrag: false,
|
|
30
|
+
panOnScroll: true,
|
|
31
|
+
proOptions,
|
|
32
|
+
selectionOnDrag: true,
|
|
33
|
+
zoomOnDoubleClick: false,
|
|
34
|
+
...props,
|
|
35
|
+
children: [
|
|
36
|
+
/* @__PURE__ */ jsx(Background, { bgColor: "var(--sidebar)" }),
|
|
37
|
+
children
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
var Controls = ({ className, ...props }) => /* @__PURE__ */ jsx(
|
|
42
|
+
ControlsPrimitive,
|
|
43
|
+
{
|
|
44
|
+
className: cn(
|
|
45
|
+
"gap-px overflow-hidden rounded-md border bg-card p-1 shadow-none!",
|
|
46
|
+
"[&>button]:rounded-md [&>button]:border-none! [&>button]:bg-transparent! [&>button]:hover:bg-secondary!",
|
|
47
|
+
className
|
|
48
|
+
),
|
|
49
|
+
...props
|
|
50
|
+
}
|
|
51
|
+
);
|
|
52
|
+
var EdgeTemporary = ({
|
|
53
|
+
id,
|
|
54
|
+
sourceX,
|
|
55
|
+
sourceY,
|
|
56
|
+
targetX,
|
|
57
|
+
targetY,
|
|
58
|
+
sourcePosition,
|
|
59
|
+
targetPosition
|
|
60
|
+
}) => {
|
|
61
|
+
const [edgePath] = getSimpleBezierPath({
|
|
62
|
+
sourcePosition,
|
|
63
|
+
sourceX,
|
|
64
|
+
sourceY,
|
|
65
|
+
targetPosition,
|
|
66
|
+
targetX,
|
|
67
|
+
targetY
|
|
68
|
+
});
|
|
69
|
+
return /* @__PURE__ */ jsx(
|
|
70
|
+
BaseEdge,
|
|
71
|
+
{
|
|
72
|
+
className: "stroke-1 stroke-ring",
|
|
73
|
+
id,
|
|
74
|
+
path: edgePath,
|
|
75
|
+
style: {
|
|
76
|
+
strokeDasharray: "5, 5"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
var getHandleCoordsByPosition = (node, handlePosition) => {
|
|
82
|
+
const handleType = handlePosition === Position.Left ? "target" : "source";
|
|
83
|
+
const handle = node.internals.handleBounds?.[handleType]?.find(
|
|
84
|
+
(h) => h.position === handlePosition
|
|
85
|
+
);
|
|
86
|
+
if (!handle) {
|
|
87
|
+
return [0, 0];
|
|
88
|
+
}
|
|
89
|
+
let offsetX = handle.width / 2;
|
|
90
|
+
let offsetY = handle.height / 2;
|
|
91
|
+
switch (handlePosition) {
|
|
92
|
+
case Position.Left: {
|
|
93
|
+
offsetX = 0;
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case Position.Right: {
|
|
97
|
+
offsetX = handle.width;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
case Position.Top: {
|
|
101
|
+
offsetY = 0;
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
case Position.Bottom: {
|
|
105
|
+
offsetY = handle.height;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
default: {
|
|
109
|
+
throw new Error(`Invalid handle position: ${handlePosition}`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
const x = node.internals.positionAbsolute.x + handle.x + offsetX;
|
|
113
|
+
const y = node.internals.positionAbsolute.y + handle.y + offsetY;
|
|
114
|
+
return [x, y];
|
|
115
|
+
};
|
|
116
|
+
var getEdgeParams = (source, target) => {
|
|
117
|
+
const sourcePos = Position.Right;
|
|
118
|
+
const [sx, sy] = getHandleCoordsByPosition(source, sourcePos);
|
|
119
|
+
const targetPos = Position.Left;
|
|
120
|
+
const [tx, ty] = getHandleCoordsByPosition(target, targetPos);
|
|
121
|
+
return {
|
|
122
|
+
sourcePos,
|
|
123
|
+
sx,
|
|
124
|
+
sy,
|
|
125
|
+
targetPos,
|
|
126
|
+
tx,
|
|
127
|
+
ty
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
var EdgeAnimated = ({ id, source, target, markerEnd, style }) => {
|
|
131
|
+
const sourceNode = useInternalNode(source);
|
|
132
|
+
const targetNode = useInternalNode(target);
|
|
133
|
+
if (!(sourceNode && targetNode)) {
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
const { sx, sy, tx, ty, sourcePos, targetPos } = getEdgeParams(sourceNode, targetNode);
|
|
137
|
+
const [edgePath] = getBezierPath({
|
|
138
|
+
sourcePosition: sourcePos,
|
|
139
|
+
sourceX: sx,
|
|
140
|
+
sourceY: sy,
|
|
141
|
+
targetPosition: targetPos,
|
|
142
|
+
targetX: tx,
|
|
143
|
+
targetY: ty
|
|
144
|
+
});
|
|
145
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
146
|
+
/* @__PURE__ */ jsx(BaseEdge, { id, markerEnd, path: edgePath, style }),
|
|
147
|
+
/* @__PURE__ */ jsx("circle", { fill: "var(--primary)", r: "4", children: /* @__PURE__ */ jsx("animateMotion", { dur: "2s", path: edgePath, repeatCount: "indefinite" }) })
|
|
148
|
+
] });
|
|
149
|
+
};
|
|
150
|
+
var Node = ({ handles, className, ...props }) => /* @__PURE__ */ jsxs(
|
|
151
|
+
Card,
|
|
152
|
+
{
|
|
153
|
+
className: cn("node-container relative size-full h-auto w-sm gap-0 rounded-md p-0", className),
|
|
154
|
+
...props,
|
|
155
|
+
children: [
|
|
156
|
+
handles.target && /* @__PURE__ */ jsx(Handle, { position: Position.Left, type: "target" }),
|
|
157
|
+
handles.source && /* @__PURE__ */ jsx(Handle, { position: Position.Right, type: "source" }),
|
|
158
|
+
props.children
|
|
159
|
+
]
|
|
160
|
+
}
|
|
161
|
+
);
|
|
162
|
+
var Panel = ({ className, ...props }) => /* @__PURE__ */ jsx(
|
|
163
|
+
PanelPrimitive,
|
|
164
|
+
{
|
|
165
|
+
className: cn("m-4 overflow-hidden rounded-md border bg-card p-1", className),
|
|
166
|
+
...props
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
var Toolbar = ({ className, ...props }) => /* @__PURE__ */ jsx(
|
|
170
|
+
NodeToolbar,
|
|
171
|
+
{
|
|
172
|
+
className: cn("flex items-center gap-1 rounded-sm border bg-background p-1.5", className),
|
|
173
|
+
position: Position.Bottom,
|
|
174
|
+
...props
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
export {
|
|
178
|
+
Canvas,
|
|
179
|
+
Controls,
|
|
180
|
+
EdgeAnimated,
|
|
181
|
+
EdgeTemporary,
|
|
182
|
+
Node,
|
|
183
|
+
Panel,
|
|
184
|
+
Toolbar
|
|
185
|
+
};
|
|
186
|
+
//# sourceMappingURL=_flow-boundary-D63PJ65S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/_flow-boundary.tsx"],"sourcesContent":["\"use client\";\n\n/**\n * The React Flow half of `@elabs-ai/components-ai`'s in-chat agent\n * workspace graph — `Canvas`, `Controls`, `Edge`, `Node`, `Panel`, `Toolbar` —\n * split out so the engine can be `lazy()`-loaded.\n *\n * `@xyflow/react` declares no `sideEffects`, so the six static imports it used to\n * have (one per public module, plus `@xyflow/react/dist/style.css`) put the whole\n * engine into the entry chunk of every consumer, canvas rendered or not. **The\n * stylesheet import has to live here too**: a bare\n * `import \"@xyflow/react/dist/style.css\"` in `canvas.tsx` keeps the edge alive on\n * its own.\n *\n * This is ONE boundary for all six parts on purpose (see `_flow-lazy.ts`): six\n * boundaries would be six chunks all pulling the same engine. The public modules\n * keep their `import type { … } from \"@xyflow/react\"` lines (types erase) and\n * their prop types, and render a `lazy()` wrapper over the implementations here.\n * `connection.tsx` is type-only already and needs no boundary.\n *\n * See ADR 0019 and `pnpm heavy-deps:check`.\n *\n * @lazy-boundary This module must only ever be reached via `import()`. The gate\n * fails if anything imports it statically, which would put React Flow back in\n * the entry chunk and make the `lazy()` pointless.\n */\nimport { Card } from \"@elabs-ai/components-ui\";\nimport { cn } from \"@elabs-ai/components-ui/lib/cn\";\nimport type { EdgeProps, InternalNode, Node as FlowNode } from \"@xyflow/react\";\nimport {\n Background,\n BaseEdge,\n Controls as ControlsPrimitive,\n getBezierPath,\n getSimpleBezierPath,\n Handle,\n NodeToolbar,\n Panel as PanelPrimitive,\n Position,\n ReactFlow,\n useInternalNode,\n} from \"@xyflow/react\";\n\nimport \"@xyflow/react/dist/style.css\";\n\nimport type { CanvasProps } from \"./canvas\";\nimport type { ControlsProps } from \"./controls\";\nimport type { NodeProps } from \"./node\";\nimport type { PanelProps } from \"./panel\";\nimport type { ToolbarProps } from \"./toolbar\";\n\nconst deleteKeyCode = [\"Backspace\", \"Delete\"];\n\n/**\n * The React Flow attribution badge is hidden on both canvas surfaces (here and\n * `@elabs-ai/components-flow`'s `CanvasShell`). `@xyflow/react` is\n * MIT — the licence requires the notice in source copies, not a rendered badge —\n * and xyflow asks that the badge only be hidden under a React Flow Pro\n * subscription. Keeping it is therefore a product/commercial decision, and this\n * repo's is to hide it. A consumer can restore it per-canvas with\n * `proOptions={{ hideAttribution: false }}`, which still wins via `...props`.\n */\nconst proOptions = { hideAttribution: true };\n\nexport const Canvas = ({ children, ...props }: CanvasProps) => (\n <ReactFlow\n deleteKeyCode={deleteKeyCode}\n fitView\n panOnDrag={false}\n panOnScroll\n proOptions={proOptions}\n selectionOnDrag={true}\n zoomOnDoubleClick={false}\n {...props}\n >\n <Background bgColor=\"var(--sidebar)\" />\n {children}\n </ReactFlow>\n);\n\nexport const Controls = ({ className, ...props }: ControlsProps) => (\n <ControlsPrimitive\n className={cn(\n \"gap-px overflow-hidden rounded-md border bg-card p-1 shadow-none!\",\n \"[&>button]:rounded-md [&>button]:border-none! [&>button]:bg-transparent! [&>button]:hover:bg-secondary!\",\n className,\n )}\n {...props}\n />\n);\n\nexport const EdgeTemporary = ({\n id,\n sourceX,\n sourceY,\n targetX,\n targetY,\n sourcePosition,\n targetPosition,\n}: EdgeProps) => {\n const [edgePath] = getSimpleBezierPath({\n sourcePosition,\n sourceX,\n sourceY,\n targetPosition,\n targetX,\n targetY,\n });\n\n return (\n <BaseEdge\n className=\"stroke-1 stroke-ring\"\n id={id}\n path={edgePath}\n style={{\n strokeDasharray: \"5, 5\",\n }}\n />\n );\n};\n\nconst getHandleCoordsByPosition = (node: InternalNode<FlowNode>, handlePosition: Position) => {\n // Choose the handle type based on position - Left is for target, Right is for source\n const handleType = handlePosition === Position.Left ? \"target\" : \"source\";\n\n const handle = node.internals.handleBounds?.[handleType]?.find(\n (h) => h.position === handlePosition,\n );\n\n if (!handle) {\n return [0, 0] as const;\n }\n\n let offsetX = handle.width / 2;\n let offsetY = handle.height / 2;\n\n // this is a tiny detail to make the markerEnd of an edge visible.\n // The handle position that gets calculated has the origin top-left, so depending which side we are using, we add a little offset\n // when the handlePosition is Position.Right for example, we need to add an offset as big as the handle itself in order to get the correct position\n switch (handlePosition) {\n case Position.Left: {\n offsetX = 0;\n break;\n }\n case Position.Right: {\n offsetX = handle.width;\n break;\n }\n case Position.Top: {\n offsetY = 0;\n break;\n }\n case Position.Bottom: {\n offsetY = handle.height;\n break;\n }\n default: {\n throw new Error(`Invalid handle position: ${handlePosition}`);\n }\n }\n\n const x = node.internals.positionAbsolute.x + handle.x + offsetX;\n const y = node.internals.positionAbsolute.y + handle.y + offsetY;\n\n return [x, y] as const;\n};\n\nconst getEdgeParams = (source: InternalNode<FlowNode>, target: InternalNode<FlowNode>) => {\n const sourcePos = Position.Right;\n const [sx, sy] = getHandleCoordsByPosition(source, sourcePos);\n const targetPos = Position.Left;\n const [tx, ty] = getHandleCoordsByPosition(target, targetPos);\n\n return {\n sourcePos,\n sx,\n sy,\n targetPos,\n tx,\n ty,\n };\n};\n\nexport const EdgeAnimated = ({ id, source, target, markerEnd, style }: EdgeProps) => {\n const sourceNode = useInternalNode(source);\n const targetNode = useInternalNode(target);\n\n if (!(sourceNode && targetNode)) {\n return null;\n }\n\n const { sx, sy, tx, ty, sourcePos, targetPos } = getEdgeParams(sourceNode, targetNode);\n\n const [edgePath] = getBezierPath({\n sourcePosition: sourcePos,\n sourceX: sx,\n sourceY: sy,\n targetPosition: targetPos,\n targetX: tx,\n targetY: ty,\n });\n\n return (\n <>\n <BaseEdge id={id} markerEnd={markerEnd} path={edgePath} style={style} />\n <circle fill=\"var(--primary)\" r=\"4\">\n <animateMotion dur=\"2s\" path={edgePath} repeatCount=\"indefinite\" />\n </circle>\n </>\n );\n};\n\nexport const Node = ({ handles, className, ...props }: NodeProps) => (\n <Card\n className={cn(\"node-container relative size-full h-auto w-sm gap-0 rounded-md p-0\", className)}\n {...props}\n >\n {handles.target && <Handle position={Position.Left} type=\"target\" />}\n {handles.source && <Handle position={Position.Right} type=\"source\" />}\n {props.children}\n </Card>\n);\n\nexport const Panel = ({ className, ...props }: PanelProps) => (\n <PanelPrimitive\n className={cn(\"m-4 overflow-hidden rounded-md border bg-card p-1\", className)}\n {...props}\n />\n);\n\nexport const Toolbar = ({ className, ...props }: ToolbarProps) => (\n <NodeToolbar\n className={cn(\"flex items-center gap-1 rounded-sm border bg-background p-1.5\", className)}\n position={Position.Bottom}\n {...props}\n />\n);\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/_interactive-terminal-xterm.ts
|
|
4
|
+
import "@xterm/xterm/css/xterm.css";
|
|
5
|
+
import { FitAddon } from "@xterm/addon-fit";
|
|
6
|
+
import { Terminal } from "@xterm/xterm";
|
|
7
|
+
export {
|
|
8
|
+
FitAddon,
|
|
9
|
+
Terminal as XTerm
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=_interactive-terminal-xterm-ATJ5EW3G.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/_interactive-terminal-xterm.ts"],"sourcesContent":["/**\n * The xterm.js half of `InteractiveTerminal`, split out so it can be reached\n * through a dynamic `import()`.\n *\n * `@xterm/xterm` declares no `sideEffects`, so a static import from\n * `interactive-terminal.tsx` put the whole emulator — plus its stylesheet — into\n * the entry chunk of every `@elabs-ai/components-ai` consumer, including\n * the vast majority that never render a terminal. The **stylesheet import has to\n * live here too**: a bare `import \"@xterm/xterm/css/xterm.css\"` in the public\n * module keeps the edge alive on its own.\n *\n * Unlike `_persona-rive.tsx` (a `lazy()` component boundary), this one follows\n * `_lazy-mermaid.ts`: the engine is reached through a **late-called interface**.\n * `InteractiveTerminal` only ever constructs xterm inside its mount effect —\n * never during render — so the public component keeps its `forwardRef`, its\n * imperative handle and its container `<div>` unchanged, and awaits this module\n * inside that effect. No `Suspense` seam, no skeleton swap, no change to the box\n * the terminal paints into (the container is sized by the consumer either way).\n *\n * `ITheme` and the two constructor types stay `import type` in the public module\n * (types erase), which is what keeps `buildInteractiveTerminalTheme` public.\n *\n * See ADR 0019 and `pnpm heavy-deps:check`.\n *\n * @lazy-boundary This module must only ever be reached via `import()`. The gate\n * fails if anything imports it statically, which would put xterm back in the\n * entry chunk and make the dynamic import pointless.\n */\nimport \"@xterm/xterm/css/xterm.css\";\n\nexport { FitAddon } from \"@xterm/addon-fit\";\nexport { Terminal as XTerm } from \"@xterm/xterm\";\n"],"mappings":";;;AA4BA,OAAO;AAEP,SAAS,gBAAgB;AACzB,SAAqB,gBAAa;","names":[]}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use client";
|
|
3
|
+
|
|
4
|
+
// src/_persona-rive.tsx
|
|
5
|
+
import { cn } from "@elabs-ai/components-ui/lib/cn";
|
|
6
|
+
import { useReducedMotion } from "@elabs-ai/components-tokens";
|
|
7
|
+
import {
|
|
8
|
+
useRive,
|
|
9
|
+
useStateMachineInput,
|
|
10
|
+
useViewModel,
|
|
11
|
+
useViewModelInstance,
|
|
12
|
+
useViewModelInstanceColor
|
|
13
|
+
} from "@rive-app/react-webgl2";
|
|
14
|
+
import { memo, useEffect, useMemo, useRef, useState } from "react";
|
|
15
|
+
import { jsx } from "react/jsx-runtime";
|
|
16
|
+
var useStrictModeSafeInit = () => {
|
|
17
|
+
const [ready, setReady] = useState(false);
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
const id = requestAnimationFrame(() => setReady(true));
|
|
20
|
+
return () => {
|
|
21
|
+
cancelAnimationFrame(id);
|
|
22
|
+
setReady(false);
|
|
23
|
+
};
|
|
24
|
+
}, []);
|
|
25
|
+
return ready;
|
|
26
|
+
};
|
|
27
|
+
var stateMachine = "default";
|
|
28
|
+
var getCurrentTheme = () => {
|
|
29
|
+
if (typeof window !== "undefined") {
|
|
30
|
+
if (document.documentElement.classList.contains("dark")) {
|
|
31
|
+
return "dark";
|
|
32
|
+
}
|
|
33
|
+
if (window.matchMedia?.("(prefers-color-scheme: dark)").matches) {
|
|
34
|
+
return "dark";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return "light";
|
|
38
|
+
};
|
|
39
|
+
var useTheme = (enabled) => {
|
|
40
|
+
const [theme, setTheme] = useState(getCurrentTheme);
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
if (!enabled) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const observer = new MutationObserver(() => {
|
|
46
|
+
setTheme(getCurrentTheme());
|
|
47
|
+
});
|
|
48
|
+
observer.observe(document.documentElement, {
|
|
49
|
+
attributeFilter: ["class"],
|
|
50
|
+
attributes: true
|
|
51
|
+
});
|
|
52
|
+
let mql = null;
|
|
53
|
+
const handleMediaChange = () => {
|
|
54
|
+
setTheme(getCurrentTheme());
|
|
55
|
+
};
|
|
56
|
+
if (window.matchMedia) {
|
|
57
|
+
mql = window.matchMedia("(prefers-color-scheme: dark)");
|
|
58
|
+
mql.addEventListener("change", handleMediaChange);
|
|
59
|
+
}
|
|
60
|
+
return () => {
|
|
61
|
+
observer.disconnect();
|
|
62
|
+
if (mql) {
|
|
63
|
+
mql.removeEventListener("change", handleMediaChange);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}, [enabled]);
|
|
67
|
+
return theme;
|
|
68
|
+
};
|
|
69
|
+
var PersonaWithModel = memo(({ rive, source, children }) => {
|
|
70
|
+
const theme = useTheme(source.dynamicColor);
|
|
71
|
+
const viewModel = useViewModel(rive, { useDefault: true });
|
|
72
|
+
const viewModelInstance = useViewModelInstance(viewModel, {
|
|
73
|
+
rive,
|
|
74
|
+
useDefault: true
|
|
75
|
+
});
|
|
76
|
+
const viewModelInstanceColor = useViewModelInstanceColor("color", viewModelInstance);
|
|
77
|
+
useEffect(() => {
|
|
78
|
+
if (!(viewModelInstanceColor && source.dynamicColor)) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const [r, g, b] = theme === "dark" ? [255, 255, 255] : [0, 0, 0];
|
|
82
|
+
viewModelInstanceColor.setRgb(r, g, b);
|
|
83
|
+
}, [viewModelInstanceColor, theme, source.dynamicColor]);
|
|
84
|
+
return children;
|
|
85
|
+
});
|
|
86
|
+
PersonaWithModel.displayName = "PersonaWithModel";
|
|
87
|
+
var PersonaWithoutModel = memo(({ children }) => children);
|
|
88
|
+
PersonaWithoutModel.displayName = "PersonaWithoutModel";
|
|
89
|
+
var PersonaRive = ({
|
|
90
|
+
className,
|
|
91
|
+
onLoad,
|
|
92
|
+
onLoadError,
|
|
93
|
+
onPause,
|
|
94
|
+
onPlay,
|
|
95
|
+
onReady,
|
|
96
|
+
onStop,
|
|
97
|
+
source,
|
|
98
|
+
src,
|
|
99
|
+
state
|
|
100
|
+
}) => {
|
|
101
|
+
const callbacksRef = useRef({ onLoad, onLoadError, onPause, onPlay, onReady, onStop });
|
|
102
|
+
useEffect(() => {
|
|
103
|
+
callbacksRef.current = { onLoad, onLoadError, onPause, onPlay, onReady, onStop };
|
|
104
|
+
}, [onLoad, onLoadError, onPause, onPlay, onReady, onStop]);
|
|
105
|
+
const stableCallbacks = useMemo(
|
|
106
|
+
() => ({
|
|
107
|
+
onLoad: ((loadedRive) => callbacksRef.current.onLoad?.(loadedRive)),
|
|
108
|
+
onLoadError: ((err) => callbacksRef.current.onLoadError?.(err)),
|
|
109
|
+
onPause: ((event) => callbacksRef.current.onPause?.(event)),
|
|
110
|
+
onPlay: ((event) => callbacksRef.current.onPlay?.(event)),
|
|
111
|
+
onReady: () => callbacksRef.current.onReady?.(),
|
|
112
|
+
onStop: ((event) => callbacksRef.current.onStop?.(event))
|
|
113
|
+
}),
|
|
114
|
+
[]
|
|
115
|
+
);
|
|
116
|
+
const ready = useStrictModeSafeInit();
|
|
117
|
+
const prefersReducedMotion = useReducedMotion();
|
|
118
|
+
const { rive, RiveComponent } = useRive(
|
|
119
|
+
ready ? {
|
|
120
|
+
autoplay: !prefersReducedMotion,
|
|
121
|
+
onLoad: stableCallbacks.onLoad,
|
|
122
|
+
onLoadError: stableCallbacks.onLoadError,
|
|
123
|
+
onPause: stableCallbacks.onPause,
|
|
124
|
+
onPlay: stableCallbacks.onPlay,
|
|
125
|
+
onRiveReady: stableCallbacks.onReady,
|
|
126
|
+
onStop: stableCallbacks.onStop,
|
|
127
|
+
src,
|
|
128
|
+
stateMachines: stateMachine
|
|
129
|
+
} : null
|
|
130
|
+
);
|
|
131
|
+
useEffect(() => {
|
|
132
|
+
if (!rive) return;
|
|
133
|
+
if (prefersReducedMotion) {
|
|
134
|
+
rive.pause();
|
|
135
|
+
} else {
|
|
136
|
+
rive.play();
|
|
137
|
+
}
|
|
138
|
+
}, [rive, prefersReducedMotion]);
|
|
139
|
+
const listeningInput = useStateMachineInput(rive, stateMachine, "listening");
|
|
140
|
+
const thinkingInput = useStateMachineInput(rive, stateMachine, "thinking");
|
|
141
|
+
const speakingInput = useStateMachineInput(rive, stateMachine, "speaking");
|
|
142
|
+
const asleepInput = useStateMachineInput(rive, stateMachine, "asleep");
|
|
143
|
+
useEffect(() => {
|
|
144
|
+
if (listeningInput) {
|
|
145
|
+
listeningInput.value = state === "listening";
|
|
146
|
+
}
|
|
147
|
+
if (thinkingInput) {
|
|
148
|
+
thinkingInput.value = state === "thinking";
|
|
149
|
+
}
|
|
150
|
+
if (speakingInput) {
|
|
151
|
+
speakingInput.value = state === "speaking";
|
|
152
|
+
}
|
|
153
|
+
if (asleepInput) {
|
|
154
|
+
asleepInput.value = state === "asleep";
|
|
155
|
+
}
|
|
156
|
+
}, [state, listeningInput, thinkingInput, speakingInput, asleepInput]);
|
|
157
|
+
const Wrapper = source.hasModel ? PersonaWithModel : PersonaWithoutModel;
|
|
158
|
+
return /* @__PURE__ */ jsx(Wrapper, { rive, source, children: /* @__PURE__ */ jsx(RiveComponent, { className: cn("size-16 shrink-0", className) }) });
|
|
159
|
+
};
|
|
160
|
+
var persona_rive_default = PersonaRive;
|
|
161
|
+
export {
|
|
162
|
+
persona_rive_default as default
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=_persona-rive-RFR2EUWP.js.map
|