inline-chat-kit 0.55.2 → 0.56.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/CHANGELOG.md +47 -0
- package/README.md +110 -2
- package/dist/Approval/Approval.d.ts +13 -2
- package/dist/Artifact/ArtifactPane.d.ts +1 -1
- package/dist/Attachments/Attachments.d.ts +2 -3
- package/dist/Branch/Branch.d.ts +2 -6
- package/dist/ChainOfThought/ChainOfThought.d.ts +2 -7
- package/dist/ChatExperience/ChatExperience.d.ts +47 -5
- package/dist/{ChatExperience-BwjmNCvw.js → ChatExperience-DCta8bv3.js} +2103 -1935
- package/dist/ChatExperience-DCta8bv3.js.map +1 -0
- package/dist/ChatInput/AddCardsOverlay.d.ts +20 -3
- package/dist/ChatInput/ChatInput.d.ts +10 -0
- package/dist/ChatTurnRow/ChatTurnRow.d.ts +36 -20
- package/dist/CodeBlock/CodeBlock.d.ts +3 -1
- package/dist/Context/Context.d.ts +2 -8
- package/dist/EmptyState/EmptyState.d.ts +1 -1
- package/dist/QuestionCard/QuestionCard.d.ts +2 -1
- package/dist/Reasoning/Reasoning.d.ts +2 -1
- package/dist/Sources/Sources.d.ts +2 -5
- package/dist/TaskList/TaskList.d.ts +2 -4
- package/dist/Tool/Tool.d.ts +2 -1
- package/dist/demo.js +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/inline-chat-kit.css +1 -1
- package/dist/inline-chat-kit.js +8 -8
- package/dist/inline-chat-kit.js.map +1 -1
- package/dist/labels/labels.d.ts +254 -0
- package/dist/turnParts/turnParts.d.ts +29 -2
- package/dist/voice/useVoiceInput.d.ts +8 -1
- package/package.json +2 -2
- package/dist/ChatExperience-BwjmNCvw.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,53 @@ The versions before 1.0 follow the pre-release convention: **a breaking change
|
|
|
8
8
|
or new public API bumps the minor**, and the patch is for fixes. Anything that would break an
|
|
9
9
|
existing install is called out under **Breaking**, with what to do about it.
|
|
10
10
|
|
|
11
|
+
## 0.56.0 — 2026-09-22
|
|
12
|
+
|
|
13
|
+
Four things that kept the kit out of a real host app: an answer could only
|
|
14
|
+
hold the kit's own parts, an approval always offered "forever", an assembled
|
|
15
|
+
chat could not be translated, and it drew controls a host had no use for.
|
|
16
|
+
Nothing here changes what an existing install draws.
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **`{ kind: "custom", id, type, data }` — the host's own card in an answer.**
|
|
21
|
+
Every other part is a component in this package; this one is drawn by the
|
|
22
|
+
new `renderPart(part, { turnId })` prop on `ChatTurnRow` and
|
|
23
|
+
`ChatExperience`, in its place among the other parts and inside the answer's
|
|
24
|
+
entrance. Merged by id like the rest, so `{ kind: "custom", id, data }`
|
|
25
|
+
replaces `data` and keeps `type`. Without a renderer, or when it returns
|
|
26
|
+
`null`, the part draws nothing. `CustomPart` is exported.
|
|
27
|
+
- **`chat` on `ChatExperience`.** It called `useChatTurns` itself, so a host
|
|
28
|
+
had no `updatePart` and a card could not change after the answer finished.
|
|
29
|
+
Pass your own hook's result and it is used instead; left out, nothing
|
|
30
|
+
changes. `onSend` is optional when `chat` is given.
|
|
31
|
+
- **`choices` on `<Approval>` and on the approval part.** `["once", "deny"]`
|
|
32
|
+
leaves "Always allow" out. Allow once stays the primary and Deny stays first.
|
|
33
|
+
`ApprovalChoice` is exported.
|
|
34
|
+
- **`labels` on `ChatExperience` and `ChatTurnRow`, and `LabelsProvider`.** One
|
|
35
|
+
`ChatLabels` object, grouped by component and partial, reaches every piece
|
|
36
|
+
through context — the header, the composer and its menu, the microphone and
|
|
37
|
+
what it announces, the highlighter, the thread, the code block's copy, the
|
|
38
|
+
pane, the jump button, the option letters, and every part. The strings that
|
|
39
|
+
were hard-coded English with no way in now all go through it.
|
|
40
|
+
`defaultLabels` is the English set. The individual `labels` props keep
|
|
41
|
+
working and win over the provider.
|
|
42
|
+
- **`headerActions` and `composerMenu` on `ChatExperience`.**
|
|
43
|
+
`headerActions={false}` (or `["theme"]`, `["share"]`) drops the built-in
|
|
44
|
+
header actions; `composerMenu={false}` removes the "+", and a list of
|
|
45
|
+
`{ id, label, icon?, onSelect? }` replaces its three entries. `ChatInput`
|
|
46
|
+
takes the same list as `menu`. `ComposerMenuItem` is exported.
|
|
47
|
+
|
|
48
|
+
### Fixed
|
|
49
|
+
|
|
50
|
+
- **Every row in `ChatExperience` re-rendered on every frame of an answer.**
|
|
51
|
+
`onOpenArtifact` was an arrow written inline in the rows' props — a new
|
|
52
|
+
function each render — so `ChatTurnRow`'s memo never held inside the
|
|
53
|
+
assembled experience. Hoisted; the custom-part test fails without it.
|
|
54
|
+
- **The composer's menu opened the file picker by matching the word "Add".**
|
|
55
|
+
Translated, it would have stopped attaching anything. It matches the entry's
|
|
56
|
+
id now.
|
|
57
|
+
|
|
11
58
|
## 0.55.2 — 2026-09-16
|
|
12
59
|
|
|
13
60
|
### Fixed
|
package/README.md
CHANGED
|
@@ -153,6 +153,14 @@ Which is why the callbacks take the turn's id rather than being closed over per
|
|
|
153
153
|
row. Pass the hook's own functions straight through — they are stable. An arrow
|
|
154
154
|
created during render is not, and hands the memo a new prop every time.
|
|
155
155
|
|
|
156
|
+
`renderPart` is a callback like the others and follows the same rule: define
|
|
157
|
+
it outside the component, or wrap it in `useCallback` / `useMemo`. A renderer
|
|
158
|
+
written inline is a new function every render, which is a changed prop on every
|
|
159
|
+
row — so every finished answer re-renders on every frame of the one arriving,
|
|
160
|
+
exactly the cost the memo exists to remove. What a card needs to change (it was
|
|
161
|
+
applied, it was sent) belongs in the part's `data`, written back with
|
|
162
|
+
`updatePart`; then only the row that owns it re-renders.
|
|
163
|
+
|
|
156
164
|
If you write your own row instead, wrap it in `React.memo` and do the same.
|
|
157
165
|
|
|
158
166
|
## The four states
|
|
@@ -217,6 +225,9 @@ input that morphs into its own bubble rather than a record of what was typed.
|
|
|
217
225
|
| `onFeedback` | `(id, verdict) => void` | | Draws the thumbs |
|
|
218
226
|
| `feedback` | `"up" \| "down" \| null` | `null` | Which one is lit |
|
|
219
227
|
| `answerActions` | `boolean` | `true` | Leave the row out |
|
|
228
|
+
| `renderPart` | `(part, { turnId }) => ReactNode` | | Draws `custom` parts — see below. Keep it stable |
|
|
229
|
+
| `composerMenu` | `ComposerMenuItem[] \| false` | built-in three | The composer's "+" menu; `false` removes the "+" |
|
|
230
|
+
| `labels` | `ChatLabels` | English | Every word the row says — see [Labels](#labels-every-word-the-kit-says) |
|
|
220
231
|
|
|
221
232
|
The live row carries **`data-active-input`**, so a page can style the composer
|
|
222
233
|
without knowing which turn it is. The case it exists for: a gradient fading the
|
|
@@ -411,15 +422,45 @@ component that owns it.
|
|
|
411
422
|
| `tasks` | `<TaskList>` | `title`, `tasks`, `collapsible` |
|
|
412
423
|
| `chain` | `<ChainOfThought>` | `steps`, `state`, `duration` |
|
|
413
424
|
| `sources` | `<Sources>` | `sources`, `title`, `collapsible` |
|
|
414
|
-
| `approval` | `<Approval>` | `title`, `description`, `tool`, `decision` |
|
|
425
|
+
| `approval` | `<Approval>` | `title`, `description`, `tool`, `decision`, `choices` |
|
|
415
426
|
| `question` | `<QuestionGroup>` | `title`, `questions`, `answers`, `activeIndex`, `collapsible` |
|
|
416
427
|
| `notice` | `<SystemMessage>` | `text`, `tone` |
|
|
417
428
|
| `artifact` | `<ArtifactCard>` | `title`, `meta`, `preview`, `lang`, `content`, `state` |
|
|
429
|
+
| `custom` | whatever `renderPart` returns | `type`, `data` — the host's own card |
|
|
418
430
|
|
|
419
431
|
`reasoning` and `chain` are the same job at two grains — a block of prose, or
|
|
420
432
|
steps that follow from one another. Sending both for one stretch of thinking
|
|
421
433
|
says it twice.
|
|
422
434
|
|
|
435
|
+
#### Your own cards: `custom`
|
|
436
|
+
|
|
437
|
+
Every other kind is a component in this package. `custom` is the host's: `type`
|
|
438
|
+
says which of your cards it is, `data` is whatever that card needs, and
|
|
439
|
+
`renderPart` draws it — in its place among the other parts, inside the answer
|
|
440
|
+
and its entrance.
|
|
441
|
+
|
|
442
|
+
```tsx
|
|
443
|
+
import type { CustomPart } from "inline-chat-kit";
|
|
444
|
+
|
|
445
|
+
// Streamed like any part…
|
|
446
|
+
yield { kind: "custom", id: "plan", type: "plan-diff", data: { changes, status: "proposed" } };
|
|
447
|
+
|
|
448
|
+
// …drawn by the host. Outside the component, so it is stable.
|
|
449
|
+
const renderPart = (part: CustomPart, { turnId }: { turnId: string }) =>
|
|
450
|
+
part.type === "plan-diff" ? <PlanDiff turnId={turnId} id={part.id} {...(part.data as PlanDiffData)} /> : null;
|
|
451
|
+
|
|
452
|
+
// …and changed after the answer has finished, by id. Only `data` is replaced.
|
|
453
|
+
updatePart(turnId, { kind: "custom", id: "plan", data: { changes, status: "applied" } });
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Without `renderPart`, or when it returns `null`, the part draws nothing — no
|
|
457
|
+
placeholder, no error. A type the host does not recognise is a type it chose
|
|
458
|
+
not to draw. `data` is replaced whole on an update, not merged: it is yours,
|
|
459
|
+
and the kit does not guess its shape.
|
|
460
|
+
|
|
461
|
+
`ChatExperience` calls `useChatTurns` itself, so a host using it passes its own
|
|
462
|
+
instead — `chat={useChatTurns({ onSend })}` — to hold `updatePart`.
|
|
463
|
+
|
|
423
464
|
#### Citing a source from the prose
|
|
424
465
|
|
|
425
466
|
`[^1]` in the answer is a **citation marker**, and the number is a position in
|
|
@@ -567,6 +608,7 @@ can already see.
|
|
|
567
608
|
| `decision` | `"once" \| "always" \| "denied" \| null` | `null` while it is still asking |
|
|
568
609
|
| `onDecide` | `(decision) => void` | |
|
|
569
610
|
| `readOnly` | `boolean` | A record of a decision made elsewhere |
|
|
611
|
+
| `choices` | `("once" \| "always" \| "deny")[]` | Which answers are offered. All three by default |
|
|
570
612
|
|
|
571
613
|
**Three answers, not two.** "Yes" and "yes forever" are not the same answer,
|
|
572
614
|
and a UI offering one button for both collects the wrong one. **Allow once is
|
|
@@ -578,6 +620,15 @@ too, so a keyboard reaches the safe answer without tabbing past the other two.
|
|
|
578
620
|
It turns red only under the pointer, because a permanently red button is the
|
|
579
621
|
first thing the eye lands on.
|
|
580
622
|
|
|
623
|
+
**Two answers, where "forever" means nothing.** Applying one change to a plan
|
|
624
|
+
happens once; `choices={["once", "deny"]}` leaves "Always allow" out. Nothing
|
|
625
|
+
else moves: Allow once is still the primary, Deny is still first in the DOM and
|
|
626
|
+
alone on the left, and the record it settles into says only what was decided.
|
|
627
|
+
|
|
628
|
+
```tsx
|
|
629
|
+
<Approval title="Apply the change to your plan" choices={["once", "deny"]} onDecide={decide} />
|
|
630
|
+
```
|
|
631
|
+
|
|
581
632
|
Give it something to show. An approval with nothing under it is asking for a
|
|
582
633
|
signature on a blank page.
|
|
583
634
|
|
|
@@ -586,7 +637,7 @@ decided. Live controls under a decision already made invite a second one that
|
|
|
586
637
|
contradicts the first.
|
|
587
638
|
|
|
588
639
|
As a `TurnPart` it is `{ kind: "approval", id, title, description?, tool?,
|
|
589
|
-
decision? }` — data, like every part, so the tool it names is drawn for it
|
|
640
|
+
decision?, choices? }` — data, like every part, so the tool it names is drawn for it
|
|
590
641
|
rather than passed in as an element. `<ChatTurnRow>` reports through
|
|
591
642
|
`onDecideApproval`.
|
|
592
643
|
|
|
@@ -1266,6 +1317,63 @@ existing call sites keep working. Its `s` / `m` / `l` map to `m` / `l` / `xl`.
|
|
|
1266
1317
|
Neither takes a dark-mode prop: the theme is a token swap on an ancestor. See
|
|
1267
1318
|
[theming.md](./theming.md).
|
|
1268
1319
|
|
|
1320
|
+
## Labels: every word the kit says
|
|
1321
|
+
|
|
1322
|
+
Every component takes a `labels` prop, and `ChatExperience` and `ChatTurnRow`
|
|
1323
|
+
take one object for all of them — grouped by the component that says it, and
|
|
1324
|
+
partial: anything left out stays English.
|
|
1325
|
+
|
|
1326
|
+
```tsx
|
|
1327
|
+
import { ChatExperience, type ChatLabels } from "inline-chat-kit";
|
|
1328
|
+
|
|
1329
|
+
const sr: ChatLabels = {
|
|
1330
|
+
input: { placeholder: "Pitaj bilo šta…", send: "Pošalji poruku", copy: "Kopiraj", edit: "Izmeni" },
|
|
1331
|
+
approval: { once: "Dozvoli jednom", deny: "Odbij", allowedOnce: "Dozvoljeno jednom", wasDenied: "Odbijeno" },
|
|
1332
|
+
reasoning: { thinking: "Razmišljam", thoughtFor: "Razmišljao" },
|
|
1333
|
+
answerActions: { copy: "Kopiraj odgovor", regenerate: "Ponovo" },
|
|
1334
|
+
tasks: { progress: "{done} od {total}" },
|
|
1335
|
+
};
|
|
1336
|
+
|
|
1337
|
+
<ChatExperience onSend={send} labels={sr} />;
|
|
1338
|
+
```
|
|
1339
|
+
|
|
1340
|
+
What counts as a word: text on screen, an `aria-label`, a `title`, a
|
|
1341
|
+
placeholder, text only a screen reader gets, and what is said through the live
|
|
1342
|
+
region. `{name}` in a value is filled in — keep it, and move it wherever the
|
|
1343
|
+
language wants it. `defaultLabels` is the full English set, which is also the
|
|
1344
|
+
list of what there is to translate.
|
|
1345
|
+
|
|
1346
|
+
It travels by context, not by a prop on every row, so the rows' memo is not
|
|
1347
|
+
disturbed. For pieces assembled by hand, `LabelsProvider` does what
|
|
1348
|
+
`ChatExperience` does:
|
|
1349
|
+
|
|
1350
|
+
```tsx
|
|
1351
|
+
<LabelsProvider labels={sr}>
|
|
1352
|
+
{turns.map((turn) => <ChatTurnRow key={turn.id} turn={turn} /* … */ />)}
|
|
1353
|
+
</LabelsProvider>
|
|
1354
|
+
```
|
|
1355
|
+
|
|
1356
|
+
The value is compared by content, so an object written inline costs nothing
|
|
1357
|
+
after the first render. A component's own `labels` prop wins over the provider
|
|
1358
|
+
for that one instance.
|
|
1359
|
+
|
|
1360
|
+
### Turning off what you do not use
|
|
1361
|
+
|
|
1362
|
+
`ChatExperience` draws a theme toggle and Share in the header and a "+" menu in
|
|
1363
|
+
the composer. A host that has none of those says so:
|
|
1364
|
+
|
|
1365
|
+
```tsx
|
|
1366
|
+
<ChatExperience
|
|
1367
|
+
onSend={send}
|
|
1368
|
+
headerActions={false} // or ["theme"], or ["share"]
|
|
1369
|
+
composerMenu={false} // or your own: [{ id, label, icon?, onSelect }]
|
|
1370
|
+
/>
|
|
1371
|
+
```
|
|
1372
|
+
|
|
1373
|
+
The saved highlights button is not one of the header's actions — it appears
|
|
1374
|
+
only once there is a highlight, and it is the only way back to them. An entry in
|
|
1375
|
+
your own menu with id `"attach"` and no `onSelect` opens the file picker.
|
|
1376
|
+
|
|
1269
1377
|
## Theming
|
|
1270
1378
|
|
|
1271
1379
|
The kit reads CSS custom properties, all prefixed `--ick-`. That is the whole
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import { ApprovalLabels } from '../labels/labels';
|
|
2
3
|
/** Once, every time from now on, or not at all. */
|
|
3
4
|
export type Decision = "once" | "always" | "denied";
|
|
4
|
-
|
|
5
|
+
/** The buttons, by what they answer. `"deny"` is the button; `"denied"` the record. */
|
|
6
|
+
export type ApprovalChoice = "once" | "always" | "deny";
|
|
7
|
+
type Labels = ApprovalLabels;
|
|
5
8
|
export interface ApprovalProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
|
|
6
9
|
/** What is being asked. One line: "Run a command in your shell". */
|
|
7
10
|
title: ReactNode;
|
|
@@ -20,6 +23,14 @@ export interface ApprovalProps extends Omit<HTMLAttributes<HTMLElement>, "title"
|
|
|
20
23
|
onDecide?: (decision: Decision) => void;
|
|
21
24
|
/** Nothing can be decided from here — a record of a decision already made. */
|
|
22
25
|
readOnly?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Which answers are offered. All three when left out.
|
|
28
|
+
*
|
|
29
|
+
* Leave out `"always"` where a standing permission means nothing — applying
|
|
30
|
+
* one edit to a plan is a thing that happens once. "Allow once" stays the
|
|
31
|
+
* primary and Deny stays first; only the button that is not offered goes.
|
|
32
|
+
*/
|
|
33
|
+
choices?: ApprovalChoice[];
|
|
23
34
|
labels?: Partial<Labels>;
|
|
24
35
|
}
|
|
25
36
|
/**
|
|
@@ -38,5 +49,5 @@ export interface ApprovalProps extends Omit<HTMLAttributes<HTMLElement>, "title"
|
|
|
38
49
|
* decided. Leaving live controls under a decision already made invites a
|
|
39
50
|
* second, contradictory one.
|
|
40
51
|
*/
|
|
41
|
-
export declare function Approval({ title, description, children, decision, onDecide, readOnly, labels, className, ...rest }: ApprovalProps): import("react").JSX.Element;
|
|
52
|
+
export declare function Approval({ title, description, children, decision, onDecide, readOnly, choices, labels, className, ...rest }: ApprovalProps): import("react").JSX.Element;
|
|
42
53
|
export {};
|
|
@@ -47,4 +47,4 @@ export interface ArtifactPaneProps extends Omit<HTMLAttributes<HTMLDivElement>,
|
|
|
47
47
|
* conversation, and it must **not** be trapped unless the pane is covering
|
|
48
48
|
* that conversation. Every host gets one of those two wrong.
|
|
49
49
|
*/
|
|
50
|
-
export declare function ArtifactPane({ title, meta, children, onClose, modal, expanded, onToggleExpanded, closeLabel, expandLabel, collapseLabel, className, ...rest }: ArtifactPaneProps): import("react").JSX.Element;
|
|
50
|
+
export declare function ArtifactPane({ title, meta, children, onClose, modal, expanded, onToggleExpanded, closeLabel: closeProp, expandLabel: expandProp, collapseLabel: collapseProp, className, ...rest }: ArtifactPaneProps): import("react").JSX.Element;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { HTMLAttributes } from 'react';
|
|
2
|
+
import { LabelsOf } from '../labels/labels';
|
|
2
3
|
/** Something sent along with a message. */
|
|
3
4
|
export interface Attachment {
|
|
4
5
|
id: string;
|
|
@@ -16,9 +17,7 @@ export interface Attachment {
|
|
|
16
17
|
/** In bytes. Shown beside the name. */
|
|
17
18
|
size?: number;
|
|
18
19
|
}
|
|
19
|
-
type Labels =
|
|
20
|
-
remove: string;
|
|
21
|
-
};
|
|
20
|
+
type Labels = LabelsOf<"attachments">;
|
|
22
21
|
export interface AttachmentsProps extends Omit<HTMLAttributes<HTMLUListElement>, "onRemove"> {
|
|
23
22
|
attachments: Attachment[];
|
|
24
23
|
/**
|
package/dist/Branch/Branch.d.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import { HTMLAttributes } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
next: string;
|
|
5
|
-
/** `{index}` and `{total}` are filled in. */
|
|
6
|
-
position: string;
|
|
7
|
-
};
|
|
2
|
+
import { LabelsOf } from '../labels/labels';
|
|
3
|
+
type Labels = LabelsOf<"branch">;
|
|
8
4
|
export interface BranchProps extends Omit<HTMLAttributes<HTMLDivElement>, "onSelect"> {
|
|
9
5
|
/** How many answers this turn has had. */
|
|
10
6
|
total: number;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { HTMLAttributes, ReactNode } from 'react';
|
|
2
2
|
import { WorkState } from '../stateGlyph/StateGlyph';
|
|
3
|
+
import { LabelsOf } from '../labels/labels';
|
|
3
4
|
/** One step of a derivation: what was worked out, and the working. */
|
|
4
5
|
export interface Thought {
|
|
5
6
|
id: string;
|
|
@@ -10,13 +11,7 @@ export interface Thought {
|
|
|
10
11
|
/** Defaults to `done`: a step you can read is a step that happened. */
|
|
11
12
|
state?: WorkState;
|
|
12
13
|
}
|
|
13
|
-
type Labels =
|
|
14
|
-
/** Followed by the count: "Thought through 4 steps". */
|
|
15
|
-
through: string;
|
|
16
|
-
step: string;
|
|
17
|
-
steps: string;
|
|
18
|
-
thinking: string;
|
|
19
|
-
};
|
|
14
|
+
type Labels = LabelsOf<"chain">;
|
|
20
15
|
export interface ChainOfThoughtProps extends Omit<HTMLAttributes<HTMLElement>, "title"> {
|
|
21
16
|
steps: Thought[];
|
|
22
17
|
/** The chain as a whole. `thinking` holds it open and narrates the last step. */
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { ChatHeaderAction } from '../ChatHeader/ChatHeader';
|
|
3
3
|
import { ReplyThreadPopupProps } from '../ReplyThreadPopup/ReplyThreadPopup';
|
|
4
|
-
import { UseChatTurnsOptions } from '../useChatTurns/useChatTurns';
|
|
4
|
+
import { UseChatTurnsOptions, UseChatTurnsResult } from '../useChatTurns/useChatTurns';
|
|
5
5
|
import { FoldMotion } from '../QuestionGroup/QuestionGroup';
|
|
6
6
|
import { InlineAnimConfig } from '../ChatInput/ChatInput';
|
|
7
7
|
import { TranscribeHandler } from '../voice/useVoiceInput';
|
|
8
|
-
import { TurnPartUpdate } from '../turnParts/turnParts';
|
|
8
|
+
import { CustomPart, TurnPartUpdate } from '../turnParts/turnParts';
|
|
9
|
+
import { ComposerMenuItem } from '../ChatInput/AddCardsOverlay';
|
|
10
|
+
import { ChatLabels } from '../labels/labels';
|
|
9
11
|
import { Answer } from '../QuestionCard/types';
|
|
10
12
|
import { Decision } from '../Approval/Approval';
|
|
11
13
|
/**
|
|
@@ -60,10 +62,50 @@ export interface ChatExperienceArtifact {
|
|
|
60
62
|
}
|
|
61
63
|
/** A part the host drives, handed the writer for the turn it belongs to. */
|
|
62
64
|
export type PartWriter = (turnId: string, part: TurnPartUpdate) => void;
|
|
65
|
+
/** The header's built-in actions, by id. */
|
|
66
|
+
export type ChatExperienceHeaderAction = "theme" | "share";
|
|
63
67
|
export interface ChatExperienceProps {
|
|
64
68
|
/** Where answers come from. Return a string, a promise of one, or an async
|
|
65
|
-
iterable of deltas — see `useChatTurns`.
|
|
66
|
-
|
|
69
|
+
iterable of deltas — see `useChatTurns`. Required unless `chat` is
|
|
70
|
+
given, which brings its own. */
|
|
71
|
+
onSend?: UseChatTurnsOptions["onSend"];
|
|
72
|
+
/**
|
|
73
|
+
* The conversation, held by the host.
|
|
74
|
+
*
|
|
75
|
+
* Left out, this component calls `useChatTurns` itself and nothing outside
|
|
76
|
+
* can reach the turns. Pass what your own `useChatTurns` returned and the
|
|
77
|
+
* host has the same handle this does — `updatePart` in particular, which is
|
|
78
|
+
* how a card in an answer changes after the answer has finished ("Apply" →
|
|
79
|
+
* "Applied"). `onSend` is ignored then; the hook you called has one.
|
|
80
|
+
*/
|
|
81
|
+
chat?: UseChatTurnsResult;
|
|
82
|
+
/**
|
|
83
|
+
* Draws the host's own `{ kind: "custom" }` parts. See `ChatTurnRow`. Keep
|
|
84
|
+
* it stable — outside the component or in `useCallback` — or every row
|
|
85
|
+
* re-renders on every frame of an answer arriving.
|
|
86
|
+
*/
|
|
87
|
+
renderPart?: (part: CustomPart, context: {
|
|
88
|
+
turnId: string;
|
|
89
|
+
}) => ReactNode;
|
|
90
|
+
/**
|
|
91
|
+
* Every word the chat says, grouped by the component that says it. Partial:
|
|
92
|
+
* anything left out stays English. Reaches every piece through context, so
|
|
93
|
+
* an inline object costs nothing — it is compared by content.
|
|
94
|
+
*/
|
|
95
|
+
labels?: ChatLabels;
|
|
96
|
+
/**
|
|
97
|
+
* The header's built-in actions. `true` (the default) is the theme toggle
|
|
98
|
+
* and Share; `false` is neither; a list keeps only those named. The saved
|
|
99
|
+
* highlights button is not one of these — it appears only once there is a
|
|
100
|
+
* highlight, and it is the only way back to them. `actions` still adds your
|
|
101
|
+
* own after whatever is left.
|
|
102
|
+
*/
|
|
103
|
+
headerActions?: boolean | ChatExperienceHeaderAction[];
|
|
104
|
+
/**
|
|
105
|
+
* The composer's "+" menu. `false` takes the "+" away; a list replaces the
|
|
106
|
+
* built-in three (Add, Design, Connectors). Keep a list stable.
|
|
107
|
+
*/
|
|
108
|
+
composerMenu?: ComposerMenuItem[] | false;
|
|
67
109
|
/** Speech to text. The kit records; the host transcribes. Omit and the
|
|
68
110
|
microphone does not appear. */
|
|
69
111
|
onTranscribe?: TranscribeHandler;
|
|
@@ -112,4 +154,4 @@ export interface ChatExperienceProps {
|
|
|
112
154
|
onDecideApproval?: (write: PartWriter, turnId: string, partId: string, decision: Decision) => void;
|
|
113
155
|
className?: string;
|
|
114
156
|
}
|
|
115
|
-
export declare function ChatExperience({ onSend, onTranscribe, onThreadReply, title, backHref, backLabel, actions, placeholder, empty, contextTotal, contextBase, artifact, theme: themeProp, onThemeChange, cursor, selectionToggle, anchorOffset, endOffset, animationConfig, foldMotion, feedDelay, onAnswerQuestion, onEditQuestion, onDecideApproval, className, }: ChatExperienceProps): import("react").JSX.Element;
|
|
157
|
+
export declare function ChatExperience({ onSend, chat: hostChat, renderPart, labels, headerActions: builtInActions, composerMenu, onTranscribe, onThreadReply, title: titleProp, backHref, backLabel, actions, placeholder, empty, contextTotal, contextBase, artifact, theme: themeProp, onThemeChange, cursor, selectionToggle, anchorOffset, endOffset, animationConfig, foldMotion, feedDelay, onAnswerQuestion, onEditQuestion, onDecideApproval, className, }: ChatExperienceProps): import("react").JSX.Element;
|