@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
|
@@ -1,17 +1,60 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { e as ChatMessageView } from './types-CxieoN2u.js';
|
|
3
|
+
|
|
4
|
+
interface ChatSearchFieldLabels {
|
|
5
|
+
search: string;
|
|
6
|
+
placeholder: string;
|
|
7
|
+
previous: string;
|
|
8
|
+
next: string;
|
|
9
|
+
clear: string;
|
|
10
|
+
matches: string;
|
|
11
|
+
}
|
|
12
|
+
interface ChatSearchFieldProps {
|
|
13
|
+
query: string;
|
|
14
|
+
onQueryChange: (query: string) => void;
|
|
15
|
+
/** Total matches in the transcript (drives the `n/N` readout). */
|
|
16
|
+
matchCount?: number;
|
|
17
|
+
/** 0-based active match index. */
|
|
18
|
+
activeIndex?: number;
|
|
19
|
+
onPrevious?: () => void;
|
|
20
|
+
onNext?: () => void;
|
|
21
|
+
labels?: Partial<ChatSearchFieldLabels>;
|
|
22
|
+
className?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The in-conversation search field (plan 101 P2): controlled query input
|
|
26
|
+
* with an `n/N` match readout and prev/next controls. Enter jumps to the
|
|
27
|
+
* next match, Shift+Enter to the previous, Escape clears. Composed by
|
|
28
|
+
* `ChatTranscript` when its `search` prop is given, or standalone.
|
|
29
|
+
*/
|
|
30
|
+
declare const ChatSearchField: React.ForwardRefExoticComponent<ChatSearchFieldProps & React.RefAttributes<HTMLDivElement>>;
|
|
3
31
|
|
|
4
32
|
interface ChatTranscriptLabels {
|
|
5
33
|
log: string;
|
|
6
34
|
scrollToBottom: string;
|
|
35
|
+
newMessages: string;
|
|
7
36
|
empty: string;
|
|
8
37
|
replied: string;
|
|
38
|
+
search: string;
|
|
39
|
+
searchPlaceholder: string;
|
|
40
|
+
previousMatch: string;
|
|
41
|
+
nextMatch: string;
|
|
42
|
+
clearSearch: string;
|
|
43
|
+
matches: string;
|
|
44
|
+
today: string;
|
|
45
|
+
yesterday: string;
|
|
46
|
+
stop: string;
|
|
47
|
+
}
|
|
48
|
+
type ChatTranscriptGroupPos = 'single' | 'start' | 'mid' | 'end';
|
|
49
|
+
interface ChatTranscriptSearch {
|
|
50
|
+
query: string;
|
|
51
|
+
onQueryChange: (query: string) => void;
|
|
9
52
|
}
|
|
10
53
|
interface ChatTranscriptProps {
|
|
11
54
|
items: ChatMessageView[];
|
|
12
|
-
/** Override the default `ChatMessage` + `MarkdownSurface` rendering. */
|
|
13
|
-
renderItem?: (message: ChatMessageView, index: number) => React.ReactNode;
|
|
14
|
-
/** Streaming tail — the live turn bubble (or any node
|
|
55
|
+
/** Override the default `ChatMessage` + `MarkdownSurface` rendering (third arg: group position when `groupConsecutive`; fourth arg: active search query). */
|
|
56
|
+
renderItem?: (message: ChatMessageView, index: number, groupPos?: ChatTranscriptGroupPos, query?: string) => React.ReactNode;
|
|
57
|
+
/** Streaming tail — the live turn bubble (or `ChatPending`) or any node. */
|
|
15
58
|
live?: React.ReactNode;
|
|
16
59
|
emptyState?: React.ReactNode;
|
|
17
60
|
/** Stick to bottom while the user hasn't scrolled away. Default true. */
|
|
@@ -20,14 +63,44 @@ interface ChatTranscriptProps {
|
|
|
20
63
|
scrollThresholdPx?: number;
|
|
21
64
|
/** Virtualize long transcripts (dynamic row measurement). Default false. */
|
|
22
65
|
virtualized?: boolean;
|
|
23
|
-
|
|
66
|
+
/**
|
|
67
|
+
* Tighten the spacing between consecutive same-role messages and tag
|
|
68
|
+
* each row with `data-group-pos` (`single | start | mid | end`).
|
|
69
|
+
* Default false.
|
|
70
|
+
*/
|
|
71
|
+
groupConsecutive?: boolean;
|
|
72
|
+
/** Visual design for the default renderer: paired bubbles (default) or flat assistant prose over the panel surface. */
|
|
73
|
+
design?: 'bubbles' | 'flat';
|
|
74
|
+
/**
|
|
75
|
+
* In-conversation search (plan 101 P2): renders `ChatSearchField`
|
|
76
|
+
* above the log, highlights matches in the default renderer, and
|
|
77
|
+
* jumps between them (Enter/Shift+Enter in the field, or the
|
|
78
|
+
* prev/next buttons). Jump-scrolling requires a non-virtualized
|
|
79
|
+
* transcript; virtualized transcripts highlight visible rows only.
|
|
80
|
+
*/
|
|
81
|
+
search?: ChatTranscriptSearch;
|
|
82
|
+
/**
|
|
83
|
+
* Today/Yesterday/date chips between day groups (reads
|
|
84
|
+
* `ChatMessageView.createdAt`; rows without one join the previous
|
|
85
|
+
* group). Default false.
|
|
86
|
+
*/
|
|
87
|
+
showDateSeparators?: boolean;
|
|
88
|
+
/** Custom formatter for older-day chips (default `MMM d, yyyy`). */
|
|
89
|
+
formatDate?: (date: Date) => string;
|
|
90
|
+
/** Scroll a message into view and flash it when this changes (branch-tree clicks, citations, deep links). */
|
|
91
|
+
focusMessageId?: string | null;
|
|
92
|
+
/** Show a floating stop pill beside the jump pill while a live turn streams and the user scrolled away. */
|
|
93
|
+
onStop?: () => void;
|
|
94
|
+
labels?: Partial<ChatTranscriptLabels & ChatSearchFieldLabels>;
|
|
24
95
|
className?: string;
|
|
25
96
|
}
|
|
26
97
|
/**
|
|
27
98
|
* The conversation list: `role="log"` with polite turn-completion
|
|
28
|
-
* announcements, stick-to-bottom auto-scroll with
|
|
29
|
-
*
|
|
99
|
+
* announcements, stick-to-bottom auto-scroll with an unread-counting
|
|
100
|
+
* jump-to-latest pill, optional consecutive-message grouping, a top
|
|
101
|
+
* fade mask while scrolled into the thread, thin themed scrollbars,
|
|
102
|
+
* and optional virtualization for thousand-message threads.
|
|
30
103
|
*/
|
|
31
104
|
declare const ChatTranscript: React.ForwardRefExoticComponent<ChatTranscriptProps & React.RefAttributes<HTMLDivElement>>;
|
|
32
105
|
|
|
33
|
-
export { ChatTranscript, type ChatTranscriptLabels, type ChatTranscriptProps };
|
|
106
|
+
export { ChatSearchField, type ChatSearchFieldLabels, type ChatSearchFieldProps, ChatTranscript, type ChatTranscriptGroupPos, type ChatTranscriptLabels, type ChatTranscriptProps, type ChatTranscriptSearch };
|
package/dist/chat-transcript.js
CHANGED
package/dist/chat-turn-status.js
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
interface ChatWelcomeProps {
|
|
4
|
+
/** Greeting headline, e.g. "Ask anything about your courses". */
|
|
5
|
+
title: string;
|
|
6
|
+
subtitle?: string;
|
|
7
|
+
/** Suggestion cards / chips — children stagger in (40 ms steps). */
|
|
8
|
+
suggestions?: React.ReactNode;
|
|
9
|
+
/** Node inside the breathing `--as-ai` orb. Default: `Sparkles`. */
|
|
10
|
+
icon?: React.ReactNode;
|
|
11
|
+
/** `page` centers generously; `sidebar` is the default density; `bubble` is compact. */
|
|
12
|
+
variant?: 'page' | 'sidebar' | 'bubble';
|
|
13
|
+
className?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The chat empty-state kit (plan 100 S6): breathing `--as-ai` identity
|
|
17
|
+
* orb, greeting, subtitle and staggered suggestion slots — drop it into
|
|
18
|
+
* `ChatTranscript emptyState`. Presentational; suggestion targets stay
|
|
19
|
+
* app-side.
|
|
20
|
+
*/
|
|
21
|
+
declare const ChatWelcome: React.ForwardRefExoticComponent<ChatWelcomeProps & React.RefAttributes<HTMLDivElement>>;
|
|
22
|
+
|
|
23
|
+
export { ChatWelcome, type ChatWelcomeProps };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"chat-welcome.js"}
|
|
@@ -36,6 +36,7 @@ var ChatSessionList = React.forwardRef(
|
|
|
36
36
|
onSelect,
|
|
37
37
|
onNew,
|
|
38
38
|
onRename,
|
|
39
|
+
onRenameCommit,
|
|
39
40
|
onDelete,
|
|
40
41
|
onExport,
|
|
41
42
|
searchable = true,
|
|
@@ -45,6 +46,8 @@ var ChatSessionList = React.forwardRef(
|
|
|
45
46
|
className
|
|
46
47
|
}, ref) {
|
|
47
48
|
const [query, setQuery] = React.useState("");
|
|
49
|
+
const [editingId, setEditingId] = React.useState(null);
|
|
50
|
+
const [draftTitle, setDraftTitle] = React.useState("");
|
|
48
51
|
const NewIcon = icons?.newChat ?? MessageSquarePlus;
|
|
49
52
|
const RenameIcon = icons?.rename ?? Pencil;
|
|
50
53
|
const DeleteIcon = icons?.delete ?? Trash2;
|
|
@@ -111,17 +114,31 @@ var ChatSessionList = React.forwardRef(
|
|
|
111
114
|
}
|
|
112
115
|
) : null
|
|
113
116
|
] }),
|
|
114
|
-
sessions.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-xs text-[var(--as-muted-fg)]", children: labels?.empty ?? "No conversations yet" }) : filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-xs text-[var(--as-muted-fg)]", children: labels?.noResults ?? "No matches" }) : /* @__PURE__ */ jsx("div", { role: "list", "aria-label": labels?.search ?? "Conversations", className: "min-h-0 flex-1 overflow-y-auto", children: groups.map((group) => /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
|
|
117
|
+
sessions.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-xs text-[var(--as-muted-fg)]", children: labels?.empty ?? "No conversations yet" }) : filtered.length === 0 ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-xs text-[var(--as-muted-fg)]", children: labels?.noResults ?? "No matches" }) : /* @__PURE__ */ jsx("div", { role: "list", "aria-label": labels?.search ?? "Conversations", "data-as": "chat-session-rows", className: "min-h-0 flex-1 overflow-y-auto", children: groups.map((group) => /* @__PURE__ */ jsxs("div", { className: "mb-2", children: [
|
|
115
118
|
group.label ? /* @__PURE__ */ jsx("p", { className: "px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-[var(--as-muted-fg)]", children: group.label }) : null,
|
|
116
119
|
group.sessions.map((session) => {
|
|
117
120
|
const isActive = session.id === activeId;
|
|
118
121
|
const date = toDate(session.updatedAt);
|
|
119
|
-
const
|
|
120
|
-
|
|
122
|
+
const isEditing = editingId === session.id;
|
|
123
|
+
const commitRename = () => {
|
|
124
|
+
if (editingId !== null && draftTitle.trim() !== "") {
|
|
125
|
+
onRenameCommit?.(editingId, draftTitle.trim());
|
|
126
|
+
}
|
|
127
|
+
setEditingId(null);
|
|
128
|
+
};
|
|
129
|
+
const actions = onRename || onRenameCommit || onDelete || onExport ? [
|
|
130
|
+
onRename || onRenameCommit ? {
|
|
121
131
|
key: "rename",
|
|
122
132
|
label: labels?.rename ?? "Rename",
|
|
123
133
|
icon: /* @__PURE__ */ jsx(RenameIcon, { className: "size-3.5", "aria-hidden": true }),
|
|
124
|
-
onSelect: () =>
|
|
134
|
+
onSelect: () => {
|
|
135
|
+
if (onRenameCommit !== void 0) {
|
|
136
|
+
setEditingId(session.id);
|
|
137
|
+
setDraftTitle(session.title);
|
|
138
|
+
} else {
|
|
139
|
+
onRename?.(session.id);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
125
142
|
} : null,
|
|
126
143
|
onExport ? {
|
|
127
144
|
key: "export",
|
|
@@ -156,7 +173,28 @@ var ChatSessionList = React.forwardRef(
|
|
|
156
173
|
},
|
|
157
174
|
tabIndex: 0,
|
|
158
175
|
children: [
|
|
159
|
-
/* @__PURE__ */ jsx(
|
|
176
|
+
isEditing ? /* @__PURE__ */ jsx(
|
|
177
|
+
"input",
|
|
178
|
+
{
|
|
179
|
+
autoFocus: true,
|
|
180
|
+
value: draftTitle,
|
|
181
|
+
"aria-label": labels?.renameInput ?? "Conversation title",
|
|
182
|
+
onChange: (event) => setDraftTitle(event.target.value),
|
|
183
|
+
onClick: (event) => event.stopPropagation(),
|
|
184
|
+
onKeyDown: (event) => {
|
|
185
|
+
event.stopPropagation();
|
|
186
|
+
if (event.key === "Enter") {
|
|
187
|
+
event.preventDefault();
|
|
188
|
+
commitRename();
|
|
189
|
+
} else if (event.key === "Escape") {
|
|
190
|
+
event.preventDefault();
|
|
191
|
+
setEditingId(null);
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
onBlur: commitRename,
|
|
195
|
+
className: "min-w-0 flex-1 rounded-[var(--as-radius-sm)] border border-[var(--as-primary)] bg-[var(--as-surface)] px-1.5 py-0.5 text-xs text-[var(--as-fg)] focus-visible:outline-none"
|
|
196
|
+
}
|
|
197
|
+
) : /* @__PURE__ */ jsx("span", { className: "line-clamp-2 min-w-0 flex-1 text-[var(--as-fg)]", children: session.title }),
|
|
160
198
|
date ? /* @__PURE__ */ jsx("span", { className: "shrink-0 text-[10px] text-[var(--as-muted-fg)]", children: formatDistanceToNow(date, { addSuffix: true }) }) : null,
|
|
161
199
|
actions.length > 0 ? /* @__PURE__ */ jsx(
|
|
162
200
|
"span",
|
|
@@ -194,5 +232,5 @@ var ChatSessionList = React.forwardRef(
|
|
|
194
232
|
);
|
|
195
233
|
|
|
196
234
|
export { ChatSessionList };
|
|
197
|
-
//# sourceMappingURL=chunk-
|
|
198
|
-
//# sourceMappingURL=chunk-
|
|
235
|
+
//# sourceMappingURL=chunk-22MIIWC7.js.map
|
|
236
|
+
//# sourceMappingURL=chunk-22MIIWC7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-session-list/ChatSessionList.tsx"],"names":["ChatSessionList"],"mappings":"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","file":"chunk-22MIIWC7.js","sourcesContent":["import * as React from 'react'\nimport { Download, MessageSquarePlus, Pencil, Search, Trash2 } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\nimport { formatDistanceToNow, isToday, isYesterday, parseISO } from 'date-fns'\n\nimport { cn } from '../../lib/utils'\nimport { searchScore } from '../../lib/fuzzy'\n\nexport interface ChatSessionView {\n id: string\n title: string\n updatedAt?: string | number | Date\n meta?: Record<string, unknown>\n}\n\nexport interface ChatSessionListLabels {\n search: string\n searchPlaceholder: string\n newChat: string\n rename: string\n renameInput: string\n delete: string\n export: string\n today: string\n yesterday: string\n earlier: string\n empty: string\n noResults: string\n}\n\nexport interface ChatSessionListIcons {\n newChat: LucideIcon\n rename: LucideIcon\n delete: LucideIcon\n export: LucideIcon\n}\n\nexport interface ChatSessionListProps {\n sessions: ChatSessionView[]\n activeId?: string | null\n onSelect: (id: string) => void\n onNew?: () => void\n onRename?: (id: string) => void\n /**\n * Inline rename: when provided, the rename action edits the title in\n * place (Enter/blur commits, Escape cancels) instead of invoking\n * `onRename` — keep `onRename` for dialog-based flows only.\n */\n onRenameCommit?: (id: string, title: string) => void\n onDelete?: (id: string) => void\n onExport?: (id: string) => void\n searchable?: boolean\n groupByDate?: boolean\n labels?: Partial<ChatSessionListLabels>\n icons?: Partial<ChatSessionListIcons>\n className?: string\n}\n\nfunction toDate(value: string | number | Date | undefined): Date | undefined {\n if (value === undefined) {\n return undefined\n }\n if (value instanceof Date) {\n return value\n }\n if (typeof value === 'number') {\n return new Date(value)\n }\n return parseISO(value)\n}\n\nfunction bucketOf(date: Date | undefined): 'today' | 'yesterday' | 'earlier' | 'none' {\n if (date === undefined) {\n return 'none'\n }\n if (isToday(date)) {\n return 'today'\n }\n if (isYesterday(date)) {\n return 'yesterday'\n }\n return 'earlier'\n}\n\n/**\n * The session list beside a full-page chat (study's `ChatSessionList` +\n * health's history overlay, generalized): fuzzy search, date grouping,\n * active marking, per-session actions (rename/delete/export) via the\n * menu when handlers are provided. All actions stay app-side.\n */\nexport const ChatSessionList = React.forwardRef<HTMLDivElement, ChatSessionListProps>(\n function ChatSessionList(\n {\n sessions,\n activeId,\n onSelect,\n onNew,\n onRename,\n onRenameCommit,\n onDelete,\n onExport,\n searchable = true,\n groupByDate = true,\n labels,\n icons,\n className,\n },\n ref,\n ) {\n const [query, setQuery] = React.useState('')\n const [editingId, setEditingId] = React.useState<string | null>(null)\n const [draftTitle, setDraftTitle] = React.useState('')\n const NewIcon = icons?.newChat ?? MessageSquarePlus\n const RenameIcon = icons?.rename ?? Pencil\n const DeleteIcon = icons?.delete ?? Trash2\n const ExportIcon = icons?.export ?? Download\n\n const filtered = React.useMemo(() => {\n const trimmed = query.trim()\n if (trimmed === '') {\n return sessions\n }\n return sessions\n .map((session) => ({\n session,\n score: searchScore(trimmed, session.title),\n }))\n .filter((entry) => entry.score !== null)\n .sort((a, b) => (b.score ?? 0) - (a.score ?? 0))\n .map((entry) => entry.session)\n }, [sessions, query])\n\n const groups = React.useMemo(() => {\n if (!groupByDate) {\n return [{ key: 'all', label: null as string | null, sessions: filtered }]\n }\n const ordered = [...filtered].sort((a, b) => {\n const dateA = toDate(a.updatedAt)?.getTime() ?? 0\n const dateB = toDate(b.updatedAt)?.getTime() ?? 0\n return dateB - dateA\n })\n const byBucket = new Map<string, ChatSessionView[]>()\n for (const session of ordered) {\n const bucket = bucketOf(toDate(session.updatedAt))\n const list = byBucket.get(bucket) ?? []\n list.push(session)\n byBucket.set(bucket, list)\n }\n const order = ['today', 'yesterday', 'earlier', 'none']\n return order\n .filter((bucket) => byBucket.has(bucket))\n .map((bucket) => ({\n key: bucket,\n label:\n bucket === 'today'\n ? (labels?.today ?? 'Today')\n : bucket === 'yesterday'\n ? (labels?.yesterday ?? 'Yesterday')\n : bucket === 'earlier'\n ? (labels?.earlier ?? 'Earlier')\n : null,\n sessions: byBucket.get(bucket) ?? [],\n }))\n }, [filtered, groupByDate, labels])\n\n return (\n <div ref={ref} data-as=\"chat-session-list\" className={cn('flex h-full min-h-0 w-full flex-col gap-2', className)}>\n <div className=\"flex items-center gap-2\">\n {searchable ? (\n <div className=\"relative min-w-0 flex-1\">\n <Search className=\"pointer-events-none absolute start-2 top-1/2 size-3.5 -translate-y-1/2 text-[var(--as-muted-fg)]\" aria-hidden />\n <input\n type=\"search\"\n role=\"searchbox\"\n value={query}\n aria-label={labels?.search ?? 'Search conversations'}\n placeholder={labels?.searchPlaceholder ?? 'Search…'}\n onChange={(event) => setQuery(event.target.value)}\n className=\"w-full rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] py-1.5 pe-2 ps-8 text-xs text-[var(--as-fg)] placeholder:text-[var(--as-muted-fg)] focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n />\n </div>\n ) : null}\n {onNew ? (\n <button\n type=\"button\"\n onClick={onNew}\n aria-label={labels?.newChat ?? 'New conversation'}\n title={labels?.newChat ?? 'New conversation'}\n className=\"flex size-7 shrink-0 items-center justify-center rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] 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 >\n <NewIcon className=\"size-4\" aria-hidden />\n </button>\n ) : null}\n </div>\n {sessions.length === 0 ? (\n <p className=\"px-2 py-3 text-xs text-[var(--as-muted-fg)]\">{labels?.empty ?? 'No conversations yet'}</p>\n ) : filtered.length === 0 ? (\n <p className=\"px-2 py-3 text-xs text-[var(--as-muted-fg)]\">{labels?.noResults ?? 'No matches'}</p>\n ) : (\n <div role=\"list\" aria-label={labels?.search ?? 'Conversations'} data-as=\"chat-session-rows\" className=\"min-h-0 flex-1 overflow-y-auto\">\n {groups.map((group) => (\n <div key={group.key} className=\"mb-2\">\n {group.label ? (\n <p className=\"px-2 pb-1 pt-2 text-[10px] font-semibold uppercase tracking-wide text-[var(--as-muted-fg)]\">\n {group.label}\n </p>\n ) : null}\n {group.sessions.map((session) => {\n const isActive = session.id === activeId\n const date = toDate(session.updatedAt)\n const isEditing = editingId === session.id\n const commitRename = () => {\n if (editingId !== null && draftTitle.trim() !== '') {\n onRenameCommit?.(editingId, draftTitle.trim())\n }\n setEditingId(null)\n }\n const actions =\n onRename || onRenameCommit || onDelete || onExport\n ? [\n onRename || onRenameCommit\n ? {\n key: 'rename',\n label: labels?.rename ?? 'Rename',\n icon: <RenameIcon className=\"size-3.5\" aria-hidden />,\n onSelect: () => {\n if (onRenameCommit !== undefined) {\n setEditingId(session.id)\n setDraftTitle(session.title)\n } else {\n onRename?.(session.id)\n }\n },\n }\n : null,\n onExport\n ? {\n key: 'export',\n label: labels?.export ?? 'Export',\n icon: <ExportIcon className=\"size-3.5\" aria-hidden />,\n onSelect: () => onExport(session.id),\n }\n : null,\n onDelete\n ? {\n key: 'delete',\n label: labels?.delete ?? 'Delete',\n icon: <DeleteIcon className=\"size-3.5\" aria-hidden />,\n onSelect: () => onDelete(session.id),\n danger: true,\n }\n : null,\n ].filter((item): item is NonNullable<typeof item> => item !== null)\n : []\n return (\n <div\n key={session.id}\n role=\"listitem\"\n aria-current={isActive ? 'true' : undefined}\n data-active={isActive || undefined}\n className={cn(\n 'group/session flex cursor-pointer items-center gap-2 rounded-[var(--as-radius)] px-2 py-1.5 text-xs transition-colors hover:bg-[var(--as-surface-raised)]',\n isActive && 'bg-[var(--as-surface-raised)] font-medium text-[var(--as-fg)]',\n )}\n onClick={() => onSelect(session.id)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n onSelect(session.id)\n }\n }}\n tabIndex={0}\n >\n {isEditing ? (\n <input\n autoFocus\n value={draftTitle}\n aria-label={labels?.renameInput ?? 'Conversation title'}\n onChange={(event) => setDraftTitle(event.target.value)}\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => {\n event.stopPropagation()\n if (event.key === 'Enter') {\n event.preventDefault()\n commitRename()\n } else if (event.key === 'Escape') {\n event.preventDefault()\n setEditingId(null)\n }\n }}\n onBlur={commitRename}\n className=\"min-w-0 flex-1 rounded-[var(--as-radius-sm)] border border-[var(--as-primary)] bg-[var(--as-surface)] px-1.5 py-0.5 text-xs text-[var(--as-fg)] focus-visible:outline-none\"\n />\n ) : (\n <span className=\"line-clamp-2 min-w-0 flex-1 text-[var(--as-fg)]\">{session.title}</span>\n )}\n {date ? (\n <span className=\"shrink-0 text-[10px] text-[var(--as-muted-fg)]\">\n {formatDistanceToNow(date, { addSuffix: true })}\n </span>\n ) : null}\n {actions.length > 0 ? (\n <span\n role=\"group\"\n aria-label={labels?.rename ?? 'Conversation actions'}\n className=\"flex shrink-0 items-center gap-0.5 opacity-0 transition-opacity focus-within:opacity-100 group-hover/session:opacity-100\"\n onClick={(event) => event.stopPropagation()}\n onKeyDown={(event) => event.stopPropagation()}\n >\n {actions.map((action) => (\n <button\n key={action.key}\n type=\"button\"\n aria-label={action.label}\n title={action.label}\n onClick={action.onSelect}\n className={cn(\n 'rounded-[var(--as-radius-sm)] p-1 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-surface)] hover:text-[var(--as-fg)] focus-visible:opacity-100 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]',\n action.danger && 'hover:text-[var(--as-danger)]',\n )}\n >\n {action.icon}\n </button>\n ))}\n </span>\n ) : null}\n </div>\n )\n })}\n </div>\n ))\n }\n </div>\n )}\n </div>\n )\n },\n)\n"]}
|
|
@@ -37,13 +37,22 @@ var semanticTokens = [
|
|
|
37
37
|
"--as-radius-sm",
|
|
38
38
|
"--as-radius",
|
|
39
39
|
"--as-radius-lg",
|
|
40
|
+
"--as-duration-fast",
|
|
41
|
+
"--as-duration-base",
|
|
42
|
+
"--as-duration-slow",
|
|
43
|
+
"--as-duration-spring",
|
|
44
|
+
"--as-ease-out",
|
|
45
|
+
"--as-ease-standard",
|
|
46
|
+
"--as-ease-spring",
|
|
40
47
|
"--as-font-sans",
|
|
41
48
|
"--as-font-mono",
|
|
49
|
+
"--as-scrollbar-thumb",
|
|
50
|
+
"--as-scrollbar-track",
|
|
42
51
|
"--as-shadow-1",
|
|
43
52
|
"--as-shadow-2",
|
|
44
53
|
"--as-shadow-3"
|
|
45
54
|
];
|
|
46
55
|
|
|
47
56
|
export { rawTokens, semanticTokens };
|
|
48
|
-
//# sourceMappingURL=chunk-
|
|
49
|
-
//# sourceMappingURL=chunk-
|
|
57
|
+
//# sourceMappingURL=chunk-5C2OLUDR.js.map
|
|
58
|
+
//# sourceMappingURL=chunk-5C2OLUDR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tokens/tokens.ts"],"names":[],"mappings":";AAAO,IAAM,SAAA,GAAY;AAAA,EACvB,aAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA,aAAA;AAAA,EACA,oBAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,aAAA;AAAA,EACA;AACF;AAEO,IAAM,cAAA,GAAiB;AAAA,EAC5B,cAAA;AAAA,EACA,iBAAA;AAAA,EACA,gBAAA;AAAA,EACA,mBAAA;AAAA,EACA,cAAA;AAAA,EACA,qBAAA;AAAA,EACA,aAAA;AAAA,EACA,SAAA;AAAA,EACA,YAAA;AAAA,EACA,eAAA;AAAA,EACA,iBAAA;AAAA,EACA,iBAAA;AAAA,EACA,gBAAA;AAAA,EACA,YAAA;AAAA,EACA,iBAAA;AAAA,EACA,cAAA;AAAA,EACA,cAAA;AAAA,EACA,gBAAA;AAAA,EACA,gBAAA;AAAA,EACA,aAAA;AAAA,EACA,gBAAA;AAAA,EACA,oBAAA;AAAA,EACA,oBAAA;AAAA,EACA,oBAAA;AAAA,EACA,sBAAA;AAAA,EACA,eAAA;AAAA,EACA,oBAAA;AAAA,EACA,kBAAA;AAAA,EACA,gBAAA;AAAA,EACA,gBAAA;AAAA,EACA,sBAAA;AAAA,EACA,sBAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA;AACF","file":"chunk-5C2OLUDR.js","sourcesContent":["export const rawTokens = [\n '--as-tone-0',\n '--as-tone-50',\n '--as-tone-100',\n '--as-tone-200',\n '--as-tone-300',\n '--as-tone-500',\n '--as-tone-700',\n '--as-tone-900',\n '--as-accent',\n '--as-accent-strong',\n '--as-success',\n '--as-warning',\n '--as-danger',\n '--as-ai',\n] as const\n\nexport const semanticTokens = [\n '--as-primary',\n '--as-primary-fg',\n '--as-secondary',\n '--as-secondary-fg',\n '--as-surface',\n '--as-surface-raised',\n '--as-border',\n '--as-fg',\n '--as-muted',\n '--as-muted-fg',\n '--as-success-fg',\n '--as-warning-fg',\n '--as-danger-fg',\n '--as-ai-fg',\n '--as-focus-ring',\n '--as-overlay',\n '--as-z-modal',\n '--as-z-popover',\n '--as-radius-sm',\n '--as-radius',\n '--as-radius-lg',\n '--as-duration-fast',\n '--as-duration-base',\n '--as-duration-slow',\n '--as-duration-spring',\n '--as-ease-out',\n '--as-ease-standard',\n '--as-ease-spring',\n '--as-font-sans',\n '--as-font-mono',\n '--as-scrollbar-thumb',\n '--as-scrollbar-track',\n '--as-shadow-1',\n '--as-shadow-2',\n '--as-shadow-3',\n] as const\n\nexport type RawTokenName = (typeof rawTokens)[number]\nexport type SemanticTokenName = (typeof semanticTokens)[number]\nexport type ThemeTokenName = SemanticTokenName | RawTokenName\nexport type ThemeTokens = Partial<Record<ThemeTokenName, string>>\n"]}
|
|
@@ -2,7 +2,7 @@ import { DetailValue } from './chunk-JVJA5BPB.js';
|
|
|
2
2
|
import { Spinner } from './chunk-SQHW7TYF.js';
|
|
3
3
|
import { cn } from './chunk-RVVXVTH3.js';
|
|
4
4
|
import * as React from 'react';
|
|
5
|
-
import { Wrench,
|
|
5
|
+
import { Wrench, TriangleAlert, ChevronDown } from 'lucide-react';
|
|
6
6
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
7
7
|
|
|
8
8
|
function formatDuration(ms) {
|
|
@@ -64,7 +64,8 @@ var ChatToolCard = React.forwardRef(
|
|
|
64
64
|
"data-as": "chat-tool-card",
|
|
65
65
|
"data-status": status,
|
|
66
66
|
className: cn(
|
|
67
|
-
"rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] text-xs",
|
|
67
|
+
"rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] text-xs transition-shadow",
|
|
68
|
+
status === "running" && "shadow-[inset_2px_0_0_var(--as-ai)]",
|
|
68
69
|
className
|
|
69
70
|
),
|
|
70
71
|
children: [
|
|
@@ -85,22 +86,34 @@ var ChatToolCard = React.forwardRef(
|
|
|
85
86
|
{
|
|
86
87
|
role: status === "running" ? "status" : void 0,
|
|
87
88
|
className: cn(
|
|
88
|
-
"flex shrink-0 items-center gap-1",
|
|
89
|
+
"as-anim-fade-swap flex shrink-0 items-center gap-1",
|
|
89
90
|
status === "done" && "text-[var(--as-success)]",
|
|
90
91
|
status === "failed" && "text-[var(--as-danger)]",
|
|
91
92
|
status === "running" && "text-[var(--as-muted-fg)]"
|
|
92
93
|
),
|
|
93
94
|
children: [
|
|
94
|
-
status === "running" ? /* @__PURE__ */ jsx(Spinner, { size: "sm" }) : status === "done" ? /* @__PURE__ */ jsx(
|
|
95
|
+
status === "running" ? /* @__PURE__ */ jsx(Spinner, { size: "sm" }) : status === "done" ? /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": true, className: "size-3.5", fill: "none", children: /* @__PURE__ */ jsx(
|
|
96
|
+
"path",
|
|
97
|
+
{
|
|
98
|
+
d: "M20 6 9 17l-5-5",
|
|
99
|
+
pathLength: 1,
|
|
100
|
+
className: "as-anim-check-draw",
|
|
101
|
+
stroke: "currentColor",
|
|
102
|
+
strokeWidth: 2,
|
|
103
|
+
strokeLinecap: "round",
|
|
104
|
+
strokeLinejoin: "round"
|
|
105
|
+
}
|
|
106
|
+
) }) : /* @__PURE__ */ jsx(TriangleAlert, { className: "size-3.5", "aria-hidden": true }),
|
|
95
107
|
/* @__PURE__ */ jsx("span", { className: "sr-only", children: statusLabel })
|
|
96
108
|
]
|
|
97
|
-
}
|
|
109
|
+
},
|
|
110
|
+
status
|
|
98
111
|
),
|
|
99
|
-
expandable ? /* @__PURE__ */ jsx(ChevronDown, { className: cn("size-3.5 shrink-0 text-[var(--as-muted-fg)] transition-transform", open && "rotate-180"), "aria-hidden": true }) : null
|
|
112
|
+
expandable ? /* @__PURE__ */ jsx(ChevronDown, { className: cn("size-3.5 shrink-0 text-[var(--as-muted-fg)] transition-transform duration-[var(--as-duration-base)] ease-[var(--as-ease-out)]", open && "rotate-180"), "aria-hidden": true }) : null
|
|
100
113
|
]
|
|
101
114
|
}
|
|
102
115
|
),
|
|
103
|
-
expandable
|
|
116
|
+
expandable ? /* @__PURE__ */ jsx("div", { id: regionId, "data-open": open, className: "as-collapse", children: /* @__PURE__ */ jsxs("div", { className: "as-collapse-inner flex flex-col gap-2 border-t border-[var(--as-border)] px-2.5 py-2", children: [
|
|
104
117
|
args ? /* @__PURE__ */ jsxs("div", { children: [
|
|
105
118
|
/* @__PURE__ */ jsx("p", { className: "mb-1 font-medium uppercase tracking-wide text-[var(--as-muted-fg)]", children: labels?.args ?? "Arguments" }),
|
|
106
119
|
/* @__PURE__ */ jsx(DetailValue, { text: args })
|
|
@@ -109,7 +122,7 @@ var ChatToolCard = React.forwardRef(
|
|
|
109
122
|
/* @__PURE__ */ jsx("p", { className: "mb-1 font-medium uppercase tracking-wide text-[var(--as-muted-fg)]", children: labels?.result ?? "Result" }),
|
|
110
123
|
renderResult ? renderResult(result ?? "") : /* @__PURE__ */ jsx(DetailValue, { text: result ?? "" })
|
|
111
124
|
] }) : null
|
|
112
|
-
] }) : null
|
|
125
|
+
] }) }) : null
|
|
113
126
|
]
|
|
114
127
|
}
|
|
115
128
|
);
|
|
@@ -117,5 +130,5 @@ var ChatToolCard = React.forwardRef(
|
|
|
117
130
|
);
|
|
118
131
|
|
|
119
132
|
export { ChatToolCard };
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
121
|
-
//# sourceMappingURL=chunk-
|
|
133
|
+
//# sourceMappingURL=chunk-EQPXM2R4.js.map
|
|
134
|
+
//# sourceMappingURL=chunk-EQPXM2R4.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-tool-card/ChatToolCard.tsx"],"names":["ChatToolCard"],"mappings":"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","file":"chunk-EQPXM2R4.js","sourcesContent":["import * as React from 'react'\nimport { ChevronDown, TriangleAlert, Wrench } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { Spinner } from '../spinner/Spinner'\nimport { DetailValue } from '../detail-value/DetailValue'\n\nexport interface ChatToolCardLabels {\n running: string\n done: string\n failed: string\n args: string\n result: string\n details: string\n}\n\nexport interface ChatToolCardProps {\n name: string\n /** Human title, e.g. \"Searching the job catalog\". */\n title?: string\n status: 'running' | 'done' | 'failed'\n /** Serialized arguments (JSON string or formatted text). */\n args?: string\n /** Serialized result. */\n result?: string\n /**\n * Custom result view (study's per-tool views, family plan 12 L2).\n * Called with the result string (possibly empty when the tool has no\n * serialized output); when absent the default `<pre>` pane renders.\n */\n renderResult?: (result: string) => React.ReactNode\n durationMs?: number\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n labels?: Partial<ChatToolCardLabels>\n icon?: LucideIcon\n className?: string\n}\n\nfunction formatDuration(ms: number): string {\n if (ms < 1000) {\n return `${Math.round(ms)} ms`\n }\n return `${(ms / 1000).toFixed(1)} s`\n}\n\n/**\n * Inline tool-call observation card (study's `ToolCallCard` + health's tool\n * chips, generalized): status, duration, expandable args/result. The\n * inspector stays app-side (health opens its own modal from `onOpenChange`\n * or wrapping markup).\n */\nexport const ChatToolCard = React.forwardRef<HTMLDivElement, ChatToolCardProps>(\n function ChatToolCard(\n {\n name,\n title,\n status,\n args,\n result,\n renderResult,\n durationMs,\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n labels,\n icon: Icon = Wrench,\n className,\n },\n ref,\n ) {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = openProp !== undefined\n const open = isControlled ? openProp : uncontrolledOpen\n const regionId = React.useId()\n const expandable = Boolean(args || result || renderResult)\n\n const toggle = () => {\n if (!expandable) {\n return\n }\n const next = !open\n if (!isControlled) {\n setUncontrolledOpen(next)\n }\n onOpenChange?.(next)\n }\n\n const onKeyDown: React.KeyboardEventHandler<HTMLButtonElement> = (event) => {\n if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault()\n toggle()\n }\n }\n\n const statusLabel =\n status === 'running' ? (labels?.running ?? 'Running') : status === 'done' ? (labels?.done ?? 'Done') : (labels?.failed ?? 'Failed')\n\n const Header = (expandable ? 'button' : 'div') as 'button'\n const headerProps: React.ComponentPropsWithoutRef<'button'> = expandable\n ? {\n type: 'button',\n 'aria-expanded': open,\n 'aria-controls': regionId,\n onClick: toggle,\n onKeyDown,\n }\n : {}\n\n return (\n <div\n ref={ref}\n data-as=\"chat-tool-card\"\n data-status={status}\n className={cn(\n 'rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] text-xs transition-shadow',\n status === 'running' && 'shadow-[inset_2px_0_0_var(--as-ai)]',\n className,\n )}\n >\n <Header\n {...headerProps}\n className=\"flex w-full items-center gap-2 px-2.5 py-1.5 text-left focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <Icon className=\"size-3.5 shrink-0 text-[var(--as-muted-fg)]\" aria-hidden />\n <span className=\"min-w-0 flex-1\">\n <span className=\"font-medium text-[var(--as-fg)]\">{title ?? name}</span>\n {title ? <span className=\"ml-1.5 font-mono text-[var(--as-muted-fg)]\">{name}</span> : null}\n </span>\n {durationMs !== undefined ? (\n <span className=\"shrink-0 tabular-nums text-[var(--as-muted-fg)]\">{formatDuration(durationMs)}</span>\n ) : null}\n <span\n key={status}\n role={status === 'running' ? 'status' : undefined}\n className={cn(\n 'as-anim-fade-swap flex shrink-0 items-center gap-1',\n status === 'done' && 'text-[var(--as-success)]',\n status === 'failed' && 'text-[var(--as-danger)]',\n status === 'running' && 'text-[var(--as-muted-fg)]',\n )}\n >\n {status === 'running' ? (\n <Spinner size=\"sm\" />\n ) : status === 'done' ? (\n <svg viewBox=\"0 0 24 24\" aria-hidden className=\"size-3.5\" fill=\"none\">\n <path\n d=\"M20 6 9 17l-5-5\"\n pathLength={1}\n className=\"as-anim-check-draw\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n ) : (\n <TriangleAlert className=\"size-3.5\" aria-hidden />\n )}\n <span className=\"sr-only\">{statusLabel}</span>\n </span>\n {expandable ? (\n <ChevronDown className={cn('size-3.5 shrink-0 text-[var(--as-muted-fg)] transition-transform duration-[var(--as-duration-base)] ease-[var(--as-ease-out)]', open && 'rotate-180')} aria-hidden />\n ) : null}\n </Header>\n {expandable ? (\n <div id={regionId} data-open={open} className=\"as-collapse\">\n <div className=\"as-collapse-inner flex flex-col gap-2 border-t border-[var(--as-border)] px-2.5 py-2\">\n {args ? (\n <div>\n <p className=\"mb-1 font-medium uppercase tracking-wide text-[var(--as-muted-fg)]\">{labels?.args ?? 'Arguments'}</p>\n <DetailValue text={args} />\n </div>\n ) : null}\n {result || renderResult ? (\n <div>\n <p className=\"mb-1 font-medium uppercase tracking-wide text-[var(--as-muted-fg)]\">{labels?.result ?? 'Result'}</p>\n {renderResult ? (\n renderResult(result ?? '')\n ) : (\n <DetailValue text={result ?? ''} />\n )}\n </div>\n ) : null}\n </div>\n </div>\n ) : null}\n </div>\n )\n },\n)\n"]}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { ChatTurnStatus } from './chunk-GIQZNEG5.js';
|
|
2
|
+
import { cn } from './chunk-RVVXVTH3.js';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var ChatPending = React.forwardRef(
|
|
7
|
+
function ChatPending2({ label = "thinking", startedAt, lines = 2, children, className }, ref) {
|
|
8
|
+
const count = Math.min(Math.max(Math.round(lines), 1), 6);
|
|
9
|
+
return /* @__PURE__ */ jsxs(
|
|
10
|
+
"div",
|
|
11
|
+
{
|
|
12
|
+
ref,
|
|
13
|
+
"data-as": "chat-pending",
|
|
14
|
+
className: cn("flex w-full max-w-[92%] flex-col gap-1.5", className),
|
|
15
|
+
children: [
|
|
16
|
+
/* @__PURE__ */ jsx(ChatTurnStatus, { label, startedAt }),
|
|
17
|
+
/* @__PURE__ */ jsx(
|
|
18
|
+
"div",
|
|
19
|
+
{
|
|
20
|
+
"aria-hidden": true,
|
|
21
|
+
className: "flex flex-col gap-2 rounded-[var(--as-radius)] rounded-bl-[var(--as-radius-sm)] border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-2.5 shadow-[inset_2px_0_0_var(--as-ai)]",
|
|
22
|
+
children: Array.from({ length: count }, (_, index) => /* @__PURE__ */ jsx(
|
|
23
|
+
"div",
|
|
24
|
+
{
|
|
25
|
+
className: cn(
|
|
26
|
+
"as-anim-shimmer h-3.5 rounded-[var(--as-radius-sm)] bg-[var(--as-muted)]",
|
|
27
|
+
index === count - 1 && count > 1 && "w-3/5"
|
|
28
|
+
)
|
|
29
|
+
},
|
|
30
|
+
index
|
|
31
|
+
))
|
|
32
|
+
}
|
|
33
|
+
),
|
|
34
|
+
children
|
|
35
|
+
]
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
export { ChatPending };
|
|
42
|
+
//# sourceMappingURL=chunk-F4BTJQLK.js.map
|
|
43
|
+
//# sourceMappingURL=chunk-F4BTJQLK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-pending/ChatPending.tsx"],"names":["ChatPending"],"mappings":";;;;;AA0BO,IAAM,WAAA,GAAoB,KAAA,CAAA,UAAA;AAAA,EAC/B,SAASA,YAAAA,CAAY,EAAE,KAAA,GAAQ,UAAA,EAAY,SAAA,EAAW,KAAA,GAAQ,CAAA,EAAG,QAAA,EAAU,SAAA,EAAU,EAAG,GAAA,EAAK;AAC3F,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,KAAA,CAAM,KAAK,CAAA,EAAG,CAAC,CAAA,EAAG,CAAC,CAAA;AACxD,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,SAAA,EAAQ,cAAA;AAAA,QACR,SAAA,EAAW,EAAA,CAAG,0CAAA,EAA4C,SAAS,CAAA;AAAA,QAEnE,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,cAAA,EAAA,EAAe,OAAc,SAAA,EAAsB,CAAA;AAAA,0BACpD,GAAA;AAAA,YAAC,KAAA;AAAA,YAAA;AAAA,cACC,aAAA,EAAW,IAAA;AAAA,cACX,SAAA,EAAU,yLAAA;AAAA,cAET,QAAA,EAAA,KAAA,CAAM,KAAK,EAAE,MAAA,EAAQ,OAAM,EAAG,CAAC,GAAG,KAAA,qBACjC,GAAA;AAAA,gBAAC,KAAA;AAAA,gBAAA;AAAA,kBAEC,SAAA,EAAW,EAAA;AAAA,oBACT,0EAAA;AAAA,oBACA,KAAA,KAAU,KAAA,GAAQ,CAAA,IAAK,KAAA,GAAQ,CAAA,IAAK;AAAA;AACtC,iBAAA;AAAA,gBAJK;AAAA,eAMR;AAAA;AAAA,WACH;AAAA,UACC;AAAA;AAAA;AAAA,KACH;AAAA,EAEJ;AACF","file":"chunk-F4BTJQLK.js","sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../../lib/utils'\nimport { ChatTurnStatus } from '../chat-turn-status/ChatTurnStatus'\n\nexport interface ChatPendingProps {\n /**\n * Phase label narrated while the first token is awaited, e.g.\n * \"thinking\" — usually the live turn's current node label.\n */\n label?: string\n /** Turn start timestamp (ms) — enables the elapsed timer. */\n startedAt?: number\n /** Placeholder line count. Default 2 (capped at 6). */\n lines?: number\n /** Extra node under the placeholder (model badge, app hints). */\n children?: React.ReactNode\n className?: string\n}\n\n/**\n * The first-token latency placeholder (plan 100 S2): narrated phase row\n * (dots + elapsed timer via `ChatTurnStatus`) over an assistant-aligned\n * shimmer placeholder tinted with the `--as-ai` accent. Render it as the\n * transcript's `live` tail between send and the first delta.\n */\nexport const ChatPending = React.forwardRef<HTMLDivElement, ChatPendingProps>(\n function ChatPending({ label = 'thinking', startedAt, lines = 2, children, className }, ref) {\n const count = Math.min(Math.max(Math.round(lines), 1), 6)\n return (\n <div\n ref={ref}\n data-as=\"chat-pending\"\n className={cn('flex w-full max-w-[92%] flex-col gap-1.5', className)}\n >\n <ChatTurnStatus label={label} startedAt={startedAt} />\n <div\n aria-hidden\n className=\"flex flex-col gap-2 rounded-[var(--as-radius)] rounded-bl-[var(--as-radius-sm)] border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-2.5 shadow-[inset_2px_0_0_var(--as-ai)]\"\n >\n {Array.from({ length: count }, (_, index) => (\n <div\n key={index}\n className={cn(\n 'as-anim-shimmer h-3.5 rounded-[var(--as-radius-sm)] bg-[var(--as-muted)]',\n index === count - 1 && count > 1 && 'w-3/5',\n )}\n />\n ))}\n </div>\n {children}\n </div>\n )\n },\n)\n"]}
|
|
@@ -43,7 +43,7 @@ var ChatTurnStatus = React.forwardRef(
|
|
|
43
43
|
},
|
|
44
44
|
index
|
|
45
45
|
)) }),
|
|
46
|
-
/* @__PURE__ */ jsx("span", { className: "text-xs", children: label }),
|
|
46
|
+
/* @__PURE__ */ jsx("span", { className: "as-anim-fade-swap text-xs", children: label }, label),
|
|
47
47
|
elapsed !== null ? /* @__PURE__ */ jsx("span", { "aria-hidden": true, className: "font-mono text-[10px] tabular-nums", children: formatElapsed(elapsed) }) : null,
|
|
48
48
|
labels?.timer ? /* @__PURE__ */ jsx("span", { className: "sr-only", children: labels.timer }) : null
|
|
49
49
|
]
|
|
@@ -53,5 +53,5 @@ var ChatTurnStatus = React.forwardRef(
|
|
|
53
53
|
);
|
|
54
54
|
|
|
55
55
|
export { ChatTurnStatus };
|
|
56
|
-
//# sourceMappingURL=chunk-
|
|
57
|
-
//# sourceMappingURL=chunk-
|
|
56
|
+
//# sourceMappingURL=chunk-GIQZNEG5.js.map
|
|
57
|
+
//# sourceMappingURL=chunk-GIQZNEG5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-turn-status/ChatTurnStatus.tsx"],"names":["ChatTurnStatus"],"mappings":";;;;AAqBA,SAAS,cAAc,EAAA,EAAoB;AACzC,EAAA,IAAI,KAAK,GAAA,EAAM;AACb,IAAA,OAAO,CAAA,EAAG,KAAK,GAAA,CAAI,CAAA,EAAG,KAAK,KAAA,CAAM,EAAE,CAAC,CAAC,CAAA,GAAA,CAAA;AAAA,EACvC;AACA,EAAA,OAAO,CAAA,EAAA,CAAI,KAAK,GAAA,EAAM,OAAA,CAAQ,KAAK,GAAA,GAAQ,CAAA,GAAI,CAAC,CAAC,CAAA,EAAA,CAAA;AACnD;AAQO,IAAM,cAAA,GAAuB,KAAA,CAAA,UAAA;AAAA,EAClC,SAASA,eAAAA,CACP,EAAE,KAAA,EAAO,SAAA,EAAW,OAAA,GAAU,KAAA,EAAO,MAAA,GAAS,GAAA,EAAK,MAAA,EAAQ,SAAA,EAAU,EACrE,GAAA,EACA;AACA,IAAA,MAAM,CAAC,KAAK,MAAM,CAAA,GAAU,eAAS,MAAM,IAAA,CAAK,KAAK,CAAA;AAErD,IAAM,gBAAU,MAAM;AACpB,MAAA,IAAI,cAAc,MAAA,EAAW;AAC3B,QAAA;AAAA,MACF;AACA,MAAA,MAAA,CAAO,IAAA,CAAK,KAAK,CAAA;AACjB,MAAA,MAAM,EAAA,GAAK,OAAO,WAAA,CAAY,MAAM,OAAO,IAAA,CAAK,GAAA,EAAK,CAAA,EAAG,MAAM,CAAA;AAC9D,MAAA,OAAO,MAAM,MAAA,CAAO,aAAA,CAAc,EAAE,CAAA;AAAA,IACtC,CAAA,EAAG,CAAC,SAAA,EAAW,MAAM,CAAC,CAAA;AAEtB,IAAA,MAAM,OAAA,GAAU,cAAc,MAAA,GAAY,IAAA,GAAO,KAAK,GAAA,CAAI,CAAA,EAAG,MAAM,SAAS,CAAA;AAE5E,IAAA,uBACE,IAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,GAAA;AAAA,QACA,IAAA,EAAK,QAAA;AAAA,QACL,YAAA,EAAY,KAAA;AAAA,QACZ,SAAA,EAAQ,kBAAA;AAAA,QACR,cAAA,EAAc,OAAA;AAAA,QACd,SAAA,EAAW,EAAA;AAAA,UACT,mDAAA;AAAA,UACA,YAAY,MAAA,IACV,uGAAA;AAAA,UACF,YAAY,KAAA,IAAS,aAAA;AAAA,UACrB;AAAA,SACF;AAAA,QAEA,QAAA,EAAA;AAAA,0BAAA,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAW,IAAA,EAAC,SAAA,EAAU,yBAAA,EACzB,QAAA,EAAA,CAAC,CAAA,EAAG,CAAA,EAAG,CAAC,CAAA,CAAE,GAAA,CAAI,CAAC,KAAA,qBACd,GAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cAEC,SAAA,EAAU,sDAAA;AAAA,cACV,OAAO,EAAE,cAAA,EAAgB,CAAA,EAAG,KAAA,GAAQ,IAAI,CAAA,CAAA,CAAA;AAAI,aAAA;AAAA,YAFvC;AAAA,WAIR,CAAA,EACH,CAAA;AAAA,0BACA,GAAA,CAAC,MAAA,EAAA,EAAiB,SAAA,EAAU,2BAAA,EAA6B,mBAA9C,KAAoD,CAAA;AAAA,UAC9D,OAAA,KAAY,IAAA,mBACX,GAAA,CAAC,MAAA,EAAA,EAAK,aAAA,EAAW,IAAA,EAAC,SAAA,EAAU,oCAAA,EACzB,QAAA,EAAA,aAAA,CAAc,OAAO,CAAA,EACxB,CAAA,GACE,IAAA;AAAA,UACH,MAAA,EAAQ,wBAAQ,GAAA,CAAC,MAAA,EAAA,EAAK,WAAU,SAAA,EAAW,QAAA,EAAA,MAAA,CAAO,OAAM,CAAA,GAAU;AAAA;AAAA;AAAA,KACrE;AAAA,EAEJ;AACF","file":"chunk-GIQZNEG5.js","sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../../lib/utils'\n\nexport interface ChatTurnStatusLabels {\n timer: string\n}\n\nexport interface ChatTurnStatusProps {\n /** Current turn phase, e.g. \"searching the catalog\". */\n label: string\n /** Turn start timestamp (ms). Presence enables the elapsed timer. */\n startedAt?: number\n /** `row` = inline pre-text line; `card` = soft surface block. */\n variant?: 'row' | 'card'\n /** Elapsed-timer refresh interval. Default 100 ms (study-proven). */\n tickMs?: number\n labels?: Partial<ChatTurnStatusLabels>\n className?: string\n}\n\nfunction formatElapsed(ms: number): string {\n if (ms < 1000) {\n return `${Math.max(0, Math.round(ms))} ms`\n }\n return `${(ms / 1000).toFixed(ms < 10000 ? 1 : 0)} s`\n}\n\n/**\n * Live pre-text turn status (study's `TurnTraceStatus` + `ThinkingDots`,\n * generalized for family plan 12 L1): animated dots + phase label, with\n * an optional elapsed timer. Presentational and controlled — the turn\n * state itself lives in `useChatStream`; this only narrates it.\n */\nexport const ChatTurnStatus = React.forwardRef<HTMLDivElement, ChatTurnStatusProps>(\n function ChatTurnStatus(\n { label, startedAt, variant = 'row', tickMs = 100, labels, className },\n ref,\n ) {\n const [now, setNow] = React.useState(() => Date.now())\n\n React.useEffect(() => {\n if (startedAt === undefined) {\n return\n }\n setNow(Date.now())\n const id = window.setInterval(() => setNow(Date.now()), tickMs)\n return () => window.clearInterval(id)\n }, [startedAt, tickMs])\n\n const elapsed = startedAt === undefined ? null : Math.max(0, now - startedAt)\n\n return (\n <div\n ref={ref}\n role=\"status\"\n aria-label={label}\n data-as=\"chat-turn-status\"\n data-variant={variant}\n className={cn(\n 'flex items-center gap-2 text-[var(--as-muted-fg)]',\n variant === 'card' &&\n 'rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface-raised)] px-3 py-2.5',\n variant === 'row' && 'px-1 py-0.5',\n className,\n )}\n >\n <span aria-hidden className=\"flex items-center gap-1\">\n {[0, 1, 2].map((index) => (\n <span\n key={index}\n className=\"as-dot size-1.5 rounded-full bg-[var(--as-muted-fg)]\"\n style={{ animationDelay: `${index * 0.16}s` }}\n />\n ))}\n </span>\n <span key={label} className=\"as-anim-fade-swap text-xs\">{label}</span>\n {elapsed !== null ? (\n <span aria-hidden className=\"font-mono text-[10px] tabular-nums\">\n {formatElapsed(elapsed)}\n </span>\n ) : null}\n {labels?.timer ? <span className=\"sr-only\">{labels.timer}</span> : null}\n </div>\n )\n },\n)\n"]}
|
|
@@ -25,6 +25,12 @@ var ChatLauncher = React.forwardRef(
|
|
|
25
25
|
const isControlled = openProp !== void 0;
|
|
26
26
|
const open = isControlled ? openProp : uncontrolledOpen;
|
|
27
27
|
const panelRef = React.useRef(null);
|
|
28
|
+
const prevOpenRef = React.useRef(open);
|
|
29
|
+
const [morphed, setMorphed] = React.useState(false);
|
|
30
|
+
if (prevOpenRef.current !== open) {
|
|
31
|
+
prevOpenRef.current = open;
|
|
32
|
+
setMorphed(true);
|
|
33
|
+
}
|
|
28
34
|
const setOpen = (next) => {
|
|
29
35
|
if (!isControlled) {
|
|
30
36
|
setUncontrolledOpen(next);
|
|
@@ -89,8 +95,15 @@ var ChatLauncher = React.forwardRef(
|
|
|
89
95
|
className
|
|
90
96
|
),
|
|
91
97
|
children: [
|
|
92
|
-
/* @__PURE__ */ jsx(Icon, { className: "size-5", "aria-hidden": true }),
|
|
93
|
-
showBadge ? /* @__PURE__ */ jsx(
|
|
98
|
+
open ? /* @__PURE__ */ jsx(CloseIcon, { className: "as-anim-morph-in size-5", "aria-hidden": true }) : /* @__PURE__ */ jsx(Icon, { className: cn("size-5", morphed && "as-anim-morph-in"), "aria-hidden": true }),
|
|
99
|
+
showBadge ? /* @__PURE__ */ jsx(
|
|
100
|
+
"span",
|
|
101
|
+
{
|
|
102
|
+
className: "as-anim-pulse-once [--as-pulse-color:var(--as-danger)] absolute -right-0.5 -top-0.5 flex h-5 min-w-5 items-center justify-center rounded-full border-2 border-[var(--as-surface)] bg-[var(--as-danger)] px-1 text-[10px] font-semibold text-[var(--as-danger-fg)]",
|
|
103
|
+
children: badge
|
|
104
|
+
},
|
|
105
|
+
String(badge)
|
|
106
|
+
) : null
|
|
94
107
|
]
|
|
95
108
|
}
|
|
96
109
|
)
|
|
@@ -99,5 +112,5 @@ var ChatLauncher = React.forwardRef(
|
|
|
99
112
|
);
|
|
100
113
|
|
|
101
114
|
export { ChatLauncher };
|
|
102
|
-
//# sourceMappingURL=chunk-
|
|
103
|
-
//# sourceMappingURL=chunk-
|
|
115
|
+
//# sourceMappingURL=chunk-GO4ILLS6.js.map
|
|
116
|
+
//# sourceMappingURL=chunk-GO4ILLS6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/chat-launcher/ChatLauncher.tsx"],"names":["ChatLauncher"],"mappings":"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","file":"chunk-GO4ILLS6.js","sourcesContent":["import * as React from 'react'\nimport { MessageCircle, X } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { Portal } from '../portal/Portal'\n\nexport interface ChatLauncherProps {\n /** The anchored panel body — usually `ChatPanel variant=\"bubble\"`. */\n panel: React.ReactNode\n open?: boolean\n defaultOpen?: boolean\n onOpenChange?: (open: boolean) => void\n position?: 'bottom-right' | 'bottom-left'\n label?: string\n closeLabel?: string\n icon?: LucideIcon\n closeIcon?: LucideIcon\n /** Unread / activity badge. */\n badge?: number | string\n /**\n * Render the floating close button pinned to the panel's top-right\n * corner (default). Turn this off when the panel body renders its own\n * header actions — an overlaid close intercepts clicks meant for\n * top-right header buttons; compose the close into those actions\n * (calling `onOpenChange(false)`) instead.\n */\n showClose?: boolean\n container?: HTMLElement | null\n panelClassName?: string\n className?: string\n}\n\n/**\n * The floating chat bubble (career's `ChatWidget` launcher,\n * family-standard): fixed launcher button opening an anchored, non-modal\n * panel. `aria-expanded` wiring, Escape closes while focus is inside.\n */\nexport const ChatLauncher = React.forwardRef<HTMLButtonElement, ChatLauncherProps>(\n function ChatLauncher(\n {\n panel,\n open: openProp,\n defaultOpen = false,\n onOpenChange,\n position = 'bottom-right',\n label = 'Chat',\n closeLabel = 'Close chat',\n icon: Icon = MessageCircle,\n closeIcon: CloseIcon = X,\n badge,\n showClose = true,\n container,\n panelClassName,\n className,\n },\n ref,\n ) {\n const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen)\n const isControlled = openProp !== undefined\n const open = isControlled ? openProp : uncontrolledOpen\n const panelRef = React.useRef<HTMLDivElement | null>(null)\n const prevOpenRef = React.useRef(open)\n const [morphed, setMorphed] = React.useState(false)\n if (prevOpenRef.current !== open) {\n prevOpenRef.current = open\n setMorphed(true)\n }\n\n const setOpen = (next: boolean) => {\n if (!isControlled) {\n setUncontrolledOpen(next)\n }\n onOpenChange?.(next)\n }\n\n React.useEffect(() => {\n if (!open) {\n return\n }\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && panelRef.current?.contains(document.activeElement)) {\n setOpen(false)\n }\n }\n document.addEventListener('keydown', onKeyDown)\n return () => document.removeEventListener('keydown', onKeyDown)\n })\n\n const showBadge = badge !== undefined && badge !== 0 && badge !== ''\n\n return (\n <>\n {open ? (\n <Portal container={container}>\n <div\n ref={panelRef}\n data-as=\"chat-launcher-panel\"\n className={cn(\n 'as-anim-pop fixed bottom-20 z-[var(--as-z-modal)] flex h-[min(36rem,calc(100dvh-11rem))] w-[min(26rem,calc(100vw-2rem))] flex-col overflow-hidden rounded-[var(--as-radius-lg)] border border-[var(--as-border)] bg-[var(--as-surface)] text-[var(--as-fg)] shadow-[var(--as-shadow-3)]',\n position === 'bottom-right' ? 'right-4' : 'left-4',\n panelClassName,\n )}\n role=\"complementary\"\n aria-label={label}\n >\n {panel}\n {showClose ? (\n <button\n type=\"button\"\n aria-label={closeLabel}\n onClick={() => setOpen(false)}\n className=\"absolute right-2 top-2 z-10 rounded-[var(--as-radius-sm)] p-1 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-secondary)] hover:text-[var(--as-fg)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <CloseIcon aria-hidden className=\"size-4\" />\n </button>\n ) : null}\n </div>\n </Portal>\n ) : null}\n <button\n ref={ref}\n type=\"button\"\n aria-expanded={open}\n aria-label={open ? closeLabel : label}\n title={open ? closeLabel : label}\n onClick={() => setOpen(!open)}\n data-as=\"chat-launcher\"\n data-open={open || undefined}\n className={cn(\n 'fixed bottom-4 z-[var(--as-z-popover)] flex size-12 items-center justify-center rounded-full bg-[var(--as-primary)] text-[var(--as-primary-fg)] shadow-[var(--as-shadow-2)] transition-transform hover:scale-105 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]',\n position === 'bottom-right' ? 'right-4' : 'left-4',\n className,\n )}\n >\n {open ? (\n <CloseIcon className=\"as-anim-morph-in size-5\" aria-hidden />\n ) : (\n <Icon className={cn('size-5', morphed && 'as-anim-morph-in')} aria-hidden />\n )}\n {showBadge ? (\n <span\n key={String(badge)}\n className=\"as-anim-pulse-once [--as-pulse-color:var(--as-danger)] absolute -right-0.5 -top-0.5 flex h-5 min-w-5 items-center justify-center rounded-full border-2 border-[var(--as-surface)] bg-[var(--as-danger)] px-1 text-[10px] font-semibold text-[var(--as-danger-fg)]\"\n >\n {badge}\n </span>\n ) : null}\n </button>\n </>\n )\n },\n)\n"]}
|