inline-chat-kit 0.57.0 → 0.59.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 +79 -0
- package/README.md +105 -2
- package/dist/ChatExperience/ChatExperience.d.ts +60 -2
- package/dist/{ChatExperience-Bawy_cnn.js → ChatExperience-BeLjIxHU.js} +956 -860
- package/dist/ChatExperience-BeLjIxHU.js.map +1 -0
- package/dist/ChatInput/ChatInput.d.ts +10 -0
- package/dist/ChatTurnRow/ChatTurnRow.d.ts +14 -1
- package/dist/Conversation/Conversation.d.ts +11 -0
- package/dist/TextHighlighter/TextHighlighter.d.ts +12 -1
- package/dist/demo/ChatExperienceDemo.d.ts +4 -1
- package/dist/demo.js +152 -140
- package/dist/demo.js.map +1 -1
- package/dist/inline-chat-kit.css +1 -1
- package/dist/inline-chat-kit.js +1 -1
- package/dist/turnParts/turnParts.d.ts +21 -3
- package/dist/useChatTurns/useChatTurns.d.ts +14 -1
- package/package.json +1 -1
- package/dist/ChatExperience-Bawy_cnn.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,85 @@ 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.59.0 — 2026-09-24
|
|
12
|
+
|
|
13
|
+
From integrating 0.58 into a host app. Nothing changes for a host that passes
|
|
14
|
+
none of the new props, with one visible difference, below.
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **`fill="window" | "container"` on `ChatExperience`.** `"container"` makes
|
|
19
|
+
the chat as tall as its parent instead of the window — both the workspace and
|
|
20
|
+
the page. Embedded in a card inset 12px top and bottom, the window's height
|
|
21
|
+
overran the card by 24px and a docked composer lost half of itself to the
|
|
22
|
+
card's clip. `"window"` is the default and is what the kit did before.
|
|
23
|
+
- **Parts sit in the prose where they arrived.** A part carries `at`, how much
|
|
24
|
+
prose had arrived when it did, stamped by `useChatTurns` on its first
|
|
25
|
+
appearance, and the row draws the answer in that order. "I suggest this
|
|
26
|
+
change:" is drawn before the change it introduces rather than under it. The
|
|
27
|
+
prose is still one string — Copy, the screen reader and versions read `ai` as
|
|
28
|
+
before; only the drawing is cut. Hosts can set `at` themselves; a part without
|
|
29
|
+
one sits before the prose, as every part did.
|
|
30
|
+
|
|
31
|
+
### Changed
|
|
32
|
+
|
|
33
|
+
- **Prose sent after a part is now drawn after it.** This is the point of the
|
|
34
|
+
above, and it is the one thing an existing host will see: a stream that sent
|
|
35
|
+
text, then a card, then more text used to draw the card on top and all the
|
|
36
|
+
text under it. Streams that send their parts before their prose — the usual
|
|
37
|
+
shape, and every stream in the demo — draw exactly as before. The one story
|
|
38
|
+
that changes is `Localized`, whose sentence now stands above its cards.
|
|
39
|
+
- **The row of actions follows the whole answer.** It lived inside the prose
|
|
40
|
+
block, so an answer made only of parts had no regenerate and no thumbs.
|
|
41
|
+
Copy is offered only when there is prose to copy.
|
|
42
|
+
|
|
43
|
+
### Fixed
|
|
44
|
+
|
|
45
|
+
- **`highlights={false}` still cut the prose into a span per word.** The spans
|
|
46
|
+
exist for marking — hit-testing, the keyboard cursor, the dimming — and with
|
|
47
|
+
marking off they were 82 elements for four sentences. The answer is text now.
|
|
48
|
+
|
|
49
|
+
## 0.58.0 — 2026-09-23
|
|
50
|
+
|
|
51
|
+
The composer at the bottom, as an alternative to the inline one — roadmap I2.
|
|
52
|
+
One prop; nothing changes for a host that does not pass it.
|
|
53
|
+
|
|
54
|
+
### Added
|
|
55
|
+
|
|
56
|
+
- **`composer="inline" | "docked"` on `ChatExperience`.** `"docked"` keeps the
|
|
57
|
+
input at the bottom edge and stacks the conversation above it. The live
|
|
58
|
+
input is still the last turn, so a sent message still becomes its bubble —
|
|
59
|
+
the same element, carried up into the conversation by its layout animation
|
|
60
|
+
as a fresh composer takes its place. A sent message is still brought to the
|
|
61
|
+
top of the view and held there while its answer is written, as it is inline;
|
|
62
|
+
the composer stays on the bottom edge while that happens, and the workspace
|
|
63
|
+
gives up whatever a phone's keyboard covers.
|
|
64
|
+
- **`nextTurn: "after-answer" | "at-send"` on `useChatTurns`.** `"at-send"`
|
|
65
|
+
opens the next input the moment a message goes, so it can be typed into
|
|
66
|
+
while the answer arrives. A send while one is in flight is now refused in
|
|
67
|
+
either mode: it used to start a second run and take the first one's abort
|
|
68
|
+
away.
|
|
69
|
+
- **`busy` on `ChatInput` and `ChatTurnRow`.** Open to type into, closed to
|
|
70
|
+
send from: Enter does nothing, the send glyph is a stop when there is an
|
|
71
|
+
`onStop` and inert when there is not.
|
|
72
|
+
- **`dock` on `Conversation`.** The last child is pinned to the bottom of the
|
|
73
|
+
view — an auto margin while the content is short, `sticky` once it is long —
|
|
74
|
+
and the room an anchor needs is put above it rather than below, where
|
|
75
|
+
`sticky` could not hold it.
|
|
76
|
+
|
|
77
|
+
- **`highlights` and `bookmarks` on `ChatExperience`, `highlights` on
|
|
78
|
+
`ChatTurnRow`, `marking` on `TextHighlighter`.** `highlights={false}` draws
|
|
79
|
+
answers as prose — no marker layer, nothing over the text in the tab order,
|
|
80
|
+
no highlight menu — and takes the saved highlights and the selection-mode
|
|
81
|
+
pair with it. `bookmarks={false}` keeps marking and drops the keeping. Both
|
|
82
|
+
are decided in code rather than offered in the interface, which is also how
|
|
83
|
+
`composer`, `pane`, `surface`, `headerActions` and `composerMenu` work.
|
|
84
|
+
|
|
85
|
+
### Fixed
|
|
86
|
+
|
|
87
|
+
- **A responding bubble drew a stop with nothing behind it** when the host
|
|
88
|
+
had not passed `onStop`. It is drawn only with somewhere to report to.
|
|
89
|
+
|
|
11
90
|
## 0.57.0 — 2026-09-22
|
|
12
91
|
|
|
13
92
|
A pane the host draws itself. `ChatExperience` placed its artifact pane beside
|
package/README.md
CHANGED
|
@@ -216,6 +216,7 @@ input that morphs into its own bubble rather than a record of what was typed.
|
|
|
216
216
|
| `onDraft` | `(id, value) => void` | | |
|
|
217
217
|
| `onSubmit` | `(id, value) => void` | | |
|
|
218
218
|
| `onStop` | `() => void` | | |
|
|
219
|
+
| `busy` | `boolean` | | An answer is arriving elsewhere: the composer offers a stop, not a send |
|
|
219
220
|
| `onEdit` | `(id) => void` | | |
|
|
220
221
|
| `onCancelEdit` | `(id) => void` | | |
|
|
221
222
|
| `onCopy` | `(value) => void` | writes to the clipboard | |
|
|
@@ -250,6 +251,53 @@ Every callback is optional; a row with none of them renders and can be marked.
|
|
|
250
251
|
The row carries `id="turn-<id>"` so a host can scroll to one, and `aria-busy`
|
|
251
252
|
while its answer is arriving.
|
|
252
253
|
|
|
254
|
+
### The composer at the bottom
|
|
255
|
+
|
|
256
|
+
The kit's argument is that the input is the message: it stands at the end of
|
|
257
|
+
the conversation and becomes the bubble where you typed it. Some products want
|
|
258
|
+
the shape every other chat has instead — the box at the bottom, the
|
|
259
|
+
conversation stacking above it. That is one prop, not a second kit:
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
<ChatExperience onSend={send} composer="docked" />
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
What changes, and what does not:
|
|
266
|
+
|
|
267
|
+
- **The box stays at the bottom.** `Conversation` pins its last child there —
|
|
268
|
+
pushed down by an auto margin while the conversation is shorter than the
|
|
269
|
+
view, held by `position: sticky` once it is longer. Both put its bottom on
|
|
270
|
+
the same edge, so nothing moves when the conversation crosses from one to
|
|
271
|
+
the other.
|
|
272
|
+
- **It still becomes the bubble.** The live input *is* the last turn, as it
|
|
273
|
+
always was, so the morph is the one the kit already has. What is new is the
|
|
274
|
+
travel: a fresh composer takes the last place, the sent one is no longer
|
|
275
|
+
last and no longer sticky, and its `layout` animation carries it up into the
|
|
276
|
+
conversation where it now belongs.
|
|
277
|
+
- **The next question can be typed while this one is answered.**
|
|
278
|
+
`useChatTurns` opens the next input at send rather than at settle
|
|
279
|
+
(`nextTurn: "at-send"`), the composer is `busy` while the answer arrives —
|
|
280
|
+
Enter does nothing and the send glyph is a stop — and a send while an answer
|
|
281
|
+
is in flight is refused rather than started on top of it. Queueing it is a
|
|
282
|
+
separate thing.
|
|
283
|
+
- **A sent message still goes to the top.** The same anchor the inline
|
|
284
|
+
composer uses: your question is brought to the top of the view and held
|
|
285
|
+
there while its answer is written underneath. The composer does not move
|
|
286
|
+
with it — it is `sticky`, so the room the anchor scrolls into passes behind
|
|
287
|
+
it. The room itself goes *above* the dock rather than below: `sticky` only
|
|
288
|
+
ever pulls an element up, so room underneath would leave the composer
|
|
289
|
+
stranded in the middle of the view.
|
|
290
|
+
- **The keyboard is allowed for.** On a phone the software keyboard comes up
|
|
291
|
+
over the bottom edge; the workspace gives up what `visualViewport` says is
|
|
292
|
+
covered, so the composer rides on the keyboard's top edge.
|
|
293
|
+
- Everything else is the same: the parts, the pane, the highlighter, editing
|
|
294
|
+
a sent message in place, `labels`, `surface="panes"`.
|
|
295
|
+
|
|
296
|
+
With a `chat` of your own, give its hook `nextTurn: "at-send"`. Assembling the
|
|
297
|
+
rows by hand, the same shape is `<Conversation dock>` with the live row last,
|
|
298
|
+
`busy={isStreaming}` on it, and `onStop` on it rather than on the bubble being
|
|
299
|
+
answered.
|
|
300
|
+
|
|
253
301
|
### Two rules everything follows
|
|
254
302
|
|
|
255
303
|
**Surfaces nest in three steps.** A **ground** is what a group of things sits
|
|
@@ -432,6 +480,31 @@ component that owns it.
|
|
|
432
480
|
steps that follow from one another. Sending both for one stretch of thinking
|
|
433
481
|
says it twice.
|
|
434
482
|
|
|
483
|
+
#### Where a part sits in the prose
|
|
484
|
+
|
|
485
|
+
The answer is drawn in the order the stream sent it. A part remembers how much
|
|
486
|
+
prose had arrived when it did — `at`, in characters of `ai` — and is drawn at
|
|
487
|
+
that point, so a sentence that introduces a card comes before the card:
|
|
488
|
+
|
|
489
|
+
```tsx
|
|
490
|
+
yield "I suggest this change:"; // prose
|
|
491
|
+
yield { kind: "custom", id: "change", type: "plan-diff", data }; // at: 22
|
|
492
|
+
yield " Tell me if it looks right."; // prose, after the card
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
`useChatTurns` stamps `at` on a part's **first** appearance and nothing moves it
|
|
496
|
+
afterwards: an update to a part is not a new part, and a card a host adds with
|
|
497
|
+
`updatePart` after the answer lands at the end. Give `at` yourself to place a
|
|
498
|
+
part — `at: 0` puts it before all the prose. A part with no `at` sits before the
|
|
499
|
+
prose, which is where every part sat before this existed, so turns built by
|
|
500
|
+
hand look as they always have.
|
|
501
|
+
|
|
502
|
+
The prose is still one string: `ai` is what Copy copies, what a screen reader
|
|
503
|
+
hears and what a version keeps. Only the drawing is cut, at the points the
|
|
504
|
+
parts arrived — each run is its own block of markdown, and a highlight cannot
|
|
505
|
+
cross a card. The row of actions goes after whatever the answer ends with, so an
|
|
506
|
+
answer made only of parts has one too, without a Copy of nothing.
|
|
507
|
+
|
|
435
508
|
#### Your own cards: `custom`
|
|
436
509
|
|
|
437
510
|
Every other kind is a component in this package. `custom` is the host's: `type`
|
|
@@ -951,6 +1024,7 @@ instant the reader scrolls away, with a button offering the way back.
|
|
|
951
1024
|
| `scrollButton` | `boolean` | `true` | The way back |
|
|
952
1025
|
| `scrollButtonLabel` | `string` | `"Jump to the latest"` | |
|
|
953
1026
|
| `follow` | `boolean` | `true` | `false` makes it a plain scroll container |
|
|
1027
|
+
| `dock` | `boolean` | `false` | The last child is pinned to the bottom edge — see [The composer at the bottom](#the-composer-at-the-bottom) |
|
|
954
1028
|
| `className` | `string` | | Goes on the root, which is the box you lay out |
|
|
955
1029
|
| `viewportClassName` | `string` | | Goes on the element that scrolls — padding belongs here |
|
|
956
1030
|
|
|
@@ -1436,17 +1510,46 @@ for that one instance.
|
|
|
1436
1510
|
|
|
1437
1511
|
### Turning off what you do not use
|
|
1438
1512
|
|
|
1439
|
-
|
|
1440
|
-
|
|
1513
|
+
Everything here is decided **in code**, not offered in the interface. A
|
|
1514
|
+
product either marks passages or it does not, keeps a theme toggle or does
|
|
1515
|
+
not; a control for choosing is a question nobody asked.
|
|
1441
1516
|
|
|
1442
1517
|
```tsx
|
|
1443
1518
|
<ChatExperience
|
|
1444
1519
|
onSend={send}
|
|
1520
|
+
composer="docked" // or "inline", the default
|
|
1521
|
+
highlights={false} // no marker layer, no highlight menu, no saved ones
|
|
1522
|
+
bookmarks={false} // marking stays, keeping goes
|
|
1445
1523
|
headerActions={false} // or ["theme"], or ["share"]
|
|
1446
1524
|
composerMenu={false} // or your own: [{ id, label, icon?, onSelect }]
|
|
1525
|
+
pane="none" // draw the artifact pane yourself
|
|
1526
|
+
surface="panes" // the conversation as a card of its own
|
|
1527
|
+
fill="container" // as tall as its parent, not the window
|
|
1447
1528
|
/>
|
|
1448
1529
|
```
|
|
1449
1530
|
|
|
1531
|
+
**Embedded, use `fill="container"`.** By default the chat is as tall as the
|
|
1532
|
+
window, which is what a page that is nothing but the chat wants. Anywhere
|
|
1533
|
+
smaller — a card in a shell, a sidebar, a split — it has to take its parent's
|
|
1534
|
+
height instead, or it hangs past the bottom of it: measured in a card inset 12px
|
|
1535
|
+
top and bottom, the default overran it by 24px and a docked composer lost half
|
|
1536
|
+
of itself to the card's clip. The parent has to have a height to give. The
|
|
1537
|
+
software keyboard is then the host's to handle, because the chat no longer
|
|
1538
|
+
knows where the window's edge is.
|
|
1539
|
+
|
|
1540
|
+
| Prop | Off means |
|
|
1541
|
+
| --- | --- |
|
|
1542
|
+
| `highlights={false}` | Answers are prose: no marker layer, nothing over the text in the tab order, no highlight menu — and no saved highlights or selection-mode pair, since both are about marking |
|
|
1543
|
+
| `bookmarks={false}` | A passage can still be marked and replied to; nothing is kept. Use `onHighlight` to keep them yourself |
|
|
1544
|
+
| `onThreadReply` omitted | No threads. A thread is opened from a highlight, so `highlights={false}` takes them too |
|
|
1545
|
+
| `headerActions={false}` | No theme toggle, no Share. Your own `actions` are unaffected |
|
|
1546
|
+
| `composerMenu={false}` | No "+" in the composer |
|
|
1547
|
+
| `selectionToggle` omitted | No marker/precise pair in the header (the default) |
|
|
1548
|
+
| `cursor` omitted | No pointer-following cursor (the default) |
|
|
1549
|
+
|
|
1550
|
+
Assembling the rows by hand, the same switch is `highlights` on
|
|
1551
|
+
`<ChatTurnRow>`, which is `marking` on `<TextHighlighter>`.
|
|
1552
|
+
|
|
1450
1553
|
The saved highlights button is not one of the header's actions — it appears
|
|
1451
1554
|
only once there is a highlight, and it is the only way back to them. An entry in
|
|
1452
1555
|
your own menu with id `"attach"` and no `onSelect` opens the file picker.
|
|
@@ -150,6 +150,40 @@ export interface ChatExperienceProps {
|
|
|
150
150
|
* `ChatLayout`.
|
|
151
151
|
*/
|
|
152
152
|
surface?: "flush" | "panes";
|
|
153
|
+
/**
|
|
154
|
+
* Where the composer lives.
|
|
155
|
+
*
|
|
156
|
+
* `"inline"` (the default): the input is the message. It stands at the end
|
|
157
|
+
* of the conversation, and what you type becomes the bubble where you typed
|
|
158
|
+
* it — the argument this kit makes.
|
|
159
|
+
*
|
|
160
|
+
* `"docked"`: the input stays at the bottom of the view, the way most chats
|
|
161
|
+
* keep it, and the conversation stacks above it. Sent, it still becomes the
|
|
162
|
+
* bubble — the same element, travelling into the conversation — and a fresh
|
|
163
|
+
* one takes its place at the bottom straight away, so the next question can
|
|
164
|
+
* be typed while this one is being answered. Everything else is the same:
|
|
165
|
+
* the parts, the pane, the highlighter, editing in place.
|
|
166
|
+
*
|
|
167
|
+
* With a `chat` of your own, give its `useChatTurns` `nextTurn: "at-send"`.
|
|
168
|
+
*/
|
|
169
|
+
composer?: "inline" | "docked";
|
|
170
|
+
/**
|
|
171
|
+
* What the chat is as tall as.
|
|
172
|
+
*
|
|
173
|
+
* `"window"` (the default): the whole window, which is what a page that is
|
|
174
|
+
* nothing but the chat wants, and why it needs no height from its host.
|
|
175
|
+
*
|
|
176
|
+
* `"container"`: whatever its parent gives it. For a chat embedded in a
|
|
177
|
+
* card, a sidebar, a split — anywhere smaller than the window, which is
|
|
178
|
+
* nearly every embed. The parent has to have a height to give; the chat
|
|
179
|
+
* fills it and scrolls inside it. Measured in a host whose card was inset
|
|
180
|
+
* 12px top and bottom, `"window"` hung 24px past the card and a docked
|
|
181
|
+
* composer lost half of itself to the card's clip.
|
|
182
|
+
*
|
|
183
|
+
* The software keyboard is the host's to handle here: the chat no longer
|
|
184
|
+
* knows where the window's bottom edge is relative to itself.
|
|
185
|
+
*/
|
|
186
|
+
fill?: "window" | "container";
|
|
153
187
|
/** The theme, if the host keeps it. Left off, this manages its own and puts
|
|
154
188
|
a toggle in the header; `data-theme` on the root element either way, and
|
|
155
189
|
unset until somebody chooses, so the kit follows the system preference —
|
|
@@ -159,8 +193,32 @@ export interface ChatExperienceProps {
|
|
|
159
193
|
/** The pointer-following cursor, and the rule that hides the real one. Only
|
|
160
194
|
ever where there is a pointer to replace. */
|
|
161
195
|
cursor?: boolean;
|
|
162
|
-
/** The freeform-marker / precise-selection pair in the header.
|
|
196
|
+
/** The freeform-marker / precise-selection pair in the header. Drawn only
|
|
197
|
+
where there is marking to choose a mode for. */
|
|
163
198
|
selectionToggle?: boolean;
|
|
199
|
+
/**
|
|
200
|
+
* Whether an answer can be marked at all.
|
|
201
|
+
*
|
|
202
|
+
* On by default: a marker over a passage is how a reader asks about one
|
|
203
|
+
* sentence rather than the whole answer. `false` draws answers as prose —
|
|
204
|
+
* no marker layer, no highlight menu, nothing in the tab order over the
|
|
205
|
+
* text — and takes the saved highlights and the selection-mode pair with
|
|
206
|
+
* it, because both are about marking. A thread is opened from a highlight,
|
|
207
|
+
* so `onThreadReply` has nothing to open it from either.
|
|
208
|
+
*
|
|
209
|
+
* Set in code, not offered in the interface: a product either works this
|
|
210
|
+
* way or it does not.
|
|
211
|
+
*/
|
|
212
|
+
highlights?: boolean;
|
|
213
|
+
/**
|
|
214
|
+
* Whether marked passages are kept.
|
|
215
|
+
*
|
|
216
|
+
* On by default, and only ever visible once there is one: the header grows
|
|
217
|
+
* a button with the count, and it opens the sheet that lists them.
|
|
218
|
+
* `false` keeps marking and threads and drops the keeping — for a host that
|
|
219
|
+
* would rather store them itself, through `onHighlight`.
|
|
220
|
+
*/
|
|
221
|
+
bookmarks?: boolean;
|
|
164
222
|
/** How far below the top edge a sent message comes to rest. Sets the
|
|
165
223
|
conversation's own top padding too — the two have to agree, so one number
|
|
166
224
|
writes both. */
|
|
@@ -177,4 +235,4 @@ export interface ChatExperienceProps {
|
|
|
177
235
|
onDecideApproval?: (write: PartWriter, turnId: string, partId: string, decision: Decision) => void;
|
|
178
236
|
className?: string;
|
|
179
237
|
}
|
|
180
|
-
export declare function ChatExperience({ onSend, chat: hostChat, renderPart, labels, headerActions: builtInActions, composerMenu, onTranscribe, onThreadReply, title: titleProp, backHref, backLabel, actions, placeholder, empty, contextTotal, contextBase, artifact, openArtifactId: openArtifactProp, onOpenArtifactChange, pane: paneMode, surface, theme: themeProp, onThemeChange, cursor, selectionToggle, anchorOffset, endOffset, animationConfig, foldMotion, feedDelay, onAnswerQuestion, onEditQuestion, onDecideApproval, className, }: ChatExperienceProps): import("react").JSX.Element;
|
|
238
|
+
export declare function ChatExperience({ onSend, chat: hostChat, renderPart, labels, headerActions: builtInActions, composerMenu, onTranscribe, onThreadReply, title: titleProp, backHref, backLabel, actions, placeholder, empty, contextTotal, contextBase, artifact, openArtifactId: openArtifactProp, onOpenArtifactChange, pane: paneMode, surface, composer, fill: fillMode, theme: themeProp, onThemeChange, cursor, selectionToggle, highlights: marking, bookmarks, anchorOffset, endOffset, animationConfig, foldMotion, feedDelay, onAnswerQuestion, onEditQuestion, onDecideApproval, className, }: ChatExperienceProps): import("react").JSX.Element;
|