inline-chat-kit 0.56.0 → 0.57.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 +29 -0
- package/README.md +77 -0
- package/dist/Artifact/ChatLayout.d.ts +14 -1
- package/dist/ChatExperience/ChatExperience.d.ts +28 -5
- package/dist/{ChatExperience-DCta8bv3.js → ChatExperience-Bawy_cnn.js} +262 -238
- package/dist/ChatExperience-Bawy_cnn.js.map +1 -0
- package/dist/ChatTurnRow/ChatTurnRow.d.ts +9 -5
- package/dist/demo.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/inline-chat-kit.css +1 -1
- package/dist/inline-chat-kit.js +1 -1
- package/dist/turnParts/turnParts.d.ts +12 -0
- package/package.json +1 -1
- package/dist/ChatExperience-DCta8bv3.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,35 @@ 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.57.0 — 2026-09-22
|
|
12
|
+
|
|
13
|
+
A pane the host draws itself. `ChatExperience` placed its artifact pane beside
|
|
14
|
+
the conversation and held which one was open, which is right until the host has
|
|
15
|
+
a layout of its own. Nothing changes for a host that passes none of this.
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **`openArtifactId` and `onOpenArtifactChange` on `ChatExperience`.** Which
|
|
20
|
+
artifact is open, held by the host. Left out, the component keeps its own;
|
|
21
|
+
`null` is a held "none open". The change callback fires either way.
|
|
22
|
+
- **`pane="inline" | "none"` on `ChatExperience`.** `"none"` draws no
|
|
23
|
+
`ArtifactPane`, reserves no width for one and never calls `artifact`; a
|
|
24
|
+
pressed card only reports its id, and still shows it is open from
|
|
25
|
+
`openArtifactId`.
|
|
26
|
+
- **`openArtifact(id)` and `closeArtifact()` in `renderPart`'s context**, next
|
|
27
|
+
to `turnId` — so a host's own card can open the pane. `CustomPartContext` is
|
|
28
|
+
exported. `ChatTurnRow` takes `onArtifactChange` for the same when assembled
|
|
29
|
+
by hand.
|
|
30
|
+
- **`ArtifactPane` outside `ChatLayout`**, documented and tested: a region with
|
|
31
|
+
focus on its title when it mounts, no trap and no Escape unless `modal`.
|
|
32
|
+
- **`surface="flush" | "panes"` on `ChatExperience` and `ChatLayout`.**
|
|
33
|
+
`"panes"` makes the conversation a card of its own, so the pane beside it —
|
|
34
|
+
the kit's or the host's — is a second surface rather than a strip cut off the
|
|
35
|
+
same one. Both are drawn from the same tokens, and `--ick-chat-pane-inset` is
|
|
36
|
+
both the ring of space around them and the gap between them. Below the
|
|
37
|
+
layout's breakpoint the corners and the inset go, where the pane is a sheet.
|
|
38
|
+
`"flush"` is the default and is what the kit drew before.
|
|
39
|
+
|
|
11
40
|
## 0.56.0 — 2026-09-22
|
|
12
41
|
|
|
13
42
|
Four things that kept the kit out of a real host app: an answer could only
|
package/README.md
CHANGED
|
@@ -461,6 +461,10 @@ and the kit does not guess its shape.
|
|
|
461
461
|
`ChatExperience` calls `useChatTurns` itself, so a host using it passes its own
|
|
462
462
|
instead — `chat={useChatTurns({ onSend })}` — to hold `updatePart`.
|
|
463
463
|
|
|
464
|
+
The second argument to `renderPart` is `{ turnId, openArtifact, closeArtifact }`
|
|
465
|
+
(`CustomPartContext`), so a card can open the pane — see
|
|
466
|
+
[Drawing the pane yourself](#drawing-the-pane-yourself).
|
|
467
|
+
|
|
464
468
|
#### Citing a source from the prose
|
|
465
469
|
|
|
466
470
|
`[^1]` in the answer is a **citation marker**, and the number is a position in
|
|
@@ -1028,6 +1032,7 @@ between products, and the only part.
|
|
|
1028
1032
|
| `onOpen` | `(id: string) => void` | Without one the card is a record, not a control |
|
|
1029
1033
|
| `<ArtifactPane>` `modal` | `boolean` | See below |
|
|
1030
1034
|
| `<ChatLayout>` `pane` | `({ narrow }) => ReactNode` | |
|
|
1035
|
+
| `<ChatLayout>` `surface` | `"flush" \| "panes"` | One surface, or two. See below |
|
|
1031
1036
|
|
|
1032
1037
|
**`modal` is the one prop that changes behaviour, and it is not about
|
|
1033
1038
|
position.** Covering the conversation changes what the pane *is*: focus has to
|
|
@@ -1041,6 +1046,78 @@ That is the part worth having in a library rather than the box. On open, focus
|
|
|
1041
1046
|
moves to the pane's heading — not into its first control, which would skip what
|
|
1042
1047
|
the thing is — and it is **not** trapped unless the pane is covering the chat.
|
|
1043
1048
|
|
|
1049
|
+
#### Two panes, not one page split in half
|
|
1050
|
+
|
|
1051
|
+
By default the conversation fills the layout and the pane is the only card on
|
|
1052
|
+
it — which is what a chat that owns the whole window wants. `surface="panes"`
|
|
1053
|
+
makes the conversation a card of its own instead:
|
|
1054
|
+
|
|
1055
|
+
```tsx
|
|
1056
|
+
<ChatExperience onSend={send} surface="panes" artifact={artifact} />
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
Both surfaces are drawn from the same tokens — `--ick-chat-pane-surface` is
|
|
1060
|
+
`--ick-artifact-pane-surface`, and the radius follows — because two panes side
|
|
1061
|
+
by side have to be the same *kind* of thing, or the chat reads as the
|
|
1062
|
+
background and the pane as a dialog over it. One number,
|
|
1063
|
+
`--ick-chat-pane-inset`, is the ring of space around both and the gap between
|
|
1064
|
+
them, so the frame is even the whole way round. No divider: the gap is what
|
|
1065
|
+
says there are two of them.
|
|
1066
|
+
|
|
1067
|
+
Below `<ChatLayout>`'s breakpoint the corners and the inset go: the pane is a
|
|
1068
|
+
sheet over the conversation there, and a card inside a card with a sheet over
|
|
1069
|
+
both is three surfaces for one screen.
|
|
1070
|
+
|
|
1071
|
+
Inside the card, `--ick-page` is the card — so the header's tint and the fades
|
|
1072
|
+
at both ends end in the colour they are standing on rather than in the ground
|
|
1073
|
+
outside it.
|
|
1074
|
+
|
|
1075
|
+
#### Drawing the pane yourself
|
|
1076
|
+
|
|
1077
|
+
`ChatExperience` places the pane beside the conversation. A host with a layout
|
|
1078
|
+
of its own — its own column, a drawer, a route — holds which artifact is open
|
|
1079
|
+
and tells the kit to keep out of the way:
|
|
1080
|
+
|
|
1081
|
+
```tsx
|
|
1082
|
+
const [openId, setOpenId] = useState<string | null>(null);
|
|
1083
|
+
const open = openId ? findArtifact(openId) : null;
|
|
1084
|
+
|
|
1085
|
+
<div className="workspace">
|
|
1086
|
+
<ChatExperience
|
|
1087
|
+
chat={chat}
|
|
1088
|
+
pane="none" // no pane here, and no room made for one
|
|
1089
|
+
openArtifactId={openId} // the cards still show which one is open
|
|
1090
|
+
onOpenArtifactChange={setOpenId} // a card pressed, or a custom card's openArtifact
|
|
1091
|
+
renderPart={renderPart}
|
|
1092
|
+
/>
|
|
1093
|
+
{open && (
|
|
1094
|
+
<aside className="my-column">
|
|
1095
|
+
<ArtifactPane key={openId} title={open.title} onClose={() => setOpenId(null)}>
|
|
1096
|
+
{open.body}
|
|
1097
|
+
</ArtifactPane>
|
|
1098
|
+
</aside>
|
|
1099
|
+
)}
|
|
1100
|
+
</div>
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
- **`openArtifactId` / `onOpenArtifactChange`** hold the state outside. Left
|
|
1104
|
+
out, `ChatExperience` keeps its own, as before. `null` is a held "nothing
|
|
1105
|
+
open"; only `undefined` means "not held". `onOpenArtifactChange` is called
|
|
1106
|
+
either way, so a host can listen without holding.
|
|
1107
|
+
- **`pane="none"`** draws no `ArtifactPane`, makes no room for one and never
|
|
1108
|
+
calls `artifact`. Pressing a card reports the id (pressing the open one again
|
|
1109
|
+
reports `null`).
|
|
1110
|
+
- **A custom card opens one too.** `renderPart`'s second argument carries
|
|
1111
|
+
`openArtifact(id)` and `closeArtifact()`, next to `turnId`: a caregiver in
|
|
1112
|
+
your card opens her profile the way an `ArtifactCard` opens a plan.
|
|
1113
|
+
- **`surface="panes"` goes with it.** The conversation becomes a card, your
|
|
1114
|
+
pane is the second one, and the two match without your having to copy the
|
|
1115
|
+
kit's radius and shadow.
|
|
1116
|
+
- **`<ArtifactPane>` stands on its own.** Outside `ChatLayout` leave `modal`
|
|
1117
|
+
off: it is a region, focus moves to its title when it mounts, and it neither
|
|
1118
|
+
traps focus nor takes Escape. Key it by the artifact's id, so opening a
|
|
1119
|
+
different one is a new pane — and focus moves to the new title.
|
|
1120
|
+
|
|
1044
1121
|
### `<SystemMessage>`
|
|
1045
1122
|
|
|
1046
1123
|
The conversation saying something about itself — not the reader, not the agent.
|
|
@@ -28,6 +28,19 @@ export interface ChatLayoutProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
28
28
|
* it out and the sheet has neither, which is a sheet a thumb cannot dismiss.
|
|
29
29
|
*/
|
|
30
30
|
onDismiss?: () => void;
|
|
31
|
+
/**
|
|
32
|
+
* Whether the conversation is a surface of its own.
|
|
33
|
+
*
|
|
34
|
+
* `"flush"` (the default): the conversation fills the layout and the pane is
|
|
35
|
+
* the only card — which is what a chat that owns the whole window wants.
|
|
36
|
+
*
|
|
37
|
+
* `"panes"`: two cards side by side on the page, with the same ring of space
|
|
38
|
+
* around both and the same gap between them. A divider would have said the
|
|
39
|
+
* same thing more cheaply and less truthfully: these are two surfaces, not
|
|
40
|
+
* one surface with a line through it. The pane the host draws itself goes
|
|
41
|
+
* beside a `"panes"` conversation and looks like it belongs there.
|
|
42
|
+
*/
|
|
43
|
+
surface?: "flush" | "panes";
|
|
31
44
|
}
|
|
32
45
|
/**
|
|
33
46
|
* Where the pane goes, decided once.
|
|
@@ -41,4 +54,4 @@ export interface ChatLayoutProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
41
54
|
* What is left open is the part that actually differs — what is *in* the pane.
|
|
42
55
|
* See `ArtifactPane`.
|
|
43
56
|
*/
|
|
44
|
-
export declare function ChatLayout({ children, pane, onDismiss, className, ...rest }: ChatLayoutProps): import("react").JSX.Element;
|
|
57
|
+
export declare function ChatLayout({ children, pane, onDismiss, surface, className, ...rest }: ChatLayoutProps): import("react").JSX.Element;
|
|
@@ -5,7 +5,7 @@ import { UseChatTurnsOptions, UseChatTurnsResult } from '../useChatTurns/useChat
|
|
|
5
5
|
import { FoldMotion } from '../QuestionGroup/QuestionGroup';
|
|
6
6
|
import { InlineAnimConfig } from '../ChatInput/ChatInput';
|
|
7
7
|
import { TranscribeHandler } from '../voice/useVoiceInput';
|
|
8
|
-
import { CustomPart, TurnPartUpdate } from '../turnParts/turnParts';
|
|
8
|
+
import { CustomPart, CustomPartContext, TurnPartUpdate } from '../turnParts/turnParts';
|
|
9
9
|
import { ComposerMenuItem } from '../ChatInput/AddCardsOverlay';
|
|
10
10
|
import { ChatLabels } from '../labels/labels';
|
|
11
11
|
import { Answer } from '../QuestionCard/types';
|
|
@@ -84,9 +84,7 @@ export interface ChatExperienceProps {
|
|
|
84
84
|
* it stable — outside the component or in `useCallback` — or every row
|
|
85
85
|
* re-renders on every frame of an answer arriving.
|
|
86
86
|
*/
|
|
87
|
-
renderPart?: (part: CustomPart, context:
|
|
88
|
-
turnId: string;
|
|
89
|
-
}) => ReactNode;
|
|
87
|
+
renderPart?: (part: CustomPart, context: CustomPartContext) => ReactNode;
|
|
90
88
|
/**
|
|
91
89
|
* Every word the chat says, grouped by the component that says it. Partial:
|
|
92
90
|
* anything left out stays English. Reaches every piece through context, so
|
|
@@ -127,6 +125,31 @@ export interface ChatExperienceProps {
|
|
|
127
125
|
contextBase?: number;
|
|
128
126
|
/** The pane beside the conversation, asked for the artifact that is open. */
|
|
129
127
|
artifact?: (openId: string) => ChatExperienceArtifact | null;
|
|
128
|
+
/**
|
|
129
|
+
* Which artifact is open, held by the host. Left out (`undefined`), this
|
|
130
|
+
* component keeps it. `null` is "none open" — held, just empty.
|
|
131
|
+
*/
|
|
132
|
+
openArtifactId?: string | null;
|
|
133
|
+
/** Somebody opened or closed one — a card pressed, the pane's X, a custom
|
|
134
|
+
card calling `openArtifact`. Called whether or not the state is held. */
|
|
135
|
+
onOpenArtifactChange?: (id: string | null) => void;
|
|
136
|
+
/**
|
|
137
|
+
* Who draws the pane. `"inline"` (the default): this component, beside the
|
|
138
|
+
* conversation, from `artifact`. `"none"`: nobody here — no pane, no room
|
|
139
|
+
* made for one. The cards still open and still show which one is open;
|
|
140
|
+
* the host draws the pane wherever its own layout wants it, usually with
|
|
141
|
+
* `openArtifactId` and `<ArtifactPane>`.
|
|
142
|
+
*/
|
|
143
|
+
pane?: "inline" | "none";
|
|
144
|
+
/**
|
|
145
|
+
* Whether the conversation is a card of its own.
|
|
146
|
+
*
|
|
147
|
+
* `"flush"` (the default) fills the window, as before. `"panes"` makes it a
|
|
148
|
+
* surface on the page, so the pane beside it — the kit's or the host's own —
|
|
149
|
+
* is a second surface rather than a strip cut off the same one. See
|
|
150
|
+
* `ChatLayout`.
|
|
151
|
+
*/
|
|
152
|
+
surface?: "flush" | "panes";
|
|
130
153
|
/** The theme, if the host keeps it. Left off, this manages its own and puts
|
|
131
154
|
a toggle in the header; `data-theme` on the root element either way, and
|
|
132
155
|
unset until somebody chooses, so the kit follows the system preference —
|
|
@@ -154,4 +177,4 @@ export interface ChatExperienceProps {
|
|
|
154
177
|
onDecideApproval?: (write: PartWriter, turnId: string, partId: string, decision: Decision) => void;
|
|
155
178
|
className?: string;
|
|
156
179
|
}
|
|
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;
|
|
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;
|