@copilotkit/channels-ui 0.1.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 +197 -0
- package/dist/bind.d.ts +6 -0
- package/dist/bind.d.ts.map +1 -0
- package/dist/bind.js +18 -0
- package/dist/bind.test.d.ts +2 -0
- package/dist/bind.test.d.ts.map +1 -0
- package/dist/bind.test.js +14 -0
- package/dist/components.d.ts +154 -0
- package/dist/components.d.ts.map +1 -0
- package/dist/components.js +32 -0
- package/dist/components.test.d.ts +2 -0
- package/dist/components.test.d.ts.map +1 -0
- package/dist/components.test.js +89 -0
- package/dist/emoji.d.ts +104 -0
- package/dist/emoji.d.ts.map +1 -0
- package/dist/emoji.js +77 -0
- package/dist/emoji.test.d.ts +2 -0
- package/dist/emoji.test.d.ts.map +1 -0
- package/dist/emoji.test.js +63 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/ir.d.ts +11 -0
- package/dist/ir.d.ts.map +1 -0
- package/dist/ir.js +1 -0
- package/dist/jsx-dev-runtime.d.ts +7 -0
- package/dist/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/jsx-dev-runtime.js +4 -0
- package/dist/jsx-runtime.d.ts +30 -0
- package/dist/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx-runtime.js +6 -0
- package/dist/jsx-runtime.test.d.ts +2 -0
- package/dist/jsx-runtime.test.d.ts.map +1 -0
- package/dist/jsx-runtime.test.js +17 -0
- package/dist/modal.d.ts +60 -0
- package/dist/modal.d.ts.map +1 -0
- package/dist/modal.js +13 -0
- package/dist/modal.test.d.ts +2 -0
- package/dist/modal.test.d.ts.map +1 -0
- package/dist/modal.test.js +29 -0
- package/dist/render.d.ts +3 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +37 -0
- package/dist/render.test.d.ts +2 -0
- package/dist/render.test.d.ts.map +1 -0
- package/dist/render.test.js +39 -0
- package/dist/types.d.ts +212 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Atai Barkai
|
|
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
|
|
13
|
+
all 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
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
# @copilotkit/channels-ui
|
|
2
|
+
|
|
3
|
+
A pure **JSX runtime + intermediate representation (IR) + cross-platform
|
|
4
|
+
component vocabulary** for authoring rich bot messages. No React, no agent
|
|
5
|
+
runtime, no Slack β `@copilotkit/channels-ui` depends on nothing in the repo
|
|
6
|
+
except `@copilotkit/shared` (for `StandardSchemaV1` types). That's what lets
|
|
7
|
+
a platform adapter (e.g. `@copilotkit/channels-slack`) translate the same UI into
|
|
8
|
+
Block Kit, while keeping the component layer tree-shakeable and testable in
|
|
9
|
+
isolation.
|
|
10
|
+
|
|
11
|
+
You author UI as JSX, it normalizes to one serializable IR (`BotNode[]`), and
|
|
12
|
+
behavior props (`onClick` / `onSelect` / `onSubmit`) ride along on the nodes
|
|
13
|
+
for the engine (`@copilotkit/channels`) to bind.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
pnpm add @copilotkit/channels-ui
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
To author components as JSX, point the TypeScript JSX factory at this package
|
|
22
|
+
in the consuming project's `tsconfig.json`:
|
|
23
|
+
|
|
24
|
+
```jsonc
|
|
25
|
+
{
|
|
26
|
+
"compilerOptions": {
|
|
27
|
+
"jsx": "react-jsx",
|
|
28
|
+
"jsxImportSource": "@copilotkit/channels-ui",
|
|
29
|
+
},
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
This package ships `@copilotkit/channels-ui/jsx-runtime` (and
|
|
34
|
+
`/jsx-dev-runtime`) exporting `jsx` / `jsxs` / `Fragment`. Author component
|
|
35
|
+
files as `.tsx`.
|
|
36
|
+
|
|
37
|
+
## Example
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import {
|
|
41
|
+
Message,
|
|
42
|
+
Header,
|
|
43
|
+
Section,
|
|
44
|
+
Actions,
|
|
45
|
+
Button,
|
|
46
|
+
renderToIR,
|
|
47
|
+
} from "@copilotkit/channels-ui";
|
|
48
|
+
|
|
49
|
+
function Greeting({ name }: { name: string }) {
|
|
50
|
+
return (
|
|
51
|
+
<Message>
|
|
52
|
+
<Header>Hello {name}</Header>
|
|
53
|
+
<Section>Pick an option β **bold** and `code` work too.</Section>
|
|
54
|
+
<Actions>
|
|
55
|
+
<Button
|
|
56
|
+
style="primary"
|
|
57
|
+
onClick={(ctx) => ctx.thread.post("you clicked!")}
|
|
58
|
+
>
|
|
59
|
+
Continue
|
|
60
|
+
</Button>
|
|
61
|
+
</Actions>
|
|
62
|
+
</Message>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const ir = renderToIR(<Greeting name="Ada" />);
|
|
67
|
+
// ir is BotNode[] β hand it to an adapter, or let @copilotkit/channels post it.
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`renderToIR(ui: Renderable): BotNode[]` recursively invokes any component
|
|
71
|
+
function (passing its props) until only intrinsic string-typed nodes remain;
|
|
72
|
+
strings in children become `{ type: "text", props: { value } }`; `Fragment`
|
|
73
|
+
flattens its children. Components must be **pure functions of serializable
|
|
74
|
+
props** β same props in, same tree out β which is what makes content-stable
|
|
75
|
+
action binding and re-render rehydration possible in `@copilotkit/channels`.
|
|
76
|
+
|
|
77
|
+
`Renderable` also accepts a `{ raw }` escape hatch, which `renderToIR` passes
|
|
78
|
+
through as `{ type: "raw", props: { value } }` for adapters that want to
|
|
79
|
+
short-circuit to a native payload.
|
|
80
|
+
|
|
81
|
+
## Component vocabulary
|
|
82
|
+
|
|
83
|
+
Each component is a thin function returning a `BotNode` with a stable
|
|
84
|
+
intrinsic `type` string. An adapter maps these to native primitives.
|
|
85
|
+
|
|
86
|
+
Every component has a fully-typed prop interface (`MessageProps`,
|
|
87
|
+
`ButtonProps`, β¦, all exported), and the package ships its own `JSX` namespace
|
|
88
|
+
(resolved via `jsxImportSource: "@copilotkit/channels-ui"`). So JSX is statically
|
|
89
|
+
checked: unknown attributes, wrong prop values, and bad children are
|
|
90
|
+
compile-time errors β `<Section bogus={1} />` or `<Button style="nope">` won't
|
|
91
|
+
type-check. There are no lowercase intrinsic tags; the vocabulary is the
|
|
92
|
+
capitalized component set below.
|
|
93
|
+
|
|
94
|
+
| Component | Purpose |
|
|
95
|
+
| ---------- | -------------------------------------------------------------------------- |
|
|
96
|
+
| `Message` | Root container for a single posted message β `accent`, `onReaction`. |
|
|
97
|
+
| `Header` | Bold header / title row. |
|
|
98
|
+
| `Section` | A block of (markdown) body text. |
|
|
99
|
+
| `Markdown` | Explicit markdown text block. |
|
|
100
|
+
| `Field` | One label/value cell inside `Fields` β optional `label`. |
|
|
101
|
+
| `Fields` | A grid of `Field`s (two-column key/value layout). |
|
|
102
|
+
| `Context` | Small, muted secondary text (footnotes, metadata). |
|
|
103
|
+
| `Actions` | Row container for interactive controls. |
|
|
104
|
+
| `Button` | Clickable button β `onClick`, `value`, `style`, or `url` (link button). |
|
|
105
|
+
| `Select` | Dropdown β `onSelect`, `placeholder`, `options: {label,value}[]`, `multi`. |
|
|
106
|
+
| `Input` | Text input β `onSubmit`, `placeholder`, `multiline`, `name`. |
|
|
107
|
+
| `Image` | An image block. |
|
|
108
|
+
| `Divider` | A horizontal rule. |
|
|
109
|
+
|
|
110
|
+
### Behavior props
|
|
111
|
+
|
|
112
|
+
Interactive components carry handler props typed as `ClickHandler`:
|
|
113
|
+
|
|
114
|
+
- `Button` β `onClick`
|
|
115
|
+
- `Select` β `onSelect`
|
|
116
|
+
- `Input` β `onSubmit`
|
|
117
|
+
|
|
118
|
+
`Message` also takes `onReaction`, fired when a user reacts to the posted
|
|
119
|
+
message (adds or removes). The first arg is the emoji; the second carries
|
|
120
|
+
`added`/`user`/`rawEmoji` plus a `thread` and the reacted message's
|
|
121
|
+
`messageRef` β the same surface an `onClick` gets, so a reaction can post new
|
|
122
|
+
UI, swap the message in place, or run a HITL flow:
|
|
123
|
+
|
|
124
|
+
```tsx
|
|
125
|
+
<Message
|
|
126
|
+
onReaction={async (emoji, r) => {
|
|
127
|
+
if (!r.added) return;
|
|
128
|
+
if (emoji === "bug") await r.thread.post(<FileBug />); // post new UI
|
|
129
|
+
if (emoji === "white_check_mark")
|
|
130
|
+
await r.thread.update(r.messageRef, <Resolved />); // swap UI in place
|
|
131
|
+
}}
|
|
132
|
+
>
|
|
133
|
+
β¦
|
|
134
|
+
</Message>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
It's durable on the same terms as a component `onClick`: when the `<Message>`
|
|
138
|
+
comes from a component registered via `createBot({ components: [...] })` and a
|
|
139
|
+
durable `store` is configured, a reaction after a restart re-renders the
|
|
140
|
+
component to re-derive the handler. Inline handlers (and `<Message>` used
|
|
141
|
+
directly) route in-process but don't survive a restart. For durable, filtered
|
|
142
|
+
reaction routing across _all_ messages, use `bot.onReaction(...)`.
|
|
143
|
+
|
|
144
|
+
A `ClickHandler` receives an `InteractionContext`, both generic over the
|
|
145
|
+
clicked control's value type:
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
type ClickHandler<TValue = unknown> = (
|
|
149
|
+
ctx: InteractionContext<TValue>,
|
|
150
|
+
) => void | Promise<void>;
|
|
151
|
+
|
|
152
|
+
interface InteractionContext<TValue = unknown> {
|
|
153
|
+
thread: Thread;
|
|
154
|
+
message: IncomingMessage;
|
|
155
|
+
action: { id: string; value?: TValue };
|
|
156
|
+
values: Record<string, unknown>;
|
|
157
|
+
user: PlatformUser;
|
|
158
|
+
platform: string;
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`Button` is generic over its `value` prop, so `ctx.action.value` is **inferred**
|
|
163
|
+
from `value` β `<Button value={{ confirmed: true }} onClick={(ctx) => ctx.action.value?.confirmed}>`
|
|
164
|
+
type-checks with no cast. `Select`/`Input` resolve the value to `string`.
|
|
165
|
+
|
|
166
|
+
The structural types `Thread`, `IncomingMessage`, `PlatformUser`,
|
|
167
|
+
`MessageRef`, and `ClickHandler` are declared here for handler typing only β
|
|
168
|
+
they're implemented at runtime by `@copilotkit/channels` and its adapters.
|
|
169
|
+
`@copilotkit/channels-ui` has no runtime dependency on them.
|
|
170
|
+
|
|
171
|
+
## `bind()` β the Tier-2 escape hatch
|
|
172
|
+
|
|
173
|
+
Inline `onClick` handlers are bound by content (component identity + path +
|
|
174
|
+
serializable props), so a handler can be re-derived after a restart by
|
|
175
|
+
re-rendering the component. When a handler closes over data that **can't** be
|
|
176
|
+
reconstructed from props, wrap it with `bind()` so the engine persists that
|
|
177
|
+
small payload explicitly alongside the minted action id:
|
|
178
|
+
|
|
179
|
+
```tsx
|
|
180
|
+
import { bind } from "@copilotkit/channels-ui";
|
|
181
|
+
|
|
182
|
+
<Button onClick={bind(handleChoice, { choiceId: "abc123" })}>Choose</Button>;
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
`bind(handler, args)` returns a tagged handler; the action registry stores
|
|
186
|
+
`args` so a cold-path dispatch passes them back via `ctx.action.value`. Keep
|
|
187
|
+
`args` small β it's the only handler-specific state that survives a restart.
|
|
188
|
+
|
|
189
|
+
## Exports
|
|
190
|
+
|
|
191
|
+
Runtime: `renderToIR`, `Fragment`, `bind`, and the vocabulary
|
|
192
|
+
(`Message`, `Header`, `Section`, `Markdown`, `Field`, `Fields`, `Context`,
|
|
193
|
+
`Actions`, `Button`, `Select`, `Input`, `Image`, `Divider`).
|
|
194
|
+
Types: `BotNode`, `BotChildren`, `ComponentFn`, `Renderable`, `Thread`,
|
|
195
|
+
`InteractionContext`, `PlatformUser`, `IncomingMessage`, `MessageRef`,
|
|
196
|
+
`ClickHandler`, and the per-component prop types (`MessageProps`,
|
|
197
|
+
`ButtonProps`, `SelectProps`, `TableProps`, `TableColumn`, β¦).
|
package/dist/bind.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ClickHandler } from "./types.js";
|
|
2
|
+
export declare function bind(handler: ClickHandler, args: unknown): ClickHandler;
|
|
3
|
+
export declare function isBound(h: unknown): boolean;
|
|
4
|
+
export declare function getBoundArgs(h: unknown): unknown;
|
|
5
|
+
export declare function getBoundHandler(h: unknown): ClickHandler | undefined;
|
|
6
|
+
//# sourceMappingURL=bind.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.d.ts","sourceRoot":"","sources":["../src/bind.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAsB,MAAM,YAAY,CAAC;AAMnE,wBAAgB,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,IAAI,EAAE,OAAO,GAAG,YAAY,CAQvE;AACD,wBAAgB,OAAO,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAE3C;AACD,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAEhD;AACD,wBAAgB,eAAe,CAAC,CAAC,EAAE,OAAO,GAAG,YAAY,GAAG,SAAS,CAEpE"}
|
package/dist/bind.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const BOUND = Symbol.for("copilotkit.bot-ui.bound");
|
|
2
|
+
export function bind(handler, args) {
|
|
3
|
+
const wrapped = ((ctx) => handler({
|
|
4
|
+
...ctx,
|
|
5
|
+
action: { ...ctx.action, value: args },
|
|
6
|
+
}));
|
|
7
|
+
wrapped[BOUND] = { handler, args };
|
|
8
|
+
return wrapped;
|
|
9
|
+
}
|
|
10
|
+
export function isBound(h) {
|
|
11
|
+
return typeof h === "function" && !!h[BOUND];
|
|
12
|
+
}
|
|
13
|
+
export function getBoundArgs(h) {
|
|
14
|
+
return h[BOUND]?.args;
|
|
15
|
+
}
|
|
16
|
+
export function getBoundHandler(h) {
|
|
17
|
+
return h[BOUND]?.handler;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bind.test.d.ts","sourceRoot":"","sources":["../src/bind.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { bind, isBound, getBoundArgs, getBoundHandler } from "./bind.js";
|
|
3
|
+
describe("bind", () => {
|
|
4
|
+
it("tags a handler with serializable args", () => {
|
|
5
|
+
const h = () => { };
|
|
6
|
+
const b = bind(h, { flightId: "x1" });
|
|
7
|
+
expect(isBound(b)).toBe(true);
|
|
8
|
+
expect(getBoundArgs(b)).toEqual({ flightId: "x1" });
|
|
9
|
+
expect(getBoundHandler(b)).toBe(h);
|
|
10
|
+
});
|
|
11
|
+
it("plain handler is not bound", () => {
|
|
12
|
+
expect(isBound(() => { })).toBe(false);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import type { BotNode } from "./ir.js";
|
|
2
|
+
import type { ClickHandler, MessageReactionHandler } from "./types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Anything that can appear as a child in the component tree: nested elements,
|
|
5
|
+
* text, numbers, and conditionals (`false` / `null` / `undefined` render
|
|
6
|
+
* nothing), plus arrays thereof.
|
|
7
|
+
*/
|
|
8
|
+
export type BotChildren = BotNode | string | number | boolean | null | undefined | BotChildren[];
|
|
9
|
+
/** Mixin for the container components that wrap children. */
|
|
10
|
+
interface WithChildren {
|
|
11
|
+
children?: BotChildren;
|
|
12
|
+
}
|
|
13
|
+
export interface MessageProps extends WithChildren {
|
|
14
|
+
/** Accent color (hex, e.g. `#27AE60`) for the message's colored rail. */
|
|
15
|
+
accent?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Called when a user reacts to this message (add or remove). The first arg is
|
|
18
|
+
* the emoji, e.g. `onReaction={(r) => r === "bug" ? triage() : ack()}`; the
|
|
19
|
+
* second carries `added`/`user`/`rawEmoji` plus a `thread` and the reacted
|
|
20
|
+
* message's `messageRef` β the same surface an `onClick` gets, so the handler
|
|
21
|
+
* can `thread.post(...)`, `thread.update(messageRef, ...)`, or run a HITL flow.
|
|
22
|
+
* Durable on the same terms as a component `onClick`: survives a restart when
|
|
23
|
+
* the `<Message>` comes from a registered component and a durable store is
|
|
24
|
+
* configured; inline handlers route in-process only.
|
|
25
|
+
*/
|
|
26
|
+
onReaction?: MessageReactionHandler;
|
|
27
|
+
}
|
|
28
|
+
export interface HeaderProps extends WithChildren {
|
|
29
|
+
}
|
|
30
|
+
export interface SectionProps extends WithChildren {
|
|
31
|
+
}
|
|
32
|
+
export interface MarkdownProps extends WithChildren {
|
|
33
|
+
}
|
|
34
|
+
export interface FieldsProps extends WithChildren {
|
|
35
|
+
}
|
|
36
|
+
export interface FieldProps extends WithChildren {
|
|
37
|
+
/**
|
|
38
|
+
* Bold label rendered before the value (e.g. `<Field label="Status">Online</Field>`).
|
|
39
|
+
* Rendered on Discord, Slack, and Telegram; surfaces without a field label
|
|
40
|
+
* concept fall back to the value text alone.
|
|
41
|
+
*/
|
|
42
|
+
label?: string;
|
|
43
|
+
}
|
|
44
|
+
export interface ContextProps extends WithChildren {
|
|
45
|
+
}
|
|
46
|
+
export interface ActionsProps extends WithChildren {
|
|
47
|
+
}
|
|
48
|
+
export interface ImageProps {
|
|
49
|
+
/** Image URL. */
|
|
50
|
+
url: string;
|
|
51
|
+
/** Alternative text for accessibility. */
|
|
52
|
+
alt?: string;
|
|
53
|
+
}
|
|
54
|
+
/** `<Divider />` takes no props or children. */
|
|
55
|
+
export type DividerProps = {
|
|
56
|
+
children?: never;
|
|
57
|
+
};
|
|
58
|
+
export interface ButtonProps<TValue = unknown> extends WithChildren {
|
|
59
|
+
/**
|
|
60
|
+
* Inline handler run when the button is clicked (bound by the action
|
|
61
|
+
* registry). Its `ctx.action.value` is typed as `TValue`, inferred from
|
|
62
|
+
* `value`. Ignored when `url` is set (a link button doesn't dispatch).
|
|
63
|
+
*/
|
|
64
|
+
onClick?: ClickHandler<TValue>;
|
|
65
|
+
/** Value echoed back to `onClick`/`awaitChoice` on click; drives `TValue`. */
|
|
66
|
+
value?: TValue;
|
|
67
|
+
/**
|
|
68
|
+
* Makes this a link button that opens `url` instead of dispatching a handler.
|
|
69
|
+
* Rendered natively on Slack, Discord, Teams, and Telegram; surfaces without
|
|
70
|
+
* link buttons skip it. When set, `onClick`/`value` are ignored.
|
|
71
|
+
*/
|
|
72
|
+
url?: string;
|
|
73
|
+
/** Slack button accent. */
|
|
74
|
+
style?: "primary" | "danger";
|
|
75
|
+
}
|
|
76
|
+
export interface SelectOption {
|
|
77
|
+
label: string;
|
|
78
|
+
value: string;
|
|
79
|
+
}
|
|
80
|
+
export interface SelectProps {
|
|
81
|
+
/**
|
|
82
|
+
* Handler run on selection. `ctx.action.value` is the chosen option's `value`
|
|
83
|
+
* (a `string`), or a `string[]` of chosen values when `multi` is set.
|
|
84
|
+
*/
|
|
85
|
+
onSelect?: ClickHandler<string | string[]>;
|
|
86
|
+
placeholder?: string;
|
|
87
|
+
options: SelectOption[];
|
|
88
|
+
/**
|
|
89
|
+
* Allow selecting multiple options. Rendered natively on Slack
|
|
90
|
+
* (`multi_static_select`), Discord (max-values), and Teams
|
|
91
|
+
* (`isMultiSelect`); surfaces that can only express a single choice
|
|
92
|
+
* (Telegram, WhatsApp) degrade to single-select. When set, `onSelect`
|
|
93
|
+
* receives a `string[]`.
|
|
94
|
+
*/
|
|
95
|
+
multi?: boolean;
|
|
96
|
+
}
|
|
97
|
+
export interface InputProps {
|
|
98
|
+
/** Handler run on submit; `ctx.action.value` is the entered text. */
|
|
99
|
+
onSubmit?: ClickHandler<string>;
|
|
100
|
+
placeholder?: string;
|
|
101
|
+
multiline?: boolean;
|
|
102
|
+
name?: string;
|
|
103
|
+
}
|
|
104
|
+
export interface TableColumn {
|
|
105
|
+
header: string;
|
|
106
|
+
align?: "left" | "center" | "right";
|
|
107
|
+
}
|
|
108
|
+
export interface TableProps extends WithChildren {
|
|
109
|
+
columns?: TableColumn[];
|
|
110
|
+
}
|
|
111
|
+
export interface RowProps extends WithChildren {
|
|
112
|
+
}
|
|
113
|
+
export interface CellProps extends WithChildren {
|
|
114
|
+
}
|
|
115
|
+
/** The chart kinds a surface can render. Platforms that don't support a native
|
|
116
|
+
* chart simply skip the node (the renderer is total). */
|
|
117
|
+
export type ChartType = "verticalBar" | "horizontalBar" | "line" | "pie" | "donut";
|
|
118
|
+
/** One `(label, value)` datum. `label` is the category/x value, `value` the
|
|
119
|
+
* numeric y value (or the slice size for pie/donut). */
|
|
120
|
+
export interface ChartDataPoint {
|
|
121
|
+
label: string;
|
|
122
|
+
value: number;
|
|
123
|
+
}
|
|
124
|
+
export interface ChartProps {
|
|
125
|
+
/** Chart kind; defaults to `verticalBar`. */
|
|
126
|
+
type?: ChartType;
|
|
127
|
+
/** Title shown above the chart. */
|
|
128
|
+
title?: string;
|
|
129
|
+
/** Axis titles (cartesian charts only β bar/line; ignored for pie/donut). */
|
|
130
|
+
xAxisTitle?: string;
|
|
131
|
+
yAxisTitle?: string;
|
|
132
|
+
/** The data to plot β one entry per category. */
|
|
133
|
+
data: ChartDataPoint[];
|
|
134
|
+
}
|
|
135
|
+
export declare const intrinsic: <P>(type: string) => (props: P) => BotNode;
|
|
136
|
+
export declare const Message: (props: MessageProps) => BotNode;
|
|
137
|
+
export declare const Header: (props: HeaderProps) => BotNode;
|
|
138
|
+
export declare const Section: (props: SectionProps) => BotNode;
|
|
139
|
+
export declare const Markdown: (props: MarkdownProps) => BotNode;
|
|
140
|
+
export declare const Field: (props: FieldProps) => BotNode;
|
|
141
|
+
export declare const Fields: (props: FieldsProps) => BotNode;
|
|
142
|
+
export declare const Context: (props: ContextProps) => BotNode;
|
|
143
|
+
export declare const Actions: (props: ActionsProps) => BotNode;
|
|
144
|
+
export declare const Image: (props: ImageProps) => BotNode;
|
|
145
|
+
export declare const Divider: (props: DividerProps) => BotNode;
|
|
146
|
+
export declare const Chart: (props: ChartProps) => BotNode;
|
|
147
|
+
export declare const Row: (props: RowProps) => BotNode;
|
|
148
|
+
export declare const Cell: (props: CellProps) => BotNode;
|
|
149
|
+
export declare function Button<TValue = unknown>(props: ButtonProps<TValue>): BotNode;
|
|
150
|
+
export declare function Select(props: SelectProps): BotNode;
|
|
151
|
+
export declare function Input(props: InputProps): BotNode;
|
|
152
|
+
export declare function Table(props: TableProps): BotNode;
|
|
153
|
+
export {};
|
|
154
|
+
//# sourceMappingURL=components.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.d.ts","sourceRoot":"","sources":["../src/components.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// ---- Components ----------------------------------------------------------
|
|
2
|
+
// `intrinsic` produces a typed component that lowers `<X .../>` to an IR node
|
|
3
|
+
// of the given `type`; the generic `P` is what gives each tag its prop type.
|
|
4
|
+
export const intrinsic = (type) => (props) => ({
|
|
5
|
+
type,
|
|
6
|
+
props: (props ?? {}),
|
|
7
|
+
});
|
|
8
|
+
export const Message = intrinsic("message");
|
|
9
|
+
export const Header = intrinsic("header");
|
|
10
|
+
export const Section = intrinsic("section");
|
|
11
|
+
export const Markdown = intrinsic("markdown");
|
|
12
|
+
export const Field = intrinsic("field");
|
|
13
|
+
export const Fields = intrinsic("fields");
|
|
14
|
+
export const Context = intrinsic("context");
|
|
15
|
+
export const Actions = intrinsic("actions");
|
|
16
|
+
export const Image = intrinsic("image");
|
|
17
|
+
export const Divider = intrinsic("divider");
|
|
18
|
+
export const Chart = intrinsic("chart");
|
|
19
|
+
export const Row = intrinsic("row");
|
|
20
|
+
export const Cell = intrinsic("cell");
|
|
21
|
+
export function Button(props) {
|
|
22
|
+
return { type: "button", props: props };
|
|
23
|
+
}
|
|
24
|
+
export function Select(props) {
|
|
25
|
+
return { type: "select", props: props };
|
|
26
|
+
}
|
|
27
|
+
export function Input(props) {
|
|
28
|
+
return { type: "input", props: props };
|
|
29
|
+
}
|
|
30
|
+
export function Table(props) {
|
|
31
|
+
return { type: "table", props: props };
|
|
32
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"components.test.d.ts","sourceRoot":"","sources":["../src/components.test.tsx"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@copilotkit/channels-ui/jsx-runtime";
|
|
2
|
+
import { describe, it, expect } from "vitest";
|
|
3
|
+
import { renderToIR } from "./render.js";
|
|
4
|
+
import { Message, Header, Section, Actions, Button, Divider, Table, Row, Cell, Image, Select, Chart, } from "./components.js";
|
|
5
|
+
/**
|
|
6
|
+
* Compile-time prop type guards. This arrow is never invoked β the assertions
|
|
7
|
+
* are validated by `tsc` (build / check-types). Each `@ts-expect-error` fails
|
|
8
|
+
* the type-check if the props ever stop being enforced (regression guard); the
|
|
9
|
+
* trailing valid cases fail if a legitimate usage is wrongly rejected.
|
|
10
|
+
*/
|
|
11
|
+
const __typeGuards = () => {
|
|
12
|
+
// @ts-expect-error unknown prop on a container component
|
|
13
|
+
_jsx(Section, { bogus: 1 });
|
|
14
|
+
// @ts-expect-error invalid Button.style value
|
|
15
|
+
_jsx(Button, { style: "nope", children: "x" });
|
|
16
|
+
// @ts-expect-error excess prop on Button
|
|
17
|
+
_jsx(Button, { extra: true, children: "x" });
|
|
18
|
+
// @ts-expect-error Message.accent must be a string
|
|
19
|
+
_jsx(Message, { accent: 1 });
|
|
20
|
+
// @ts-expect-error Divider takes no children
|
|
21
|
+
_jsx(Divider, { children: "x" });
|
|
22
|
+
// @ts-expect-error Image.url is required
|
|
23
|
+
_jsx(Image, { alt: "x" });
|
|
24
|
+
// @ts-expect-error Select.options is required
|
|
25
|
+
_jsx(Select, { placeholder: "p" });
|
|
26
|
+
// @ts-expect-error Chart.data is required
|
|
27
|
+
_jsx(Chart, { title: "x" });
|
|
28
|
+
// @ts-expect-error invalid Chart.type value
|
|
29
|
+
_jsx(Chart, { type: "scatter", data: [] });
|
|
30
|
+
// Valid usages β must type-check cleanly.
|
|
31
|
+
_jsxs(Section, { children: ["hello ", 42] });
|
|
32
|
+
_jsx(Message, { accent: "#27AE60", children: _jsx(Header, { children: "Title" }) });
|
|
33
|
+
_jsx(Button, { style: "primary", value: { ok: true }, onClick: () => { }, children: "Go" });
|
|
34
|
+
_jsx(Image, { url: "https://example.com/x.png", alt: "x" });
|
|
35
|
+
_jsx(Chart, { type: "line", title: "Revenue", xAxisTitle: "Month", yAxisTitle: "USD", data: [{ label: "Jan", value: 10 }] });
|
|
36
|
+
// Button.value flows into onClick: ctx.action.value is inferred, not unknown.
|
|
37
|
+
_jsx(Button, { value: { confirmed: true }, onClick: (ctx) => {
|
|
38
|
+
ctx.action.value?.confirmed;
|
|
39
|
+
// @ts-expect-error 'nope' is not on the inferred value type
|
|
40
|
+
ctx.action.value?.nope;
|
|
41
|
+
}, children: "Confirm" });
|
|
42
|
+
};
|
|
43
|
+
void __typeGuards;
|
|
44
|
+
describe("component vocabulary", () => {
|
|
45
|
+
it("Message wraps children with intrinsic type 'message'", () => {
|
|
46
|
+
const out = renderToIR(_jsx(Message, { children: _jsx(Header, { children: "Hi" }) }));
|
|
47
|
+
expect(out[0].type).toBe("message");
|
|
48
|
+
});
|
|
49
|
+
it("Button carries onClick and style in props", () => {
|
|
50
|
+
const fn = () => { };
|
|
51
|
+
const out = renderToIR(_jsx(Actions, { children: _jsx(Button, { onClick: fn, style: "primary", children: "Go" }) }));
|
|
52
|
+
const actions = out[0];
|
|
53
|
+
const button = actions.props.children[0];
|
|
54
|
+
expect(button.type).toBe("button");
|
|
55
|
+
expect(button.props.onClick).toBe(fn);
|
|
56
|
+
expect(button.props.style).toBe("primary");
|
|
57
|
+
});
|
|
58
|
+
it("Divider renders with no children", () => {
|
|
59
|
+
const out = renderToIR(_jsx(Divider, {}));
|
|
60
|
+
expect(out[0]).toMatchObject({ type: "divider" });
|
|
61
|
+
});
|
|
62
|
+
it("Table carries columns and nests RowβCellβtext children", () => {
|
|
63
|
+
const out = renderToIR(_jsx(Table, { columns: [{ header: "Name" }, { header: "Status", align: "center" }], children: _jsxs(Row, { children: [_jsx(Cell, { children: "Ana" }), _jsx(Cell, { children: "Active" })] }) }));
|
|
64
|
+
const table = out[0];
|
|
65
|
+
expect(table.type).toBe("table");
|
|
66
|
+
expect(table.props.columns.length).toBe(2);
|
|
67
|
+
const rows = table.props.children;
|
|
68
|
+
const row = rows[0];
|
|
69
|
+
expect(row.type).toBe("row");
|
|
70
|
+
const cells = row.props.children;
|
|
71
|
+
expect(cells.length).toBe(2);
|
|
72
|
+
expect(cells[0].type).toBe("cell");
|
|
73
|
+
const cellText = cells[0].props.children[0];
|
|
74
|
+
expect(cellText).toMatchObject({ type: "text", props: { value: "Ana" } });
|
|
75
|
+
});
|
|
76
|
+
it("Chart carries type, title, axis titles, and data in props", () => {
|
|
77
|
+
const data = [
|
|
78
|
+
{ label: "Jan", value: 10 },
|
|
79
|
+
{ label: "Feb", value: 20 },
|
|
80
|
+
];
|
|
81
|
+
const out = renderToIR(_jsx(Chart, { type: "line", title: "Revenue", yAxisTitle: "USD", data: data }));
|
|
82
|
+
const chart = out[0];
|
|
83
|
+
expect(chart.type).toBe("chart");
|
|
84
|
+
expect(chart.props.type).toBe("line");
|
|
85
|
+
expect(chart.props.title).toBe("Revenue");
|
|
86
|
+
expect(chart.props.yAxisTitle).toBe("USD");
|
|
87
|
+
expect(chart.props.data).toEqual(data);
|
|
88
|
+
});
|
|
89
|
+
});
|
package/dist/emoji.d.ts
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/** Platforms that support a normalized emoji token. */
|
|
2
|
+
export type EmojiPlatform = "slack" | "discord" | "telegram";
|
|
3
|
+
export interface EmojiEntry {
|
|
4
|
+
/** Canonical cross-platform name (matches a `KnownEmoji`). */
|
|
5
|
+
name: KnownEmoji;
|
|
6
|
+
/** Unicode token β the native form for Discord and Telegram. */
|
|
7
|
+
unicode: string;
|
|
8
|
+
/** Slack shortcodes (no colons); index 0 is canonical, the rest are aliases. */
|
|
9
|
+
slack: string[];
|
|
10
|
+
}
|
|
11
|
+
/** Starter set; unknown emoji pass through unnormalized as `rawEmoji`. */
|
|
12
|
+
export declare const EMOJI_TABLE: readonly [{
|
|
13
|
+
readonly name: "thumbs_up";
|
|
14
|
+
readonly unicode: "π";
|
|
15
|
+
readonly slack: ["+1", "thumbsup"];
|
|
16
|
+
}, {
|
|
17
|
+
readonly name: "thumbs_down";
|
|
18
|
+
readonly unicode: "π";
|
|
19
|
+
readonly slack: ["-1", "thumbsdown"];
|
|
20
|
+
}, {
|
|
21
|
+
readonly name: "heart";
|
|
22
|
+
readonly unicode: "β€οΈ";
|
|
23
|
+
readonly slack: ["heart"];
|
|
24
|
+
}, {
|
|
25
|
+
readonly name: "fire";
|
|
26
|
+
readonly unicode: "π₯";
|
|
27
|
+
readonly slack: ["fire"];
|
|
28
|
+
}, {
|
|
29
|
+
readonly name: "eyes";
|
|
30
|
+
readonly unicode: "π";
|
|
31
|
+
readonly slack: ["eyes"];
|
|
32
|
+
}, {
|
|
33
|
+
readonly name: "bug";
|
|
34
|
+
readonly unicode: "π";
|
|
35
|
+
readonly slack: ["bug"];
|
|
36
|
+
}, {
|
|
37
|
+
readonly name: "check";
|
|
38
|
+
readonly unicode: "β
";
|
|
39
|
+
readonly slack: ["white_check_mark", "heavy_check_mark"];
|
|
40
|
+
}, {
|
|
41
|
+
readonly name: "cross";
|
|
42
|
+
readonly unicode: "β";
|
|
43
|
+
readonly slack: ["x"];
|
|
44
|
+
}, {
|
|
45
|
+
readonly name: "tada";
|
|
46
|
+
readonly unicode: "π";
|
|
47
|
+
readonly slack: ["tada"];
|
|
48
|
+
}, {
|
|
49
|
+
readonly name: "rocket";
|
|
50
|
+
readonly unicode: "π";
|
|
51
|
+
readonly slack: ["rocket"];
|
|
52
|
+
}, {
|
|
53
|
+
readonly name: "warning";
|
|
54
|
+
readonly unicode: "β οΈ";
|
|
55
|
+
readonly slack: ["warning"];
|
|
56
|
+
}, {
|
|
57
|
+
readonly name: "question";
|
|
58
|
+
readonly unicode: "β";
|
|
59
|
+
readonly slack: ["question"];
|
|
60
|
+
}, {
|
|
61
|
+
readonly name: "raised_hands";
|
|
62
|
+
readonly unicode: "π";
|
|
63
|
+
readonly slack: ["raised_hands"];
|
|
64
|
+
}, {
|
|
65
|
+
readonly name: "clap";
|
|
66
|
+
readonly unicode: "π";
|
|
67
|
+
readonly slack: ["clap"];
|
|
68
|
+
}, {
|
|
69
|
+
readonly name: "pray";
|
|
70
|
+
readonly unicode: "π";
|
|
71
|
+
readonly slack: ["pray"];
|
|
72
|
+
}, {
|
|
73
|
+
readonly name: "smile";
|
|
74
|
+
readonly unicode: "π";
|
|
75
|
+
readonly slack: ["smile"];
|
|
76
|
+
}, {
|
|
77
|
+
readonly name: "thinking";
|
|
78
|
+
readonly unicode: "π€";
|
|
79
|
+
readonly slack: ["thinking_face"];
|
|
80
|
+
}];
|
|
81
|
+
export type KnownEmoji = (typeof EMOJI_TABLE)[number]["name"];
|
|
82
|
+
/**
|
|
83
|
+
* Accepts a known canonical name (with autocomplete) or any string. Unknown
|
|
84
|
+
* strings pass through as a platform-native token (custom/server emoji).
|
|
85
|
+
*/
|
|
86
|
+
export type EmojiValue = KnownEmoji | (string & {});
|
|
87
|
+
/** Typed accessor map, e.g. `emoji.thumbs_up`. Each value is its own name. */
|
|
88
|
+
export declare const emoji: Record<KnownEmoji, KnownEmoji>;
|
|
89
|
+
/**
|
|
90
|
+
* Resolves any known emoji form β canonical name, Slack shortcode/alias, or
|
|
91
|
+
* Unicode token β to the platform-native token, or `undefined` if unknown.
|
|
92
|
+
*/
|
|
93
|
+
export declare function toPlatformEmoji(value: EmojiValue, platform: EmojiPlatform): string | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Resolve any known emoji form β canonical name, Slack shortcode/alias, or
|
|
96
|
+
* Unicode token (with or without VS16) β to its canonical name,
|
|
97
|
+
* platform-agnostically. Unknown tokens (e.g. custom/server emoji) pass through
|
|
98
|
+
* unchanged. Used to normalize caller-supplied reaction filters so they match
|
|
99
|
+
* the canonical names ingress produces.
|
|
100
|
+
*/
|
|
101
|
+
export declare function toCanonicalEmoji(value: EmojiValue): EmojiValue;
|
|
102
|
+
/** Platform-native token β canonical name, or `undefined` if unrecognized. */
|
|
103
|
+
export declare function normalizeEmoji(token: string, platform: EmojiPlatform): EmojiValue | undefined;
|
|
104
|
+
//# sourceMappingURL=emoji.d.ts.map
|