@neuronection/assistant-ui 0.52.0 → 0.53.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 +91 -0
- package/README.md +4 -1
- package/dist/chat-branch-tree.d.ts +15 -2
- package/dist/chat-composer.d.ts +43 -3
- package/dist/chat-composer.js +1 -1
- package/dist/chat-core.d.ts +54 -4
- package/dist/chat-launcher.js +1 -1
- package/dist/chat-markdown.d.ts +8 -1
- package/dist/chat-markdown.js +1 -1
- package/dist/chat-message.d.ts +16 -1
- package/dist/chat-message.js +1 -1
- package/dist/chat-panel.js +1 -1
- package/dist/chat-pending.d.ts +25 -0
- package/dist/chat-pending.js +3 -0
- package/dist/chat-pending.js.map +1 -0
- package/dist/chat-reasoning.d.ts +10 -2
- package/dist/chat-reasoning.js +1 -1
- package/dist/chat-session-list.d.ts +7 -0
- package/dist/chat-session-list.js +1 -1
- package/dist/chat-suggestion-card.d.ts +19 -0
- package/dist/chat-suggestion-card.js +3 -0
- package/dist/chat-suggestion-card.js.map +1 -0
- package/dist/chat-tool-card.js +1 -1
- package/dist/chat-transcript.d.ts +81 -8
- package/dist/chat-transcript.js +1 -1
- package/dist/chat-turn-status.js +1 -1
- package/dist/chat-welcome.d.ts +23 -0
- package/dist/chat-welcome.js +3 -0
- package/dist/chat-welcome.js.map +1 -0
- package/dist/{chunk-PC3CE4W2.js → chunk-22MIIWC7.js} +45 -7
- package/dist/chunk-22MIIWC7.js.map +1 -0
- package/dist/{chunk-GDGKARRB.js → chunk-5C2OLUDR.js} +11 -2
- package/dist/chunk-5C2OLUDR.js.map +1 -0
- package/dist/{chunk-5BJ4VULP.js → chunk-EQPXM2R4.js} +23 -10
- package/dist/chunk-EQPXM2R4.js.map +1 -0
- package/dist/chunk-F4BTJQLK.js +43 -0
- package/dist/chunk-F4BTJQLK.js.map +1 -0
- package/dist/{chunk-TQDTFPM4.js → chunk-GIQZNEG5.js} +3 -3
- package/dist/chunk-GIQZNEG5.js.map +1 -0
- package/dist/{chunk-E3NZM4U7.js → chunk-GO4ILLS6.js} +17 -4
- package/dist/chunk-GO4ILLS6.js.map +1 -0
- package/dist/chunk-HXU6P5FD.js +479 -0
- package/dist/chunk-HXU6P5FD.js.map +1 -0
- package/dist/{chunk-MFM4W6ZO.js → chunk-I4R5BRC7.js} +3 -3
- package/dist/{chunk-MFM4W6ZO.js.map → chunk-I4R5BRC7.js.map} +1 -1
- package/dist/{chunk-5U45TQJE.js → chunk-I5H4KYEZ.js} +3 -3
- package/dist/{chunk-5U45TQJE.js.map → chunk-I5H4KYEZ.js.map} +1 -1
- package/dist/{chunk-S63SYV6O.js → chunk-INXQJM2K.js} +27 -6
- package/dist/chunk-INXQJM2K.js.map +1 -0
- package/dist/{chunk-HQ3X5SVR.js → chunk-KQLKITZL.js} +105 -16
- package/dist/chunk-KQLKITZL.js.map +1 -0
- package/dist/chunk-M4SYVPC4.js +3 -0
- package/dist/chunk-M4SYVPC4.js.map +1 -0
- package/dist/chunk-NOAKHVBJ.js +264 -0
- package/dist/chunk-NOAKHVBJ.js.map +1 -0
- package/dist/chunk-OOQO6VGO.js +33 -0
- package/dist/chunk-OOQO6VGO.js.map +1 -0
- package/dist/chunk-P3QUNCBR.js +366 -0
- package/dist/chunk-P3QUNCBR.js.map +1 -0
- package/dist/chunk-PABMR4RA.js +30 -0
- package/dist/chunk-PABMR4RA.js.map +1 -0
- package/dist/{chunk-SEZZVAGP.js → chunk-SR4IN564.js} +10 -3
- package/dist/chunk-SR4IN564.js.map +1 -0
- package/dist/index.d.ts +243 -36
- package/dist/index.js +40 -37
- package/dist/markdown-diff-view.js +1 -1
- package/dist/model-registry.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/theme-scope.d.ts +1 -1
- package/dist/tokens.d.ts +1 -1
- package/dist/tokens.js +1 -1
- package/dist/{types-LhE1KFBf.d.ts → types-CxieoN2u.d.ts} +1 -1
- package/dist/types-pivJdPC8.d.ts +14 -0
- package/package.json +13 -1
- package/dist/chunk-5BJ4VULP.js.map +0 -1
- package/dist/chunk-C5JZCCU7.js +0 -220
- package/dist/chunk-C5JZCCU7.js.map +0 -1
- package/dist/chunk-E3NZM4U7.js.map +0 -1
- package/dist/chunk-GDGKARRB.js.map +0 -1
- package/dist/chunk-HQ3X5SVR.js.map +0 -1
- package/dist/chunk-PC3CE4W2.js.map +0 -1
- package/dist/chunk-S63SYV6O.js.map +0 -1
- package/dist/chunk-SEZZVAGP.js.map +0 -1
- package/dist/chunk-TQDTFPM4.js.map +0 -1
- package/dist/chunk-XOODPYJ3.js +0 -173
- package/dist/chunk-XOODPYJ3.js.map +0 -1
- package/dist/chunk-YQQZMWHL.js +0 -201
- package/dist/chunk-YQQZMWHL.js.map +0 -1
- package/dist/tree-4Hv9stjF.d.ts +0 -54
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { searchScore } from './chunk-B2G66OSQ.js';
|
|
2
|
+
import { cn } from './chunk-RVVXVTH3.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { Square, ArrowUp } from 'lucide-react';
|
|
5
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
6
|
+
|
|
7
|
+
function isIMEComposition(event) {
|
|
8
|
+
return event.nativeEvent.isComposing || event.keyCode === 229;
|
|
9
|
+
}
|
|
10
|
+
function tokenAtCaret(value, caret, trigger) {
|
|
11
|
+
const pos = Math.min(caret, value.length);
|
|
12
|
+
let start = pos;
|
|
13
|
+
while (start > 0 && !/\s/.test(value[start - 1] ?? "")) {
|
|
14
|
+
start -= 1;
|
|
15
|
+
}
|
|
16
|
+
const text = value.slice(start, pos);
|
|
17
|
+
if (!text.startsWith(trigger)) {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
const query = text.slice(trigger.length);
|
|
21
|
+
if (query.includes(trigger)) {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
return { start, end: pos, query };
|
|
25
|
+
}
|
|
26
|
+
var ChatComposer = React.forwardRef(
|
|
27
|
+
function ChatComposer2({
|
|
28
|
+
value,
|
|
29
|
+
onValueChange,
|
|
30
|
+
onSubmit,
|
|
31
|
+
sending = false,
|
|
32
|
+
onStop,
|
|
33
|
+
disabled = false,
|
|
34
|
+
canSubmit,
|
|
35
|
+
commands,
|
|
36
|
+
history,
|
|
37
|
+
placeholder,
|
|
38
|
+
ariaLabel,
|
|
39
|
+
maxRows = 8,
|
|
40
|
+
toolbarStart,
|
|
41
|
+
toolbarEnd,
|
|
42
|
+
attachments,
|
|
43
|
+
suggestions,
|
|
44
|
+
onAttachFiles,
|
|
45
|
+
labels,
|
|
46
|
+
icons,
|
|
47
|
+
textareaRef,
|
|
48
|
+
className
|
|
49
|
+
}, ref) {
|
|
50
|
+
const internalTextareaRef = React.useRef(null);
|
|
51
|
+
const [dragging, setDragging] = React.useState(false);
|
|
52
|
+
const [multiline, setMultiline] = React.useState(false);
|
|
53
|
+
const multilineRef = React.useRef(false);
|
|
54
|
+
const dragDepth = React.useRef(0);
|
|
55
|
+
const prevSendingRef = React.useRef(sending);
|
|
56
|
+
const [morphTarget, setMorphTarget] = React.useState(null);
|
|
57
|
+
if (prevSendingRef.current !== sending) {
|
|
58
|
+
prevSendingRef.current = sending;
|
|
59
|
+
setMorphTarget(sending ? "stop" : "send");
|
|
60
|
+
}
|
|
61
|
+
const [caret, setCaret] = React.useState(0);
|
|
62
|
+
const [paletteDismissed, setPaletteDismissed] = React.useState(false);
|
|
63
|
+
const [activeIndex, setActiveIndex] = React.useState(0);
|
|
64
|
+
const [historyIndex, setHistoryIndex] = React.useState(null);
|
|
65
|
+
const paletteId = React.useId();
|
|
66
|
+
const setTextarea = (element) => {
|
|
67
|
+
internalTextareaRef.current = element;
|
|
68
|
+
if (typeof textareaRef === "function") {
|
|
69
|
+
textareaRef(element);
|
|
70
|
+
} else if (textareaRef && typeof textareaRef === "object") {
|
|
71
|
+
textareaRef.current = element;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const syncCaret = () => {
|
|
75
|
+
const element = internalTextareaRef.current;
|
|
76
|
+
if (element !== null) {
|
|
77
|
+
setCaret(element.selectionStart ?? 0);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
React.useLayoutEffect(() => {
|
|
81
|
+
const element = internalTextareaRef.current;
|
|
82
|
+
if (element === null) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const style = window.getComputedStyle(element);
|
|
86
|
+
const lineHeight = Number.parseFloat(style.lineHeight) || 22;
|
|
87
|
+
const verticalPadding = (Number.parseFloat(style.paddingTop) || 0) + (Number.parseFloat(style.paddingBottom) || 0);
|
|
88
|
+
const cap = Number.parseFloat(style.maxHeight) || maxRows * 22;
|
|
89
|
+
element.style.height = "auto";
|
|
90
|
+
const next = element.scrollHeight > 0 ? Math.min(Math.ceil(element.scrollHeight) + 1, cap) : 0;
|
|
91
|
+
element.style.height = next > 0 ? `${next}px` : "auto";
|
|
92
|
+
const overflowing = element.scrollHeight > element.clientHeight + 1;
|
|
93
|
+
element.style.overflowY = overflowing ? "auto" : "hidden";
|
|
94
|
+
if (!overflowing && element.scrollTop !== 0) {
|
|
95
|
+
element.scrollTop = 0;
|
|
96
|
+
}
|
|
97
|
+
const grew = element.scrollHeight > lineHeight + verticalPadding + 1;
|
|
98
|
+
multilineRef.current = value === "" ? false : multilineRef.current || grew;
|
|
99
|
+
setMultiline(multilineRef.current);
|
|
100
|
+
}, [value, maxRows]);
|
|
101
|
+
const trigger = commands?.trigger ?? "/";
|
|
102
|
+
const token = React.useMemo(
|
|
103
|
+
() => commands === void 0 ? null : tokenAtCaret(value, caret, trigger),
|
|
104
|
+
[commands, value, caret, trigger]
|
|
105
|
+
);
|
|
106
|
+
const paletteItems = React.useMemo(() => {
|
|
107
|
+
if (commands === void 0 || token === null) {
|
|
108
|
+
return [];
|
|
109
|
+
}
|
|
110
|
+
const max = commands.maxItems ?? 8;
|
|
111
|
+
return commands.items.map((item) => ({
|
|
112
|
+
item,
|
|
113
|
+
score: token.query === "" ? 0 : searchScore(token.query, item.label) ?? searchScore(token.query, item.id)
|
|
114
|
+
})).filter((entry) => entry.score !== null).sort((a, b) => b.score - a.score).slice(0, max).map((entry) => entry.item);
|
|
115
|
+
}, [commands, token]);
|
|
116
|
+
const paletteVisible = token !== null && paletteItems.length > 0 && !paletteDismissed && !disabled;
|
|
117
|
+
React.useEffect(() => {
|
|
118
|
+
setPaletteDismissed(false);
|
|
119
|
+
setActiveIndex(0);
|
|
120
|
+
}, [token?.start, token?.query]);
|
|
121
|
+
React.useEffect(() => {
|
|
122
|
+
if (value === "") {
|
|
123
|
+
setHistoryIndex(null);
|
|
124
|
+
}
|
|
125
|
+
}, [value]);
|
|
126
|
+
const selectCommand = (command) => {
|
|
127
|
+
if (token !== null) {
|
|
128
|
+
commands?.onSelect(command.id, { start: token.start, end: token.end, query: token.query });
|
|
129
|
+
}
|
|
130
|
+
setPaletteDismissed(true);
|
|
131
|
+
internalTextareaRef.current?.focus();
|
|
132
|
+
};
|
|
133
|
+
const submit = () => {
|
|
134
|
+
if (disabled || sending) {
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
onSubmit();
|
|
138
|
+
};
|
|
139
|
+
const onKeyDown = (event) => {
|
|
140
|
+
if (paletteVisible) {
|
|
141
|
+
if (event.key === "ArrowDown") {
|
|
142
|
+
event.preventDefault();
|
|
143
|
+
setActiveIndex((index) => (index + 1) % paletteItems.length);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
if (event.key === "ArrowUp") {
|
|
147
|
+
event.preventDefault();
|
|
148
|
+
setActiveIndex((index) => (index - 1 + paletteItems.length) % paletteItems.length);
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
if ((event.key === "Enter" || event.key === "Tab") && !isIMEComposition(event)) {
|
|
152
|
+
event.preventDefault();
|
|
153
|
+
selectCommand(paletteItems[activeIndex] ?? paletteItems[0]);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
if (event.key === "Escape") {
|
|
157
|
+
event.preventDefault();
|
|
158
|
+
setPaletteDismissed(true);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
} else if (event.key === "Escape" && sending && onStop !== void 0) {
|
|
162
|
+
event.preventDefault();
|
|
163
|
+
onStop();
|
|
164
|
+
return;
|
|
165
|
+
} else if ((event.key === "ArrowUp" || event.key === "ArrowDown") && history !== void 0 && history.length > 0 && (value === "" || historyIndex !== null)) {
|
|
166
|
+
event.preventDefault();
|
|
167
|
+
if (event.key === "ArrowUp") {
|
|
168
|
+
const next = historyIndex === null ? history.length - 1 : Math.max(0, historyIndex - 1);
|
|
169
|
+
setHistoryIndex(next);
|
|
170
|
+
onValueChange(history[next] ?? "");
|
|
171
|
+
setCaret((history[next] ?? "").length);
|
|
172
|
+
} else if (historyIndex !== null) {
|
|
173
|
+
const next = historyIndex + 1;
|
|
174
|
+
if (next >= history.length) {
|
|
175
|
+
setHistoryIndex(null);
|
|
176
|
+
onValueChange("");
|
|
177
|
+
setCaret(0);
|
|
178
|
+
} else {
|
|
179
|
+
setHistoryIndex(next);
|
|
180
|
+
onValueChange(history[next] ?? "");
|
|
181
|
+
setCaret((history[next] ?? "").length);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (event.key !== "Enter" || event.shiftKey) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (isIMEComposition(event)) {
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
event.preventDefault();
|
|
193
|
+
submit();
|
|
194
|
+
};
|
|
195
|
+
const emitFiles = (fileList) => {
|
|
196
|
+
const files = fileList ? Array.from(fileList) : [];
|
|
197
|
+
if (files.length > 0) {
|
|
198
|
+
onAttachFiles?.(files);
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
const dragCounterHandlers = {
|
|
202
|
+
onDragEnter: (event) => {
|
|
203
|
+
if (onAttachFiles === void 0 || !event.dataTransfer.types.includes("Files")) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
event.preventDefault();
|
|
207
|
+
dragDepth.current += 1;
|
|
208
|
+
setDragging(true);
|
|
209
|
+
},
|
|
210
|
+
onDragOver: (event) => {
|
|
211
|
+
if (onAttachFiles === void 0 || !event.dataTransfer.types.includes("Files")) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
event.preventDefault();
|
|
215
|
+
},
|
|
216
|
+
onDragLeave: () => {
|
|
217
|
+
if (dragDepth.current > 0) {
|
|
218
|
+
dragDepth.current -= 1;
|
|
219
|
+
if (dragDepth.current === 0) {
|
|
220
|
+
setDragging(false);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
onDrop: (event) => {
|
|
225
|
+
if (onAttachFiles === void 0) {
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
event.preventDefault();
|
|
229
|
+
dragDepth.current = 0;
|
|
230
|
+
setDragging(false);
|
|
231
|
+
emitFiles(event.dataTransfer.files);
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
const SendIcon = icons?.send ?? ArrowUp;
|
|
235
|
+
const StopIcon = icons?.stop ?? Square;
|
|
236
|
+
const showStop = sending && onStop !== void 0;
|
|
237
|
+
const submitBlocked = disabled || sending || (canSubmit === void 0 ? value.trim() === "" : !canSubmit);
|
|
238
|
+
return /* @__PURE__ */ jsxs(
|
|
239
|
+
"form",
|
|
240
|
+
{
|
|
241
|
+
ref,
|
|
242
|
+
"data-as": "chat-composer",
|
|
243
|
+
"data-sending": sending,
|
|
244
|
+
onSubmit: (event) => {
|
|
245
|
+
event.preventDefault();
|
|
246
|
+
submit();
|
|
247
|
+
},
|
|
248
|
+
className: cn("flex w-full flex-col gap-2", className),
|
|
249
|
+
...dragCounterHandlers,
|
|
250
|
+
children: [
|
|
251
|
+
suggestions ? /* @__PURE__ */ jsx("div", { className: "as-anim-slide-up flex flex-wrap gap-1.5", children: suggestions }) : null,
|
|
252
|
+
attachments ? /* @__PURE__ */ jsx("div", { className: "as-anim-slide-up flex flex-wrap gap-1.5", children: attachments }) : null,
|
|
253
|
+
/* @__PURE__ */ jsxs(
|
|
254
|
+
"div",
|
|
255
|
+
{
|
|
256
|
+
"data-as": "chat-composer-row",
|
|
257
|
+
"data-multiline": multiline || void 0,
|
|
258
|
+
"data-dragging": dragging || void 0,
|
|
259
|
+
className: cn(
|
|
260
|
+
"relative flex items-end gap-1.5 rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5",
|
|
261
|
+
dragging && "border-dashed border-[var(--as-primary)] bg-[var(--as-primary)]/5",
|
|
262
|
+
disabled && "opacity-50"
|
|
263
|
+
),
|
|
264
|
+
children: [
|
|
265
|
+
paletteVisible ? /* @__PURE__ */ jsx(
|
|
266
|
+
"div",
|
|
267
|
+
{
|
|
268
|
+
id: paletteId,
|
|
269
|
+
role: "listbox",
|
|
270
|
+
"aria-label": labels?.commands ?? "Commands",
|
|
271
|
+
"data-as": "chat-composer-commands",
|
|
272
|
+
className: "as-anim-slide-up absolute bottom-full left-0 right-0 z-[var(--as-z-popover)] mb-1.5 max-h-56 overflow-y-auto rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] p-1 shadow-[var(--as-shadow-pop)]",
|
|
273
|
+
children: paletteItems.map((item, index) => /* @__PURE__ */ jsxs(
|
|
274
|
+
"button",
|
|
275
|
+
{
|
|
276
|
+
type: "button",
|
|
277
|
+
id: `${paletteId}-option-${index}`,
|
|
278
|
+
role: "option",
|
|
279
|
+
"aria-selected": index === activeIndex,
|
|
280
|
+
tabIndex: -1,
|
|
281
|
+
onMouseEnter: () => setActiveIndex(index),
|
|
282
|
+
onClick: () => selectCommand(item),
|
|
283
|
+
className: cn(
|
|
284
|
+
"flex w-full items-center gap-2 rounded-[var(--as-radius-sm)] px-2 py-1.5 text-left text-sm transition-colors",
|
|
285
|
+
index === activeIndex ? "bg-[var(--as-secondary)] text-[var(--as-secondary-fg)]" : "text-[var(--as-fg)]"
|
|
286
|
+
),
|
|
287
|
+
children: [
|
|
288
|
+
item.icon ? /* @__PURE__ */ jsx(item.icon, { className: "size-4 shrink-0 text-[var(--as-muted-fg)]", "aria-hidden": true }) : null,
|
|
289
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
|
|
290
|
+
item.hint ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-[var(--as-muted-fg)]", children: item.hint }) : null
|
|
291
|
+
]
|
|
292
|
+
},
|
|
293
|
+
item.id
|
|
294
|
+
))
|
|
295
|
+
}
|
|
296
|
+
) : null,
|
|
297
|
+
toolbarStart ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-0.5 pb-0.5", children: toolbarStart }) : null,
|
|
298
|
+
/* @__PURE__ */ jsx(
|
|
299
|
+
"textarea",
|
|
300
|
+
{
|
|
301
|
+
ref: setTextarea,
|
|
302
|
+
value,
|
|
303
|
+
rows: 1,
|
|
304
|
+
disabled,
|
|
305
|
+
placeholder: placeholder ?? labels?.placeholder ?? "Send a message\u2026",
|
|
306
|
+
"aria-label": ariaLabel ?? labels?.ariaLabel ?? "Message",
|
|
307
|
+
"aria-controls": paletteVisible ? paletteId : void 0,
|
|
308
|
+
"aria-activedescendant": paletteVisible ? `${paletteId}-option-${activeIndex}` : void 0,
|
|
309
|
+
"aria-autocomplete": commands !== void 0 ? "list" : void 0,
|
|
310
|
+
onChange: (event) => {
|
|
311
|
+
const next = event.target.value;
|
|
312
|
+
if (historyIndex !== null && history?.[historyIndex] !== next) {
|
|
313
|
+
setHistoryIndex(null);
|
|
314
|
+
}
|
|
315
|
+
onValueChange(next);
|
|
316
|
+
syncCaret();
|
|
317
|
+
},
|
|
318
|
+
onKeyDown,
|
|
319
|
+
onKeyUp: syncCaret,
|
|
320
|
+
onClick: syncCaret,
|
|
321
|
+
onSelect: syncCaret,
|
|
322
|
+
onPaste: (event) => emitFiles(event.clipboardData.files),
|
|
323
|
+
className: "max-h-40 min-h-[1.5rem] w-full flex-1 resize-none bg-transparent px-1 py-1 text-sm leading-relaxed text-[var(--as-fg)] placeholder:text-[var(--as-muted-fg)] focus-visible:outline-none disabled:cursor-not-allowed"
|
|
324
|
+
}
|
|
325
|
+
),
|
|
326
|
+
toolbarEnd ? /* @__PURE__ */ jsx("div", { className: "flex shrink-0 items-center gap-0.5 pb-0.5", children: toolbarEnd }) : null,
|
|
327
|
+
showStop ? /* @__PURE__ */ jsx(
|
|
328
|
+
"button",
|
|
329
|
+
{
|
|
330
|
+
type: "button",
|
|
331
|
+
"aria-label": labels?.stop ?? "Stop generating",
|
|
332
|
+
title: labels?.stop ?? "Stop generating",
|
|
333
|
+
onClick: onStop,
|
|
334
|
+
className: cn(
|
|
335
|
+
"mb-0.5 flex size-7 shrink-0 items-center justify-center rounded-full border border-[var(--as-border)] bg-[var(--as-surface-raised)] text-[var(--as-fg)] transition-colors hover:bg-[var(--as-secondary)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]",
|
|
336
|
+
morphTarget === "stop" && "as-anim-morph-in"
|
|
337
|
+
),
|
|
338
|
+
children: /* @__PURE__ */ jsx(StopIcon, { className: "size-3.5", "aria-hidden": true })
|
|
339
|
+
}
|
|
340
|
+
) : /* @__PURE__ */ jsx(
|
|
341
|
+
"button",
|
|
342
|
+
{
|
|
343
|
+
type: "submit",
|
|
344
|
+
"aria-label": labels?.send ?? "Send message",
|
|
345
|
+
title: labels?.send ?? "Send message",
|
|
346
|
+
disabled: submitBlocked,
|
|
347
|
+
className: cn(
|
|
348
|
+
"mb-0.5 flex size-7 shrink-0 items-center justify-center rounded-full bg-[var(--as-primary)] text-[var(--as-primary-fg)] transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-30 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]",
|
|
349
|
+
morphTarget === "send" && "as-anim-morph-in"
|
|
350
|
+
),
|
|
351
|
+
children: /* @__PURE__ */ jsx(SendIcon, { className: "size-4", "aria-hidden": true })
|
|
352
|
+
}
|
|
353
|
+
)
|
|
354
|
+
]
|
|
355
|
+
}
|
|
356
|
+
),
|
|
357
|
+
dragging && onAttachFiles ? /* @__PURE__ */ jsx("p", { className: "text-xs text-[var(--as-muted-fg)]", role: "status", children: labels?.dropFiles ?? "Drop files to attach" }) : null
|
|
358
|
+
]
|
|
359
|
+
}
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
export { ChatComposer };
|
|
365
|
+
//# sourceMappingURL=chunk-P3QUNCBR.js.map
|
|
366
|
+
//# sourceMappingURL=chunk-P3QUNCBR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-composer/ChatComposer.tsx"],"names":["ChatComposer"],"mappings":"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","file":"chunk-P3QUNCBR.js","sourcesContent":["import * as React from 'react'\nimport { ArrowUp, Square } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { searchScore } from '../../lib/fuzzy'\n\nexport interface ChatComposerLabels {\n send: string\n stop: string\n placeholder: string\n ariaLabel: string\n dropFiles: string\n commands: string\n}\n\nexport interface ChatComposerIcons {\n send: LucideIcon\n stop: LucideIcon\n}\n\nexport interface ChatComposerCommand {\n id: string\n label: string\n hint?: string\n icon?: LucideIcon\n}\n\nexport interface ChatComposerCommandToken {\n /** Draft offsets of the `trigger + query` token to replace on select. */\n start: number\n end: number\n /** Text typed after the trigger character. */\n query: string\n}\n\nexport interface ChatComposerCommands {\n /** Palette trigger character — `/` for slash commands, `@` for mentions. Default `/`. */\n trigger?: string\n items: ChatComposerCommand[]\n /** Max visible entries. Default 8. */\n maxItems?: number\n /**\n * Fired when a command is selected (Enter/Tab/click). The app owns the\n * draft edit: replace `value.slice(token.start, token.end)` with the\n * insertion of its choice.\n */\n onSelect: (id: string, token: ChatComposerCommandToken) => void\n}\n\nexport interface ChatComposerProps {\n value: string\n onValueChange: (value: string) => void\n /** Enter / Send — IME-safe (composition and keyCode 229 are ignored). */\n onSubmit: () => void\n /** A turn is in flight — renders the stop control when `onStop` is provided. Escape stops too. */\n sending?: boolean\n onStop?: () => void\n disabled?: boolean\n /**\n * Overrides the send button's blank-text guard. Apps that allow\n * attachment-only submits (health's image-only \"what's what?\" turn) pass\n * `true` while ready attachments exist; pass `false` to force-disable.\n * Default: the button enables only when `value.trim() !== ''`. The\n * Enter/form path is unaffected — the app's `onSubmit` stays the guard.\n */\n canSubmit?: boolean\n /**\n * Slash-command / mention palette: opens while the caret touches a\n * `trigger`-started word; ArrowUp/Down move, Enter/Tab select (never\n * submit while open), Escape dismisses. Fuzzy-filtered via `searchScore`.\n */\n commands?: ChatComposerCommands\n /**\n * Previously sent prompts (oldest → newest). ArrowUp on an empty draft\n * recalls the last one; ArrowDown walks back toward the empty draft.\n */\n history?: string[]\n placeholder?: string\n ariaLabel?: string\n /** Auto-grow cap before the textarea scrolls. Default 8. */\n maxRows?: number\n /** Leading slot inside the input row (attach menu, equation, draw…). */\n toolbarStart?: React.ReactNode\n /** Trailing slot inside the input row (dictation, tools…). */\n toolbarEnd?: React.ReactNode\n /** Attachment rail above the input (usually `FileQueue` / chips). */\n attachments?: React.ReactNode\n /** Suggestion chips / context strip above everything. */\n suggestions?: React.ReactNode\n /** Drag-drop + paste wiring for file attachments. */\n onAttachFiles?: (files: File[]) => void\n labels?: Partial<ChatComposerLabels>\n icons?: Partial<ChatComposerIcons>\n textareaRef?: React.Ref<HTMLTextAreaElement>\n className?: string\n}\n\nfunction isIMEComposition(event: React.KeyboardEvent<HTMLTextAreaElement>): boolean {\n return event.nativeEvent.isComposing || event.keyCode === 229\n}\n\ninterface ActiveToken {\n start: number\n end: number\n query: string\n}\n\nfunction tokenAtCaret(value: string, caret: number, trigger: string): ActiveToken | null {\n const pos = Math.min(caret, value.length)\n let start = pos\n while (start > 0 && !/\\s/.test(value[start - 1] ?? '')) {\n start -= 1\n }\n const text = value.slice(start, pos)\n if (!text.startsWith(trigger)) {\n return null\n }\n const query = text.slice(trigger.length)\n if (query.includes(trigger)) {\n return null\n }\n return { start, end: pos, query }\n}\n\n/**\n * The family chat input: auto-growing IME-safe textarea, send/stop\n * states, attachment/dictation/toolbar slots, drag-drop + paste file\n * wiring, a slash-command/mention palette (`commands`), Escape-to-stop\n * and ArrowUp prompt recall (`history`). Presentational + controlled;\n * transports stay app-side.\n */\nexport const ChatComposer = React.forwardRef<HTMLFormElement, ChatComposerProps>(\n function ChatComposer(\n {\n value,\n onValueChange,\n onSubmit,\n sending = false,\n onStop,\n disabled = false,\n canSubmit,\n commands,\n history,\n placeholder,\n ariaLabel,\n maxRows = 8,\n toolbarStart,\n toolbarEnd,\n attachments,\n suggestions,\n onAttachFiles,\n labels,\n icons,\n textareaRef,\n className,\n },\n ref,\n ) {\n const internalTextareaRef = React.useRef<HTMLTextAreaElement | null>(null)\n const [dragging, setDragging] = React.useState(false)\n const [multiline, setMultiline] = React.useState(false)\n const multilineRef = React.useRef(false)\n const dragDepth = React.useRef(0)\n const prevSendingRef = React.useRef(sending)\n const [morphTarget, setMorphTarget] = React.useState<'send' | 'stop' | null>(null)\n if (prevSendingRef.current !== sending) {\n prevSendingRef.current = sending\n setMorphTarget(sending ? 'stop' : 'send')\n }\n const [caret, setCaret] = React.useState(0)\n const [paletteDismissed, setPaletteDismissed] = React.useState(false)\n const [activeIndex, setActiveIndex] = React.useState(0)\n const [historyIndex, setHistoryIndex] = React.useState<number | null>(null)\n const paletteId = React.useId()\n\n const setTextarea = (element: HTMLTextAreaElement | null) => {\n internalTextareaRef.current = element\n if (typeof textareaRef === 'function') {\n textareaRef(element)\n } else if (textareaRef && typeof textareaRef === 'object') {\n ;(textareaRef as React.MutableRefObject<HTMLTextAreaElement | null>).current = element\n }\n }\n\n const syncCaret = () => {\n const element = internalTextareaRef.current\n if (element !== null) {\n setCaret(element.selectionStart ?? 0)\n }\n }\n\n React.useLayoutEffect(() => {\n const element = internalTextareaRef.current\n if (element === null) {\n return\n }\n const style = window.getComputedStyle(element)\n const lineHeight = Number.parseFloat(style.lineHeight) || 22\n const verticalPadding =\n (Number.parseFloat(style.paddingTop) || 0) + (Number.parseFloat(style.paddingBottom) || 0)\n // The JS cap must mirror the CSS box: a `max-h-*` class wins over\n // the maxRows fallback, otherwise overflowY and the real visible\n // cap disagree and lines clip silently.\n const cap = Number.parseFloat(style.maxHeight) || maxRows * 22\n element.style.height = 'auto'\n // scrollHeight rounds fractional line-heights down (22.75px at\n // text-sm/leading-relaxed), leaving the box ~1px short — the\n // caret then scrolls the hidden-overflow textarea and clips the\n // first line at the box top. The +1 absorbs the rounding; the\n // scrollTop reset guarantees the first line stays visible\n // whenever the whole content fits.\n const next =\n element.scrollHeight > 0 ? Math.min(Math.ceil(element.scrollHeight) + 1, cap) : 0\n element.style.height = next > 0 ? `${next}px` : 'auto'\n const overflowing = element.scrollHeight > element.clientHeight + 1\n element.style.overflowY = overflowing ? 'auto' : 'hidden'\n if (!overflowing && element.scrollTop !== 0) {\n element.scrollTop = 0\n }\n // Hysteresis: apps restyle this row off [data-multiline] (e.g.\n // footer-wrapping the toolbars under a full-width textarea), which\n // changes the textarea's width between the two states. A flag\n // re-measured at whichever width the previous decision produced\n // feeds back into itself and oscillates near the wrap threshold —\n // one keystroke wide, the next squeezed. Once multiline, stay\n // multiline until the draft clears.\n const grew = element.scrollHeight > lineHeight + verticalPadding + 1\n multilineRef.current = value === '' ? false : multilineRef.current || grew\n setMultiline(multilineRef.current)\n }, [value, maxRows])\n\n const trigger = commands?.trigger ?? '/'\n const token = React.useMemo(\n () => (commands === undefined ? null : tokenAtCaret(value, caret, trigger)),\n [commands, value, caret, trigger],\n )\n\n const paletteItems = React.useMemo(() => {\n if (commands === undefined || token === null) {\n return []\n }\n const max = commands.maxItems ?? 8\n return commands.items\n .map((item) => ({\n item,\n score: token.query === '' ? 0 : (searchScore(token.query, item.label) ?? searchScore(token.query, item.id)),\n }))\n .filter((entry) => entry.score !== null)\n .sort((a, b) => b.score! - a.score!)\n .slice(0, max)\n .map((entry) => entry.item)\n }, [commands, token])\n\n const paletteVisible =\n token !== null && paletteItems.length > 0 && !paletteDismissed && !disabled\n\n React.useEffect(() => {\n setPaletteDismissed(false)\n setActiveIndex(0)\n }, [token?.start, token?.query])\n\n React.useEffect(() => {\n if (value === '') {\n setHistoryIndex(null)\n }\n }, [value])\n\n const selectCommand = (command: ChatComposerCommand) => {\n if (token !== null) {\n commands?.onSelect(command.id, { start: token.start, end: token.end, query: token.query })\n }\n setPaletteDismissed(true)\n internalTextareaRef.current?.focus()\n }\n\n const submit = () => {\n if (disabled || sending) {\n return\n }\n onSubmit()\n }\n\n const onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = (event) => {\n if (paletteVisible) {\n if (event.key === 'ArrowDown') {\n event.preventDefault()\n setActiveIndex((index) => (index + 1) % paletteItems.length)\n return\n }\n if (event.key === 'ArrowUp') {\n event.preventDefault()\n setActiveIndex((index) => (index - 1 + paletteItems.length) % paletteItems.length)\n return\n }\n if ((event.key === 'Enter' || event.key === 'Tab') && !isIMEComposition(event)) {\n event.preventDefault()\n selectCommand(paletteItems[activeIndex] ?? paletteItems[0]!)\n return\n }\n if (event.key === 'Escape') {\n event.preventDefault()\n setPaletteDismissed(true)\n return\n }\n } else if (event.key === 'Escape' && sending && onStop !== undefined) {\n event.preventDefault()\n onStop()\n return\n } else if (\n (event.key === 'ArrowUp' || event.key === 'ArrowDown') &&\n history !== undefined &&\n history.length > 0 &&\n (value === '' || historyIndex !== null)\n ) {\n event.preventDefault()\n if (event.key === 'ArrowUp') {\n const next = historyIndex === null ? history.length - 1 : Math.max(0, historyIndex - 1)\n setHistoryIndex(next)\n onValueChange(history[next] ?? '')\n setCaret((history[next] ?? '').length)\n } else if (historyIndex !== null) {\n const next = historyIndex + 1\n if (next >= history.length) {\n setHistoryIndex(null)\n onValueChange('')\n setCaret(0)\n } else {\n setHistoryIndex(next)\n onValueChange(history[next] ?? '')\n setCaret((history[next] ?? '').length)\n }\n }\n return\n }\n if (event.key !== 'Enter' || event.shiftKey) {\n return\n }\n if (isIMEComposition(event)) {\n return\n }\n event.preventDefault()\n submit()\n }\n\n const emitFiles = (fileList: FileList | null | undefined) => {\n const files = fileList ? Array.from(fileList) : []\n if (files.length > 0) {\n onAttachFiles?.(files)\n }\n }\n\n const dragCounterHandlers = {\n onDragEnter: (event: React.DragEvent) => {\n if (onAttachFiles === undefined || !event.dataTransfer.types.includes('Files')) {\n return\n }\n event.preventDefault()\n dragDepth.current += 1\n setDragging(true)\n },\n onDragOver: (event: React.DragEvent) => {\n if (onAttachFiles === undefined || !event.dataTransfer.types.includes('Files')) {\n return\n }\n event.preventDefault()\n },\n onDragLeave: () => {\n if (dragDepth.current > 0) {\n dragDepth.current -= 1\n if (dragDepth.current === 0) {\n setDragging(false)\n }\n }\n },\n onDrop: (event: React.DragEvent) => {\n if (onAttachFiles === undefined) {\n return\n }\n event.preventDefault()\n dragDepth.current = 0\n setDragging(false)\n emitFiles(event.dataTransfer.files)\n },\n }\n\n const SendIcon = icons?.send ?? ArrowUp\n const StopIcon = icons?.stop ?? Square\n const showStop = sending && onStop !== undefined\n const submitBlocked =\n disabled || sending || (canSubmit === undefined ? value.trim() === '' : !canSubmit)\n\n return (\n <form\n ref={ref}\n data-as=\"chat-composer\"\n data-sending={sending}\n onSubmit={(event) => {\n event.preventDefault()\n submit()\n }}\n className={cn('flex w-full flex-col gap-2', className)}\n {...dragCounterHandlers}\n >\n {suggestions ? <div className=\"as-anim-slide-up flex flex-wrap gap-1.5\">{suggestions}</div> : null}\n {attachments ? <div className=\"as-anim-slide-up flex flex-wrap gap-1.5\">{attachments}</div> : null}\n <div\n data-as=\"chat-composer-row\"\n data-multiline={multiline || undefined}\n data-dragging={dragging || undefined}\n className={cn(\n 'relative flex items-end gap-1.5 rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface)] px-2 py-1.5',\n dragging && 'border-dashed border-[var(--as-primary)] bg-[var(--as-primary)]/5',\n disabled && 'opacity-50',\n )}\n >\n {paletteVisible ? (\n <div\n id={paletteId}\n role=\"listbox\"\n aria-label={labels?.commands ?? 'Commands'}\n data-as=\"chat-composer-commands\"\n className=\"as-anim-slide-up absolute bottom-full left-0 right-0 z-[var(--as-z-popover)] mb-1.5 max-h-56 overflow-y-auto rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] p-1 shadow-[var(--as-shadow-pop)]\"\n >\n {paletteItems.map((item, index) => (\n <button\n type=\"button\"\n key={item.id}\n id={`${paletteId}-option-${index}`}\n role=\"option\"\n aria-selected={index === activeIndex}\n tabIndex={-1}\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => selectCommand(item)}\n className={cn(\n 'flex w-full items-center gap-2 rounded-[var(--as-radius-sm)] px-2 py-1.5 text-left text-sm transition-colors',\n index === activeIndex\n ? 'bg-[var(--as-secondary)] text-[var(--as-secondary-fg)]'\n : 'text-[var(--as-fg)]',\n )}\n >\n {item.icon ? <item.icon className=\"size-4 shrink-0 text-[var(--as-muted-fg)]\" aria-hidden /> : null}\n <span className=\"min-w-0 flex-1 truncate\">{item.label}</span>\n {item.hint ? <span className=\"shrink-0 text-xs text-[var(--as-muted-fg)]\">{item.hint}</span> : null}\n </button>\n ))}\n </div>\n ) : null}\n {toolbarStart ? <div className=\"flex shrink-0 items-center gap-0.5 pb-0.5\">{toolbarStart}</div> : null}\n <textarea\n ref={setTextarea}\n value={value}\n rows={1}\n disabled={disabled}\n placeholder={placeholder ?? labels?.placeholder ?? 'Send a message…'}\n aria-label={ariaLabel ?? labels?.ariaLabel ?? 'Message'}\n aria-controls={paletteVisible ? paletteId : undefined}\n aria-activedescendant={\n paletteVisible ? `${paletteId}-option-${activeIndex}` : undefined\n }\n aria-autocomplete={commands !== undefined ? 'list' : undefined}\n onChange={(event) => {\n const next = event.target.value\n if (historyIndex !== null && history?.[historyIndex] !== next) {\n setHistoryIndex(null)\n }\n onValueChange(next)\n syncCaret()\n }}\n onKeyDown={onKeyDown}\n onKeyUp={syncCaret}\n onClick={syncCaret}\n onSelect={syncCaret}\n onPaste={(event) => emitFiles(event.clipboardData.files)}\n className=\"max-h-40 min-h-[1.5rem] w-full flex-1 resize-none bg-transparent px-1 py-1 text-sm leading-relaxed text-[var(--as-fg)] placeholder:text-[var(--as-muted-fg)] focus-visible:outline-none disabled:cursor-not-allowed\"\n />\n {toolbarEnd ? <div className=\"flex shrink-0 items-center gap-0.5 pb-0.5\">{toolbarEnd}</div> : null}\n {showStop ? (\n <button\n type=\"button\"\n aria-label={labels?.stop ?? 'Stop generating'}\n title={labels?.stop ?? 'Stop generating'}\n onClick={onStop}\n className={cn(\n 'mb-0.5 flex size-7 shrink-0 items-center justify-center rounded-full border border-[var(--as-border)] bg-[var(--as-surface-raised)] text-[var(--as-fg)] transition-colors hover:bg-[var(--as-secondary)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]',\n morphTarget === 'stop' && 'as-anim-morph-in',\n )}\n >\n <StopIcon className=\"size-3.5\" aria-hidden />\n </button>\n ) : (\n <button\n type=\"submit\"\n aria-label={labels?.send ?? 'Send message'}\n title={labels?.send ?? 'Send message'}\n disabled={submitBlocked}\n className={cn(\n 'mb-0.5 flex size-7 shrink-0 items-center justify-center rounded-full bg-[var(--as-primary)] text-[var(--as-primary-fg)] transition-opacity hover:opacity-90 disabled:pointer-events-none disabled:opacity-30 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]',\n morphTarget === 'send' && 'as-anim-morph-in',\n )}\n >\n <SendIcon className=\"size-4\" aria-hidden />\n </button>\n )}\n </div>\n {dragging && onAttachFiles ? (\n <p className=\"text-xs text-[var(--as-muted-fg)]\" role=\"status\">\n {labels?.dropFiles ?? 'Drop files to attach'}\n </p>\n ) : null}\n </form>\n )\n },\n)\n"]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { cn } from './chunk-RVVXVTH3.js';
|
|
2
|
+
import * as React from 'react';
|
|
3
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
var ChatSuggestionCard = React.forwardRef(
|
|
6
|
+
function ChatSuggestionCard2({ icon: Icon, hint, className, children, ...props }, ref) {
|
|
7
|
+
return /* @__PURE__ */ jsxs(
|
|
8
|
+
"button",
|
|
9
|
+
{
|
|
10
|
+
ref,
|
|
11
|
+
type: "button",
|
|
12
|
+
"data-as": "chat-suggestion-card",
|
|
13
|
+
className: cn(
|
|
14
|
+
"flex w-full items-center gap-2.5 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-2.5 text-left text-sm text-[var(--as-fg)] shadow-[var(--as-shadow-1)] transition-[border-color,box-shadow,background-color] duration-[var(--as-duration-fast)] ease-[var(--as-ease-standard)] hover:border-[var(--as-primary)] hover:bg-[var(--as-surface-raised)] hover:shadow-[var(--as-shadow-2)] focus-visible:border-[var(--as-primary)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)] disabled:pointer-events-none disabled:opacity-50",
|
|
15
|
+
className
|
|
16
|
+
),
|
|
17
|
+
...props,
|
|
18
|
+
children: [
|
|
19
|
+
Icon ? /* @__PURE__ */ jsx(Icon, { className: "size-4 shrink-0 text-[var(--as-muted-fg)]", "aria-hidden": true }) : null,
|
|
20
|
+
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children }),
|
|
21
|
+
hint ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-xs text-[var(--as-muted-fg)]", children: hint }) : null
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
export { ChatSuggestionCard };
|
|
29
|
+
//# sourceMappingURL=chunk-PABMR4RA.js.map
|
|
30
|
+
//# sourceMappingURL=chunk-PABMR4RA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-suggestion-card/ChatSuggestionCard.tsx"],"names":["ChatSuggestionCard"],"mappings":";;;;AAmBO,IAAM,kBAAA,GAA2B,KAAA,CAAA,UAAA;AAAA,EACtC,SAASA,mBAAAA,CAAmB,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,SAAA,EAAW,QAAA,EAAU,GAAG,KAAA,EAAM,EAAG,GAAA,EAAK;AACpF,IAAA,uBACE,IAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,IAAA,EAAK,QAAA;AAAA,QACL,SAAA,EAAQ,sBAAA;AAAA,QACR,SAAA,EAAW,EAAA;AAAA,UACT,gmBAAA;AAAA,UACA;AAAA,SACF;AAAA,QACC,GAAG,KAAA;AAAA,QAEH,QAAA,EAAA;AAAA,UAAA,IAAA,uBAAQ,IAAA,EAAA,EAAK,SAAA,EAAU,2CAAA,EAA4C,aAAA,EAAW,MAAC,CAAA,GAAK,IAAA;AAAA,0BACrF,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,yBAAA,EAA2B,QAAA,EAAS,CAAA;AAAA,UACnD,uBAAO,GAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,4CAAA,EAA8C,gBAAK,CAAA,GAAU;AAAA;AAAA;AAAA,KACvF;AAAA,EAEJ;AACF","file":"chunk-PABMR4RA.js","sourcesContent":["import * as React from 'react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\n\nexport interface ChatSuggestionCardProps extends React.ComponentProps<'button'> {\n /** Leading icon (defaults to none — pass `Sparkles`, `BookOpen`, …). */\n icon?: LucideIcon\n /** Trailing hint text, e.g. \"5 min\". */\n hint?: string\n children: React.ReactNode\n}\n\n/**\n * The family suggestion card (plan 101 P4): the standard action chip for\n * `ChatWelcome suggestions` and composer suggestion strips — left-aligned\n * icon + title + hint with a lift-on-hover affordance (border + shadow,\n * no transform utilities: TW3-safe).\n */\nexport const ChatSuggestionCard = React.forwardRef<HTMLButtonElement, ChatSuggestionCardProps>(\n function ChatSuggestionCard({ icon: Icon, hint, className, children, ...props }, ref) {\n return (\n <button\n ref={ref}\n type=\"button\"\n data-as=\"chat-suggestion-card\"\n className={cn(\n 'flex w-full items-center gap-2.5 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-2.5 text-left text-sm text-[var(--as-fg)] shadow-[var(--as-shadow-1)] transition-[border-color,box-shadow,background-color] duration-[var(--as-duration-fast)] ease-[var(--as-ease-standard)] hover:border-[var(--as-primary)] hover:bg-[var(--as-surface-raised)] hover:shadow-[var(--as-shadow-2)] focus-visible:border-[var(--as-primary)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)] disabled:pointer-events-none disabled:opacity-50',\n className,\n )}\n {...props}\n >\n {Icon ? <Icon className=\"size-4 shrink-0 text-[var(--as-muted-fg)]\" aria-hidden /> : null}\n <span className=\"min-w-0 flex-1 truncate\">{children}</span>\n {hint ? <span className=\"shrink-0 text-xs text-[var(--as-muted-fg)]\">{hint}</span> : null}\n </button>\n )\n },\n)\n"]}
|
|
@@ -27,7 +27,14 @@ var ChatPanel = React.forwardRef(
|
|
|
27
27
|
]
|
|
28
28
|
}
|
|
29
29
|
) : null,
|
|
30
|
-
banner ? /* @__PURE__ */ jsx(
|
|
30
|
+
banner ? /* @__PURE__ */ jsx(
|
|
31
|
+
"div",
|
|
32
|
+
{
|
|
33
|
+
"data-as": "chat-panel-banner",
|
|
34
|
+
className: "as-anim-slide-up shrink-0 px-3 py-1.5 text-xs text-[var(--as-muted-fg)]",
|
|
35
|
+
children: banner
|
|
36
|
+
}
|
|
37
|
+
) : null,
|
|
31
38
|
/* @__PURE__ */ jsx("div", { className: "flex min-h-0 flex-1 flex-col", children: /* @__PURE__ */ jsx(
|
|
32
39
|
"div",
|
|
33
40
|
{
|
|
@@ -47,5 +54,5 @@ var ChatPanel = React.forwardRef(
|
|
|
47
54
|
);
|
|
48
55
|
|
|
49
56
|
export { ChatPanel };
|
|
50
|
-
//# sourceMappingURL=chunk-
|
|
51
|
-
//# sourceMappingURL=chunk-
|
|
57
|
+
//# sourceMappingURL=chunk-SR4IN564.js.map
|
|
58
|
+
//# sourceMappingURL=chunk-SR4IN564.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-panel/ChatPanel.tsx"],"names":["ChatPanel"],"mappings":";;;;AA6BO,IAAM,SAAA,GAAkB,KAAA,CAAA,UAAA;AAAA,EAC7B,SAASA,UAAAA,CAAU,EAAE,OAAA,EAAS,KAAA,EAAO,OAAA,EAAS,MAAA,EAAQ,UAAA,EAAY,QAAA,EAAU,MAAA,EAAQ,SAAA,EAAU,EAAG,GAAA,EAAK;AACpG,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAQ,YAAA;AAAA,QACR,cAAA,EAAc,OAAA;AAAA,QACd,SAAA,EAAW,EAAA;AAAA,UACT,gFAAA;AAAA,UACA,YAAY,QAAA,IAAY,iBAAA;AAAA,UACxB;AAAA,SACF;AAAA,QAEC,QAAA,EAAA;AAAA,UAAA,KAAA,KAAU,MAAA,IAAa,YAAY,MAAA,mBAClC,IAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAQ,mBAAA;AAAA,cACR,SAAA,EAAU,+EAAA;AAAA,cAEV,QAAA,EAAA;AAAA,gCAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,+CAAA,EAAiD,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,gBACrE,0BAAU,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,oCAAA,EAAsC,mBAAQ,CAAA,GAAS;AAAA;AAAA;AAAA,WACnF,GACE,IAAA;AAAA,UACH,MAAA,mBACC,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAQ,mBAAA;AAAA,cACR,SAAA,EAAU,yEAAA;AAAA,cAET,QAAA,EAAA;AAAA;AAAA,WACH,GACE,IAAA;AAAA,0BACJ,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,8BAAA,EACb,QAAA,kBAAA,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAW,EAAA;AAAA,gBACT,qCAAA;AAAA,gBACA,YAAY,MAAA,IAAU;AAAA,eACxB;AAAA,cAEC,QAAA,EAAA;AAAA;AAAA,WACH,EACF,CAAA;AAAA,UACC,QAAA,mBACC,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mDACb,QAAA,kBAAA,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAW,EAAA,CAAG,YAAY,MAAA,IAAU,0BAA0B,CAAA,EAAI,QAAA,EAAA,QAAA,EAAS,GAClF,CAAA,GACE,IAAA;AAAA,UACH,yBACC,GAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,2EAAA,EAA6E,kBAAO,CAAA,GACjG;AAAA;AAAA;AAAA,KACN;AAAA,EAEJ;AACF","file":"chunk-SR4IN564.js","sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../../lib/utils'\n\nexport type ChatPanelVariant = 'page' | 'sidebar' | 'bubble'\n\nexport interface ChatPanelProps {\n /** Layout tier: full page (full-bleed shell, centered conversation column), sidebar (dense column), bubble (compact widget body). */\n variant: ChatPanelVariant\n /** Header row: title node + action nodes (session list, branch tree, expand, close). */\n title?: React.ReactNode\n actions?: React.ReactNode\n /** Status strip under the header (connection warnings, context summary). */\n banner?: React.ReactNode\n /** Usually `<ChatTranscript …/>`. */\n transcript: React.ReactNode\n /** Usually `<ChatComposer …/>`. */\n composer?: React.ReactNode\n /** Disclaimer row under the composer (health guidance, etc.). */\n footer?: React.ReactNode\n className?: string\n}\n\n/**\n * The composed chat host — the one uniform surface assembly behind the\n * family's three shapes (full page / sidepanel / bubble). Owns layout\n * only; transcript, composer and every feature slot stay app-composed\n * (ADR-006 tier 3, `RichTextEditor` precedent).\n */\nexport const ChatPanel = React.forwardRef<HTMLDivElement, ChatPanelProps>(\n function ChatPanel({ variant, title, actions, banner, transcript, composer, footer, className }, ref) {\n return (\n <div\n ref={ref}\n data-as=\"chat-panel\"\n data-variant={variant}\n className={cn(\n 'flex h-full min-h-0 w-full flex-col bg-[var(--as-surface)] text-[var(--as-fg)]',\n variant === 'bubble' && 'overflow-hidden',\n className,\n )}\n >\n {title !== undefined || actions !== undefined ? (\n <div\n data-as=\"chat-panel-header\"\n className=\"flex shrink-0 items-center gap-2 border-b border-[var(--as-border)] px-3 py-2\"\n >\n <div className=\"min-w-0 flex-1 truncate text-sm font-semibold\">{title}</div>\n {actions ? <div className=\"flex shrink-0 items-center gap-0.5\">{actions}</div> : null}\n </div>\n ) : null}\n {banner ? (\n <div\n data-as=\"chat-panel-banner\"\n className=\"as-anim-slide-up shrink-0 px-3 py-1.5 text-xs text-[var(--as-muted-fg)]\"\n >\n {banner}\n </div>\n ) : null}\n <div className=\"flex min-h-0 flex-1 flex-col\">\n <div\n className={cn(\n 'flex min-h-0 w-full flex-1 flex-col',\n variant === 'page' && 'mx-auto max-w-3xl',\n )}\n >\n {transcript}\n </div>\n </div>\n {composer ? (\n <div className=\"shrink-0 border-t border-[var(--as-border)] p-2\">\n <div className={cn(variant === 'page' && 'mx-auto w-full max-w-3xl')}>{composer}</div>\n </div>\n ) : null}\n {footer ? (\n <div className=\"shrink-0 px-3 pb-2 pt-1 text-center text-[10px] text-[var(--as-muted-fg)]\">{footer}</div>\n ) : null}\n </div>\n )\n },\n)\n"]}
|