@m6d/cortex-react 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -22,18 +22,27 @@ export function Chat() {
22
22
  }
23
23
  ```
24
24
 
25
- `CortexReactConfig` is the shared `CortexConfig` plus a React-only `toolComponents` slot (`Record<string, ComponentType<CortexToolComponentInputs>>`). Every other property, the client tools flow, and the media blocks are documented in [`packages/cortex-angular/README.md`](../cortex-angular/README.md); only the `toolComponents` and `injector` rows are Angular-specific.
25
+ `CortexReactConfig` is the shared `CortexConfig` plus a React-only `toolComponents` field (`Record<string, ComponentType<CortexToolComponentInputs>>`). Every other property, the client tools flow, and the media blocks are documented in [`packages/cortex-angular/README.md`](../cortex-angular/README.md); only the `toolComponents` and `injector` rows are Angular-specific.
26
26
 
27
- ## Custom header
27
+ ## Custom parts
28
28
 
29
- `renderHeader` replaces the header on both screens, the chat and the history,
30
- and receives the same context the Angular `cortexHeader` template does (fields
31
- listed in the Angular README):
29
+ With `slots` you draw the widget's parts yourself: `header`, `landing` (the
30
+ blank chat) and `threadList` (the history's list). Each is a component that
31
+ takes the context the default is drawn from as its props, the same one
32
+ Angular's `cortexSlot` templates get (fields listed in the Angular README). The
33
+ landing's `composer` is a React node to place. Define slot components outside
34
+ render: a new component each render remounts the part.
32
35
 
33
36
  ```tsx
34
- <CortexChatWidget
35
- config={config}
36
- renderHeader={(chat) => (
37
+ import {
38
+ CortexChatWidget,
39
+ type CortexHeaderContext,
40
+ type CortexLandingContext,
41
+ type CortexReactSlots,
42
+ } from '@m6d/cortex-react';
43
+
44
+ function Header(chat: CortexHeaderContext) {
45
+ return (
37
46
  <div className="cortex-widget__chat-header">
38
47
  <div className="cortex-widget__chat-title-wrap">
39
48
  <p className="cortex-widget__chat-title">{chat.title ?? chat.agentName}</p>
@@ -42,8 +51,21 @@ listed in the Angular README):
42
51
  +
43
52
  </button>
44
53
  </div>
45
- )}
46
- />
54
+ );
55
+ }
56
+
57
+ function Landing(landing: CortexLandingContext) {
58
+ return (
59
+ <div className="cortex-widget__landing">
60
+ <h1>{landing.greeting}</h1>
61
+ {landing.composer}
62
+ </div>
63
+ );
64
+ }
65
+
66
+ const slots = { header: Header, landing: Landing } satisfies CortexReactSlots;
67
+
68
+ <CortexChatWidget config={config} slots={slots} />;
47
69
  ```
48
70
 
49
71
  The theming tokens and the table actions are the same as Angular's.
package/dist/index.d.ts CHANGED
@@ -19,6 +19,14 @@ export type ThreadSummary = {
19
19
  name: string;
20
20
  };
21
21
  };
22
+ /**
23
+ * One landing-page chip: the widget shows `title` and sends `prompt` as the
24
+ * first message when clicked. The two may be the same text.
25
+ */
26
+ export type Suggestion = {
27
+ title: string;
28
+ prompt: string;
29
+ };
22
30
  export type CortexHeaders = Record<string, string>;
23
31
  /**
24
32
  * How the widget reaches its cortex server. `baseUrl` may be a thunk so a host
@@ -37,7 +45,9 @@ export type MediaRenderContext = {
37
45
  * Draws a closed media fence's `source` into `host`, resolves once drawn, and
38
46
  * returns the teardown. A consumer's `mediaRenderers` config entry has this
39
47
  * shape too: one per fence language, replacing the built-in of the same name
40
- * or adding a language of its own.
48
+ * or adding a language of its own. The same source can be drawn twice at once,
49
+ * inline and in its expanded view, so a renderer keeps no state that two
50
+ * drawings would share.
41
51
  */
42
52
  export type MediaRenderer = (host: HTMLElement, source: string, context: MediaRenderContext) => Promise<() => void>;
43
53
  export type MediaRenderers = Partial<Record<string, MediaRenderer>>;
@@ -45,31 +55,6 @@ export type MediaRenderers = Partial<Record<string, MediaRenderer>>;
45
55
  export type Localized<T> = T | Partial<Record<Locale, T>>;
46
56
  export type CortexViewMode = "helper" | "full";
47
57
  export type CortexTheme = "light" | "dark" | "system";
48
- /**
49
- * What a host's own header receives in place of the widget's: where the
50
- * widget is, what to show, and the actions the default header offers. One
51
- * header serves both screens; `screen` says which is showing.
52
- */
53
- export type CortexHeaderContext = {
54
- screen: "chat" | "threads";
55
- viewMode: CortexViewMode;
56
- /** The open thread's title; null on a new chat. */
57
- title: string | null;
58
- /** `agentName` in the widget's locale. */
59
- agentName: string | undefined;
60
- isWorking: boolean;
61
- /** Whether the host enabled the debug switch, and whether it is on. */
62
- debug: {
63
- shown: boolean;
64
- on: boolean;
65
- };
66
- newChat: () => void;
67
- /** Shows the history: the history screen, or in full mode the sidebar where it is hidden. */
68
- openHistory: () => void;
69
- /** Returns to the open chat from wherever `openHistory` went. */
70
- closeHistory: () => void;
71
- toggleDebug: () => void;
72
- };
73
58
  export type CortexToolCallContext = {
74
59
  threadId: string;
75
60
  };
@@ -93,7 +78,7 @@ export type CortexToolComponentInputs = {
93
78
  };
94
79
  /**
95
80
  * The framework-neutral part of the widget's configuration. Each SDK extends it
96
- * with its own `toolComponents` slot, which is the one field whose type is
81
+ * with its own `toolComponents` field, which is the one field whose type is
97
82
  * inherently framework-bound.
98
83
  */
99
84
  export type CortexConfig = {
@@ -134,20 +119,95 @@ export type CortexConfig = {
134
119
  trustSameOriginEmbeds?: boolean;
135
120
  hooks?: CortexHooks;
136
121
  };
122
+ /**
123
+ * What the header receives, the host's own or the widget's: where the widget
124
+ * is, what to show, and the actions the default header offers. One header
125
+ * serves both screens; `screen` says which is showing.
126
+ */
127
+ export type CortexHeaderContext = {
128
+ screen: "chat" | "threads";
129
+ viewMode: CortexViewMode;
130
+ /** The open thread's title; null on a new chat. */
131
+ title: string | null;
132
+ /** `agentName` in the widget's locale. */
133
+ agentName: string | undefined;
134
+ /** How many conversations the history lists; 0 while it loads. */
135
+ threadCount: number;
136
+ isWorking: boolean;
137
+ /** Whether the host enabled the debug switch, and whether it is on. */
138
+ debug: {
139
+ shown: boolean;
140
+ on: boolean;
141
+ };
142
+ newChat: () => void;
143
+ /** Shows the history: the history screen, or in full mode the sidebar where it is hidden. */
144
+ openHistory: () => void;
145
+ /** Returns to the open chat from wherever `openHistory` went. */
146
+ closeHistory: () => void;
147
+ toggleDebug: () => void;
148
+ };
149
+ /**
150
+ * What the blank-chat landing receives, the host's own or the widget's. The
151
+ * composer arrives ready to place as the SDK's own view type (`View`), so a
152
+ * custom landing keeps the widget's attachments and send rules. Each SDK
153
+ * exports it as `CortexLandingContext` with its view type filled in.
154
+ */
155
+ export type LandingContext<View> = {
156
+ /** The agent's greeting in the widget's locale, or the built-in one. */
157
+ greeting: string;
158
+ /** Empty until the handshake answers, and for an agent that takes no messages. */
159
+ suggestions: Suggestion[];
160
+ /** Newest first; undefined while the first load is out. */
161
+ threads: ThreadSummary[] | undefined;
162
+ /** The composer, or the notice an agent that takes no messages shows instead; empty until the handshake answers. */
163
+ composer: View;
164
+ /**
165
+ * Sends a first message, which opens a thread and swaps the landing for it.
166
+ * Does nothing until the handshake answers, or for an agent that takes no messages.
167
+ */
168
+ send: (prompt: string) => void;
169
+ openThread: (thread: ThreadSummary) => void;
170
+ };
171
+ /** What the history's list receives, the host's own or the widget's. Its header is the header slot. */
172
+ export type CortexThreadListContext = {
173
+ /** Newest first; undefined while the first load is out. */
174
+ threads: ThreadSummary[] | undefined;
175
+ /** The open thread's id; undefined on a new chat. */
176
+ selectedThreadId: string | undefined;
177
+ openThread: (thread: ThreadSummary) => void;
178
+ deleteThread: (threadId: string) => void;
179
+ newChat: () => void;
180
+ };
181
+ /** Each part of the widget a host can draw itself, with the context it receives. */
182
+ export type CortexSlotContexts<View> = {
183
+ header: CortexHeaderContext;
184
+ landing: LandingContext<View>;
185
+ threadList: CortexThreadListContext;
186
+ };
137
187
  export type CortexReactConfig = CortexConfig & {
138
188
  toolComponents?: Record<string, ComponentType<CortexToolComponentInputs>>;
139
189
  };
140
- export type HeaderRenderer = (chat: CortexHeaderContext) => ReactNode;
190
+ /** The landing's context, its composer a React node to place. */
191
+ export type CortexLandingContext = LandingContext<ReactNode>;
192
+ /**
193
+ * The parts of the widget a host draws itself: each a component taking the
194
+ * part's context as its props, the same type as the widget's default.
195
+ */
196
+ export type CortexReactSlots = {
197
+ [Slot in keyof CortexSlotContexts<ReactNode>]?: ComponentType<CortexSlotContexts<ReactNode>[Slot]>;
198
+ };
141
199
  /** The chat widget: the thread list, the open conversation and its composer, for the agent `config` points at. */
142
- export declare function CortexChatWidget({ config, className, renderHeader, }: {
200
+ export declare function CortexChatWidget({ config, className, slots, }: {
143
201
  config: CortexReactConfig;
144
202
  /** Sizing classes for the host. */
145
203
  className?: string;
146
204
  /**
147
- * The host's own header. When given it replaces the default on both the
148
- * chat and the history screen, and receives the widget's state and actions.
205
+ * The host's own parts. Each given one replaces the widget's default and
206
+ * receives the context the default is drawn from as its props. `header`
207
+ * serves both the chat and the history screen. Pass components defined
208
+ * outside render: a new one each render remounts the part.
149
209
  */
150
- renderHeader?: HeaderRenderer;
210
+ slots?: CortexReactSlots;
151
211
  }): import("react").JSX.Element;
152
212
 
153
213
  export {};