@neuronection/assistant-ui 0.47.0 → 0.48.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 +20 -0
- package/dist/chat-message.d.ts +6 -0
- package/dist/chat-message.js +1 -1
- package/dist/chat-transcript.js +1 -1
- package/dist/{chunk-EAJU4LFG.js → chunk-C5JZCCU7.js} +6 -3
- package/dist/chunk-C5JZCCU7.js.map +1 -0
- package/dist/{chunk-AIFKK377.js → chunk-CYK3ZLAB.js} +14 -10
- package/dist/chunk-CYK3ZLAB.js.map +1 -0
- package/dist/chunk-WY5TO6R4.js +415 -0
- package/dist/chunk-WY5TO6R4.js.map +1 -0
- package/dist/{chunk-MTFHU6QY.js → chunk-XOODPYJ3.js} +3 -3
- package/dist/{chunk-MTFHU6QY.js.map → chunk-XOODPYJ3.js.map} +1 -1
- package/dist/index.d.ts +13 -5
- package/dist/index.js +4 -4
- package/dist/profile-switcher.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/user-menu.d.ts +7 -5
- package/dist/user-menu.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-AIFKK377.js.map +0 -1
- package/dist/chunk-C5OAZ2AW.js +0 -303
- package/dist/chunk-C5OAZ2AW.js.map +0 -1
- package/dist/chunk-EAJU4LFG.js.map +0 -1
package/dist/chunk-C5OAZ2AW.js
DELETED
|
@@ -1,303 +0,0 @@
|
|
|
1
|
-
import { Input } from './chunk-GQDW6BBO.js';
|
|
2
|
-
import { Popover, PopoverTrigger, PopoverContent } from './chunk-VX3EQRSM.js';
|
|
3
|
-
import { Button } from './chunk-4WBBF5LH.js';
|
|
4
|
-
import { cn } from './chunk-RVVXVTH3.js';
|
|
5
|
-
import * as React from 'react';
|
|
6
|
-
import { UserRound, Check, Pencil, Star, Trash2, Plus } from 'lucide-react';
|
|
7
|
-
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
8
|
-
|
|
9
|
-
var defaultLabels = {
|
|
10
|
-
trigger: "Switch profile",
|
|
11
|
-
panelTitle: "Profiles",
|
|
12
|
-
currentBadge: "Current",
|
|
13
|
-
defaultBadge: "Default",
|
|
14
|
-
newProfile: "New profile",
|
|
15
|
-
newProfilePlaceholder: "Profile name",
|
|
16
|
-
create: "Create",
|
|
17
|
-
rename: (name) => `Rename ${name}`,
|
|
18
|
-
renamePlaceholder: "Profile name",
|
|
19
|
-
renameSubmit: "Save",
|
|
20
|
-
setDefault: (name) => `Make ${name} the default profile`,
|
|
21
|
-
delete: (name) => `Delete ${name}`,
|
|
22
|
-
cancel: "Cancel",
|
|
23
|
-
loading: "Loading profiles\u2026",
|
|
24
|
-
empty: "No profiles yet"
|
|
25
|
-
};
|
|
26
|
-
function ProfileAvatar({ profile }) {
|
|
27
|
-
const letter = (profile.name.trim()[0] ?? "?").toUpperCase();
|
|
28
|
-
return /* @__PURE__ */ jsx(
|
|
29
|
-
"span",
|
|
30
|
-
{
|
|
31
|
-
"aria-hidden": true,
|
|
32
|
-
className: "flex size-6 shrink-0 items-center justify-center rounded-full text-[10px] font-semibold",
|
|
33
|
-
style: profile.color ? { backgroundColor: `${profile.color}22`, color: profile.color } : {
|
|
34
|
-
backgroundColor: "var(--as-secondary)",
|
|
35
|
-
color: "var(--as-muted-fg)"
|
|
36
|
-
},
|
|
37
|
-
children: profile.color ? letter : /* @__PURE__ */ jsx(UserRound, { className: "size-3.5" })
|
|
38
|
-
}
|
|
39
|
-
);
|
|
40
|
-
}
|
|
41
|
-
var ProfileSwitcher = React.forwardRef(
|
|
42
|
-
function ProfileSwitcher2({
|
|
43
|
-
profiles,
|
|
44
|
-
currentId,
|
|
45
|
-
onSelect,
|
|
46
|
-
onCreate,
|
|
47
|
-
onRename,
|
|
48
|
-
onDelete,
|
|
49
|
-
onSetDefault,
|
|
50
|
-
loading = false,
|
|
51
|
-
error = null,
|
|
52
|
-
align = "start",
|
|
53
|
-
labels,
|
|
54
|
-
icons,
|
|
55
|
-
className
|
|
56
|
-
}, ref) {
|
|
57
|
-
const merged = { ...defaultLabels, ...labels };
|
|
58
|
-
const TriggerIcon = icons?.trigger ?? UserRound;
|
|
59
|
-
const CreateIcon = icons?.create ?? Plus;
|
|
60
|
-
const RenameIcon = icons?.rename ?? Pencil;
|
|
61
|
-
const SetDefaultIcon = icons?.setDefault ?? Star;
|
|
62
|
-
const DeleteIcon = icons?.delete ?? Trash2;
|
|
63
|
-
const EmptyIcon = icons?.empty ?? UserRound;
|
|
64
|
-
const [open, setOpen] = React.useState(false);
|
|
65
|
-
const [draftName, setDraftName] = React.useState("");
|
|
66
|
-
const [renamingId, setRenamingId] = React.useState(null);
|
|
67
|
-
const [renameDraft, setRenameDraft] = React.useState("");
|
|
68
|
-
const renameInputRef = React.useRef(null);
|
|
69
|
-
const current = profiles.find((profile) => profile.id === currentId) ?? profiles[0] ?? null;
|
|
70
|
-
const close = React.useCallback(() => {
|
|
71
|
-
setOpen(false);
|
|
72
|
-
setRenamingId(null);
|
|
73
|
-
setDraftName("");
|
|
74
|
-
}, []);
|
|
75
|
-
React.useEffect(() => {
|
|
76
|
-
if (renamingId !== null) {
|
|
77
|
-
renameInputRef.current?.focus();
|
|
78
|
-
renameInputRef.current?.select();
|
|
79
|
-
}
|
|
80
|
-
}, [renamingId]);
|
|
81
|
-
const startRename = (profile) => {
|
|
82
|
-
setRenamingId(profile.id);
|
|
83
|
-
setRenameDraft(profile.name);
|
|
84
|
-
};
|
|
85
|
-
const submitRename = async (profile) => {
|
|
86
|
-
const name = renameDraft.trim();
|
|
87
|
-
if (!name || name === profile.name) {
|
|
88
|
-
setRenamingId(null);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
await onRename(profile, name);
|
|
92
|
-
setRenamingId(null);
|
|
93
|
-
};
|
|
94
|
-
const submitCreate = async (event) => {
|
|
95
|
-
event.preventDefault();
|
|
96
|
-
const name = draftName.trim();
|
|
97
|
-
if (!name) return;
|
|
98
|
-
await onCreate(name);
|
|
99
|
-
setDraftName("");
|
|
100
|
-
};
|
|
101
|
-
return /* @__PURE__ */ jsx("div", { ref, "data-as": "profile-switcher", className: cn("inline-block", className), children: /* @__PURE__ */ jsxs(
|
|
102
|
-
Popover,
|
|
103
|
-
{
|
|
104
|
-
open,
|
|
105
|
-
onOpenChange: (next) => {
|
|
106
|
-
setOpen(next);
|
|
107
|
-
if (!next) {
|
|
108
|
-
setRenamingId(null);
|
|
109
|
-
setDraftName("");
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
children: [
|
|
113
|
-
/* @__PURE__ */ jsx(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs(
|
|
114
|
-
Button,
|
|
115
|
-
{
|
|
116
|
-
type: "button",
|
|
117
|
-
variant: "outline",
|
|
118
|
-
size: "sm",
|
|
119
|
-
"aria-haspopup": "dialog",
|
|
120
|
-
"aria-label": merged.trigger,
|
|
121
|
-
children: [
|
|
122
|
-
/* @__PURE__ */ jsx(TriggerIcon, { "aria-hidden": true }),
|
|
123
|
-
/* @__PURE__ */ jsx("span", { className: "max-w-32 truncate", children: current ? current.name : merged.empty })
|
|
124
|
-
]
|
|
125
|
-
}
|
|
126
|
-
) }),
|
|
127
|
-
/* @__PURE__ */ jsxs(
|
|
128
|
-
PopoverContent,
|
|
129
|
-
{
|
|
130
|
-
align,
|
|
131
|
-
role: "dialog",
|
|
132
|
-
"aria-label": merged.panelTitle,
|
|
133
|
-
className: "w-72 p-2",
|
|
134
|
-
onEscapeKeyDown: (event) => {
|
|
135
|
-
if (renamingId !== null) event.preventDefault();
|
|
136
|
-
},
|
|
137
|
-
children: [
|
|
138
|
-
/* @__PURE__ */ jsx("div", { className: "px-2 pb-1 pt-1 text-xs font-medium text-[var(--as-muted-fg)]", children: merged.panelTitle }),
|
|
139
|
-
loading ? /* @__PURE__ */ jsx("p", { className: "px-2 py-3 text-sm text-[var(--as-muted-fg)]", children: merged.loading }) : profiles.length === 0 ? /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 px-2 py-3 text-sm text-[var(--as-muted-fg)]", children: [
|
|
140
|
-
/* @__PURE__ */ jsx(EmptyIcon, { "aria-hidden": true }),
|
|
141
|
-
merged.empty
|
|
142
|
-
] }) : /* @__PURE__ */ jsx("ul", { className: "max-h-64 space-y-0.5 overflow-y-auto", children: profiles.map((profile) => {
|
|
143
|
-
const isCurrent = current !== null && profile.id === current.id;
|
|
144
|
-
return /* @__PURE__ */ jsx(
|
|
145
|
-
"li",
|
|
146
|
-
{
|
|
147
|
-
className: "group flex items-center gap-1 rounded-[var(--as-radius-sm)] px-1 py-0.5 hover:bg-[var(--as-secondary)]",
|
|
148
|
-
children: renamingId === profile.id ? /* @__PURE__ */ jsxs(
|
|
149
|
-
"form",
|
|
150
|
-
{
|
|
151
|
-
className: "flex w-full items-center gap-1",
|
|
152
|
-
onSubmit: (event) => {
|
|
153
|
-
event.preventDefault();
|
|
154
|
-
void submitRename(profile);
|
|
155
|
-
},
|
|
156
|
-
children: [
|
|
157
|
-
/* @__PURE__ */ jsx(
|
|
158
|
-
Input,
|
|
159
|
-
{
|
|
160
|
-
ref: renameInputRef,
|
|
161
|
-
"aria-label": merged.rename(profile.name),
|
|
162
|
-
placeholder: merged.renamePlaceholder,
|
|
163
|
-
value: renameDraft,
|
|
164
|
-
onChange: (event) => setRenameDraft(event.target.value),
|
|
165
|
-
onKeyDown: (event) => {
|
|
166
|
-
if (event.key === "Escape") {
|
|
167
|
-
event.preventDefault();
|
|
168
|
-
setRenamingId(null);
|
|
169
|
-
}
|
|
170
|
-
},
|
|
171
|
-
className: "h-7 flex-1"
|
|
172
|
-
}
|
|
173
|
-
),
|
|
174
|
-
/* @__PURE__ */ jsx(
|
|
175
|
-
Button,
|
|
176
|
-
{
|
|
177
|
-
type: "submit",
|
|
178
|
-
size: "sm",
|
|
179
|
-
disabled: !renameDraft.trim(),
|
|
180
|
-
"aria-label": merged.renameSubmit,
|
|
181
|
-
children: merged.renameSubmit
|
|
182
|
-
}
|
|
183
|
-
),
|
|
184
|
-
/* @__PURE__ */ jsx(
|
|
185
|
-
Button,
|
|
186
|
-
{
|
|
187
|
-
type: "button",
|
|
188
|
-
size: "sm",
|
|
189
|
-
variant: "ghost",
|
|
190
|
-
"aria-label": merged.cancel,
|
|
191
|
-
onClick: () => setRenamingId(null),
|
|
192
|
-
children: merged.cancel
|
|
193
|
-
}
|
|
194
|
-
)
|
|
195
|
-
]
|
|
196
|
-
}
|
|
197
|
-
) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
198
|
-
/* @__PURE__ */ jsxs(
|
|
199
|
-
"button",
|
|
200
|
-
{
|
|
201
|
-
type: "button",
|
|
202
|
-
"aria-current": isCurrent || void 0,
|
|
203
|
-
className: "flex min-w-0 flex-1 items-center gap-2 rounded-[var(--as-radius-sm)] px-1.5 py-1 text-left text-sm outline-none focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]",
|
|
204
|
-
onClick: () => {
|
|
205
|
-
onSelect(profile);
|
|
206
|
-
close();
|
|
207
|
-
},
|
|
208
|
-
children: [
|
|
209
|
-
/* @__PURE__ */ jsx(ProfileAvatar, { profile }),
|
|
210
|
-
/* @__PURE__ */ jsx("span", { className: "min-w-0 flex-1 truncate", children: profile.name }),
|
|
211
|
-
isCurrent ? /* @__PURE__ */ jsxs("span", { className: "inline-flex items-center gap-0.5 text-[10px] text-[var(--as-muted-fg)]", children: [
|
|
212
|
-
/* @__PURE__ */ jsx(Check, { "aria-hidden": true }),
|
|
213
|
-
merged.currentBadge
|
|
214
|
-
] }) : null,
|
|
215
|
-
profile.is_default ? /* @__PURE__ */ jsx("span", { className: "text-[10px] text-[var(--as-muted-fg)]", children: merged.defaultBadge }) : null
|
|
216
|
-
]
|
|
217
|
-
}
|
|
218
|
-
),
|
|
219
|
-
/* @__PURE__ */ jsx(
|
|
220
|
-
Button,
|
|
221
|
-
{
|
|
222
|
-
type: "button",
|
|
223
|
-
size: "sm",
|
|
224
|
-
variant: "ghost",
|
|
225
|
-
"aria-label": merged.rename(profile.name),
|
|
226
|
-
onClick: () => startRename(profile),
|
|
227
|
-
children: /* @__PURE__ */ jsx(RenameIcon, { "aria-hidden": true })
|
|
228
|
-
}
|
|
229
|
-
),
|
|
230
|
-
onSetDefault && !profile.is_default ? /* @__PURE__ */ jsx(
|
|
231
|
-
Button,
|
|
232
|
-
{
|
|
233
|
-
type: "button",
|
|
234
|
-
size: "sm",
|
|
235
|
-
variant: "ghost",
|
|
236
|
-
"aria-label": merged.setDefault(profile.name),
|
|
237
|
-
onClick: () => void onSetDefault(profile),
|
|
238
|
-
children: /* @__PURE__ */ jsx(SetDefaultIcon, { "aria-hidden": true })
|
|
239
|
-
}
|
|
240
|
-
) : null,
|
|
241
|
-
/* @__PURE__ */ jsx(
|
|
242
|
-
Button,
|
|
243
|
-
{
|
|
244
|
-
type: "button",
|
|
245
|
-
size: "sm",
|
|
246
|
-
variant: "ghost",
|
|
247
|
-
"aria-label": merged.delete(profile.name),
|
|
248
|
-
onClick: () => void onDelete(profile),
|
|
249
|
-
children: /* @__PURE__ */ jsx(DeleteIcon, { "aria-hidden": true })
|
|
250
|
-
}
|
|
251
|
-
)
|
|
252
|
-
] })
|
|
253
|
-
},
|
|
254
|
-
profile.id
|
|
255
|
-
);
|
|
256
|
-
}) }),
|
|
257
|
-
error ? /* @__PURE__ */ jsx("p", { role: "alert", className: "px-2 py-1 text-xs text-[var(--as-danger)]", children: error }) : null,
|
|
258
|
-
/* @__PURE__ */ jsxs(
|
|
259
|
-
"form",
|
|
260
|
-
{
|
|
261
|
-
className: "mt-2 flex items-center gap-1 border-t border-[var(--as-border)] pt-2",
|
|
262
|
-
onSubmit: (event) => {
|
|
263
|
-
void submitCreate(event);
|
|
264
|
-
},
|
|
265
|
-
children: [
|
|
266
|
-
/* @__PURE__ */ jsx(
|
|
267
|
-
Input,
|
|
268
|
-
{
|
|
269
|
-
"aria-label": merged.newProfile,
|
|
270
|
-
placeholder: merged.newProfilePlaceholder,
|
|
271
|
-
value: draftName,
|
|
272
|
-
onChange: (event) => setDraftName(event.target.value),
|
|
273
|
-
className: "h-7 flex-1"
|
|
274
|
-
}
|
|
275
|
-
),
|
|
276
|
-
/* @__PURE__ */ jsxs(
|
|
277
|
-
Button,
|
|
278
|
-
{
|
|
279
|
-
type: "submit",
|
|
280
|
-
size: "sm",
|
|
281
|
-
disabled: !draftName.trim(),
|
|
282
|
-
"aria-label": merged.create,
|
|
283
|
-
children: [
|
|
284
|
-
/* @__PURE__ */ jsx(CreateIcon, { "aria-hidden": true }),
|
|
285
|
-
merged.create
|
|
286
|
-
]
|
|
287
|
-
}
|
|
288
|
-
)
|
|
289
|
-
]
|
|
290
|
-
}
|
|
291
|
-
)
|
|
292
|
-
]
|
|
293
|
-
}
|
|
294
|
-
)
|
|
295
|
-
]
|
|
296
|
-
}
|
|
297
|
-
) });
|
|
298
|
-
}
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
export { ProfileSwitcher };
|
|
302
|
-
//# sourceMappingURL=chunk-C5OAZ2AW.js.map
|
|
303
|
-
//# sourceMappingURL=chunk-C5OAZ2AW.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/profile-switcher/ProfileSwitcher.tsx"],"names":["ProfileSwitcher"],"mappings":"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","file":"chunk-C5OAZ2AW.js","sourcesContent":["import * as React from 'react'\nimport {\n Check,\n Pencil,\n Plus,\n Star,\n Trash2,\n UserRound,\n type LucideIcon,\n} from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { Button } from '../button/Button'\nimport { Input } from '../input/Input'\nimport { Popover, PopoverContent, PopoverTrigger } from '../popover/Popover'\n\nexport interface ProfileItem {\n id: string\n name: string\n is_default?: boolean\n color?: string | null\n}\n\nexport interface ProfileSwitcherLabels {\n trigger: string\n panelTitle: string\n currentBadge: string\n defaultBadge: string\n newProfile: string\n newProfilePlaceholder: string\n create: string\n rename: (name: string) => string\n renamePlaceholder: string\n renameSubmit: string\n setDefault: (name: string) => string\n delete: (name: string) => string\n cancel: string\n loading: string\n empty: string\n}\n\nexport interface ProfileSwitcherIcons {\n trigger?: LucideIcon\n create?: LucideIcon\n rename?: LucideIcon\n setDefault?: LucideIcon\n delete?: LucideIcon\n empty?: LucideIcon\n}\n\nexport interface ProfileSwitcherProps {\n profiles: ProfileItem[]\n currentId: string | null\n onSelect: (profile: ProfileItem) => void\n onCreate: (name: string) => void | Promise<unknown>\n onRename: (profile: ProfileItem, name: string) => void | Promise<unknown>\n onDelete: (profile: ProfileItem) => void | Promise<unknown>\n /** When given, rows expose a \"make Default\" action (identity-auth §12). */\n onSetDefault?: (profile: ProfileItem) => void | Promise<unknown>\n loading?: boolean\n error?: string | null\n align?: 'start' | 'end'\n labels?: Partial<ProfileSwitcherLabels>\n icons?: ProfileSwitcherIcons\n className?: string\n}\n\nconst defaultLabels: ProfileSwitcherLabels = {\n trigger: 'Switch profile',\n panelTitle: 'Profiles',\n currentBadge: 'Current',\n defaultBadge: 'Default',\n newProfile: 'New profile',\n newProfilePlaceholder: 'Profile name',\n create: 'Create',\n rename: (name) => `Rename ${name}`,\n renamePlaceholder: 'Profile name',\n renameSubmit: 'Save',\n setDefault: (name) => `Make ${name} the default profile`,\n delete: (name) => `Delete ${name}`,\n cancel: 'Cancel',\n loading: 'Loading profiles…',\n empty: 'No profiles yet',\n}\n\nfunction ProfileAvatar({ profile }: { profile: ProfileItem }) {\n const letter = (profile.name.trim()[0] ?? '?').toUpperCase()\n return (\n <span\n aria-hidden\n className=\"flex size-6 shrink-0 items-center justify-center rounded-full text-[10px] font-semibold\"\n style={\n profile.color\n ? { backgroundColor: `${profile.color}22`, color: profile.color }\n : {\n backgroundColor: 'var(--as-secondary)',\n color: 'var(--as-muted-fg)',\n }\n }\n >\n {profile.color ? letter : <UserRound className=\"size-3.5\" />}\n </span>\n )\n}\n\nexport const ProfileSwitcher = React.forwardRef<HTMLDivElement, ProfileSwitcherProps>(\n function ProfileSwitcher(\n {\n profiles,\n currentId,\n onSelect,\n onCreate,\n onRename,\n onDelete,\n onSetDefault,\n loading = false,\n error = null,\n align = 'start',\n labels,\n icons,\n className,\n },\n ref,\n ) {\n const merged = { ...defaultLabels, ...labels }\n const TriggerIcon = icons?.trigger ?? UserRound\n const CreateIcon = icons?.create ?? Plus\n const RenameIcon = icons?.rename ?? Pencil\n const SetDefaultIcon = icons?.setDefault ?? Star\n const DeleteIcon = icons?.delete ?? Trash2\n const EmptyIcon = icons?.empty ?? UserRound\n\n const [open, setOpen] = React.useState(false)\n const [draftName, setDraftName] = React.useState('')\n const [renamingId, setRenamingId] = React.useState<string | null>(null)\n const [renameDraft, setRenameDraft] = React.useState('')\n const renameInputRef = React.useRef<HTMLInputElement>(null)\n\n const current = profiles.find((profile) => profile.id === currentId) ?? profiles[0] ?? null\n\n const close = React.useCallback(() => {\n setOpen(false)\n setRenamingId(null)\n setDraftName('')\n }, [])\n\n React.useEffect(() => {\n if (renamingId !== null) {\n renameInputRef.current?.focus()\n renameInputRef.current?.select()\n }\n }, [renamingId])\n\n const startRename = (profile: ProfileItem) => {\n setRenamingId(profile.id)\n setRenameDraft(profile.name)\n }\n\n const submitRename = async (profile: ProfileItem) => {\n const name = renameDraft.trim()\n if (!name || name === profile.name) {\n setRenamingId(null)\n return\n }\n await onRename(profile, name)\n setRenamingId(null)\n }\n\n const submitCreate = async (event: React.FormEvent) => {\n event.preventDefault()\n const name = draftName.trim()\n if (!name) return\n await onCreate(name)\n setDraftName('')\n }\n\n return (\n <div ref={ref} data-as=\"profile-switcher\" className={cn('inline-block', className)}>\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next)\n if (!next) {\n setRenamingId(null)\n setDraftName('')\n }\n }}\n >\n <PopoverTrigger asChild>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n aria-haspopup=\"dialog\"\n aria-label={merged.trigger}\n >\n <TriggerIcon aria-hidden />\n <span className=\"max-w-32 truncate\">{current ? current.name : merged.empty}</span>\n </Button>\n </PopoverTrigger>\n <PopoverContent\n align={align}\n role=\"dialog\"\n aria-label={merged.panelTitle}\n className=\"w-72 p-2\"\n onEscapeKeyDown={(event) => {\n // Escape cancels an inline rename first, closes the panel\n // only on the second press.\n if (renamingId !== null) event.preventDefault()\n }}\n >\n <div className=\"px-2 pb-1 pt-1 text-xs font-medium text-[var(--as-muted-fg)]\">\n {merged.panelTitle}\n </div>\n {loading ? (\n <p className=\"px-2 py-3 text-sm text-[var(--as-muted-fg)]\">{merged.loading}</p>\n ) : profiles.length === 0 ? (\n <p className=\"flex items-center gap-2 px-2 py-3 text-sm text-[var(--as-muted-fg)]\">\n <EmptyIcon aria-hidden />\n {merged.empty}\n </p>\n ) : (\n <ul className=\"max-h-64 space-y-0.5 overflow-y-auto\">\n {profiles.map((profile) => {\n const isCurrent = current !== null && profile.id === current.id\n return (\n <li\n key={profile.id}\n className=\"group flex items-center gap-1 rounded-[var(--as-radius-sm)] px-1 py-0.5 hover:bg-[var(--as-secondary)]\"\n >\n {renamingId === profile.id ? (\n <form\n className=\"flex w-full items-center gap-1\"\n onSubmit={(event) => {\n event.preventDefault()\n void submitRename(profile)\n }}\n >\n <Input\n ref={renameInputRef}\n aria-label={merged.rename(profile.name)}\n placeholder={merged.renamePlaceholder}\n value={renameDraft}\n onChange={(event) => setRenameDraft(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n setRenamingId(null)\n }\n }}\n className=\"h-7 flex-1\"\n />\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={!renameDraft.trim()}\n aria-label={merged.renameSubmit}\n >\n {merged.renameSubmit}\n </Button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n aria-label={merged.cancel}\n onClick={() => setRenamingId(null)}\n >\n {merged.cancel}\n </Button>\n </form>\n ) : (\n <>\n <button\n type=\"button\"\n aria-current={isCurrent || undefined}\n className=\"flex min-w-0 flex-1 items-center gap-2 rounded-[var(--as-radius-sm)] px-1.5 py-1 text-left text-sm outline-none focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n onClick={() => {\n onSelect(profile)\n close()\n }}\n >\n <ProfileAvatar profile={profile} />\n <span className=\"min-w-0 flex-1 truncate\">{profile.name}</span>\n {isCurrent ? (\n <span className=\"inline-flex items-center gap-0.5 text-[10px] text-[var(--as-muted-fg)]\">\n <Check aria-hidden />\n {merged.currentBadge}\n </span>\n ) : null}\n {profile.is_default ? (\n <span className=\"text-[10px] text-[var(--as-muted-fg)]\">\n {merged.defaultBadge}\n </span>\n ) : null}\n </button>\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n aria-label={merged.rename(profile.name)}\n onClick={() => startRename(profile)}\n >\n <RenameIcon aria-hidden />\n </Button>\n {onSetDefault && !profile.is_default ? (\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n aria-label={merged.setDefault(profile.name)}\n onClick={() => void onSetDefault(profile)}\n >\n <SetDefaultIcon aria-hidden />\n </Button>\n ) : null}\n <Button\n type=\"button\"\n size=\"sm\"\n variant=\"ghost\"\n aria-label={merged.delete(profile.name)}\n onClick={() => void onDelete(profile)}\n >\n <DeleteIcon aria-hidden />\n </Button>\n </>\n )}\n </li>\n )\n })}\n </ul>\n )}\n {error ? (\n <p role=\"alert\" className=\"px-2 py-1 text-xs text-[var(--as-danger)]\">\n {error}\n </p>\n ) : null}\n <form\n className=\"mt-2 flex items-center gap-1 border-t border-[var(--as-border)] pt-2\"\n onSubmit={(event) => {\n void submitCreate(event)\n }}\n >\n <Input\n aria-label={merged.newProfile}\n placeholder={merged.newProfilePlaceholder}\n value={draftName}\n onChange={(event) => setDraftName(event.target.value)}\n className=\"h-7 flex-1\"\n />\n <Button\n type=\"submit\"\n size=\"sm\"\n disabled={!draftName.trim()}\n aria-label={merged.create}\n >\n <CreateIcon aria-hidden />\n {merged.create}\n </Button>\n </form>\n </PopoverContent>\n </Popover>\n </div>\n )\n },\n)\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/chat-message/ChatMessageEditor.tsx","../src/components/chat-message/MessageVariantSwitcher.tsx","../src/components/chat-message/ChatMessage.tsx"],"names":["ChatMessageEditor","React2","MessageVariantSwitcher","jsxs","jsx","React3","ChatMessage"],"mappings":"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","file":"chunk-EAJU4LFG.js","sourcesContent":["import * as React from 'react'\n\nimport { cn } from '../../lib/utils'\nimport { Button } from '../button/Button'\n\nexport interface ChatMessageEditorLabels {\n save: string\n cancel: string\n ariaLabel: string\n}\n\nexport interface ChatMessageEditorProps {\n value: string\n onValueChange: (value: string) => void\n /** Save & resend — branches the tree (family `edit` endpoint) and reruns the turn. */\n onSubmit: () => void\n onCancel: () => void\n submitDisabled?: boolean\n rows?: number\n labels?: Partial<ChatMessageEditorLabels>\n className?: string\n}\n\n/**\n * Inline user-prompt editor for the edit-and-resend flow (study pattern):\n * controlled textarea, Cmd/Ctrl+Enter saves, Escape cancels.\n */\nexport const ChatMessageEditor = React.forwardRef<HTMLDivElement, ChatMessageEditorProps>(\n function ChatMessageEditor(\n { value, onValueChange, onSubmit, onCancel, submitDisabled = false, rows = 3, labels, className },\n ref,\n ) {\n const onKeyDown: React.KeyboardEventHandler<HTMLTextAreaElement> = (event) => {\n if (event.key === 'Escape') {\n event.preventDefault()\n onCancel()\n return\n }\n if (event.key === 'Enter' && (event.metaKey || event.ctrlKey)) {\n event.preventDefault()\n if (!submitDisabled) {\n onSubmit()\n }\n }\n }\n\n return (\n <div ref={ref} data-as=\"chat-message-editor\" className={cn('flex w-full flex-col gap-2', className)}>\n <textarea\n value={value}\n rows={rows}\n aria-label={labels?.ariaLabel ?? 'Edit message'}\n onChange={(event) => onValueChange(event.target.value)}\n onKeyDown={onKeyDown}\n className=\"w-full resize-y rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-2 text-sm text-[var(--as-fg)] placeholder:text-[var(--as-muted-fg)] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-[var(--as-focus-ring)]\"\n />\n <div className=\"flex items-center justify-end gap-2\">\n <Button variant=\"ghost\" size=\"sm\" onClick={onCancel}>\n {labels?.cancel ?? 'Cancel'}\n </Button>\n <Button size=\"sm\" disabled={submitDisabled} onClick={onSubmit}>\n {labels?.save ?? 'Save & resend'}\n </Button>\n </div>\n </div>\n )\n },\n)\n","import * as React from 'react'\nimport { ChevronLeft, ChevronRight } from 'lucide-react'\n\nimport type { ChatMessageVariants } from '../chat-core/types'\nimport { cn } from '../../lib/utils'\n\nexport interface MessageVariantSwitcherLabels {\n group: string\n variantOf: (index: number, count: number) => string\n previous: string\n next: string\n}\n\nexport interface MessageVariantSwitcherProps {\n variants: ChatMessageVariants\n /** Flip the parent's active-child pointer to the sibling id (family `select` endpoint). */\n onSelect: (messageId: string) => void\n labels?: Partial<MessageVariantSwitcherLabels>\n className?: string\n}\n\n/**\n * The `‹ n/N ›` sibling-variant switcher under a branched message\n * (study's inline switcher, family branching contract).\n */\nexport const MessageVariantSwitcher = React.forwardRef<HTMLDivElement, MessageVariantSwitcherProps>(\n function MessageVariantSwitcher({ variants, onSelect, labels, className }, ref) {\n const { index, count, siblingIds } = variants\n const previousId = index > 1 ? siblingIds[index - 2] : undefined\n const nextId = index < count ? siblingIds[index] : undefined\n\n const select = (event: React.MouseEvent<HTMLButtonElement>, messageId: string | undefined) => {\n event.stopPropagation()\n if (messageId !== undefined) {\n onSelect(messageId)\n }\n }\n\n return (\n <div\n ref={ref}\n role=\"group\"\n aria-label={labels?.group ?? 'Message variants'}\n data-as=\"message-variant-switcher\"\n className={cn('flex items-center gap-0.5 text-xs text-[var(--as-muted-fg)]', className)}\n >\n <button\n type=\"button\"\n disabled={previousId === undefined}\n aria-label={labels?.previous ?? 'Previous variant'}\n title={labels?.previous ?? 'Previous variant'}\n onClick={(event) => select(event, previousId)}\n className=\"rounded-[var(--as-radius-sm)] p-0.5 transition-colors hover:bg-[var(--as-surface-raised)] hover:text-[var(--as-fg)] disabled:pointer-events-none disabled:opacity-30 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <ChevronLeft className=\"size-3.5\" aria-hidden />\n </button>\n <span className=\"tabular-nums\" title={labels?.variantOf?.(index, count) ?? `Variant ${index} of ${count}`}>\n {index}/{count}\n </span>\n <button\n type=\"button\"\n disabled={nextId === undefined}\n aria-label={labels?.next ?? 'Next variant'}\n title={labels?.next ?? 'Next variant'}\n onClick={(event) => select(event, nextId)}\n className=\"rounded-[var(--as-radius-sm)] p-0.5 transition-colors hover:bg-[var(--as-surface-raised)] hover:text-[var(--as-fg)] disabled:pointer-events-none disabled:opacity-30 focus-visible:outline-2 focus-visible:outline-offset-1 focus-visible:outline-[var(--as-focus-ring)]\"\n >\n <ChevronRight className=\"size-3.5\" aria-hidden />\n </button>\n </div>\n )\n },\n)\n","import * as React from 'react'\nimport { Copy, Pencil, RotateCcw, TriangleAlert } from 'lucide-react'\nimport type { LucideIcon } from 'lucide-react'\n\nimport { cn } from '../../lib/utils'\nimport { Button } from '../button/Button'\nimport type { ChatError, ChatMessageVariants, ChatRole } from '../chat-core/types'\nimport { ChatMessageEditor, type ChatMessageEditorLabels } from './ChatMessageEditor'\nimport { MessageVariantSwitcher, type MessageVariantSwitcherLabels } from './MessageVariantSwitcher'\n\nexport interface ChatMessageAction {\n key: string\n label: string\n icon?: LucideIcon\n onClick: () => void\n danger?: boolean\n}\n\nexport interface ChatMessageActions {\n onCopy?: () => void\n onEdit?: () => void\n onRegenerate?: () => void\n onRetry?: () => void\n /** Extra icon actions (app-specific). */\n extras?: ChatMessageAction[]\n}\n\nexport interface ChatMessageLabels {\n copy: string\n edit: string\n regenerate: string\n retry: string\n interrupted: string\n error: string\n}\n\nexport interface ChatMessageProps {\n role: ChatRole\n /** Usually a `MarkdownSurface`; any node graph renders here. */\n content: React.ReactNode\n /** Thinking block slot (usually `ChatReasoning`). */\n reasoning?: React.ReactNode\n /** Tool cards / HITL cards below the content. */\n children?: React.ReactNode\n status?: 'streaming' | 'done' | 'error' | 'interrupted'\n error?: ChatError\n actions?: ChatMessageActions\n /** Edit-and-resend mode for user messages (renders `ChatMessageEditor`). */\n editing?: false | { value: string; onValueChange: (value: string) => void; onSubmit: () => void; onCancel: () => void; submitDisabled?: boolean }\n variants?: ChatMessageVariants\n onSelectVariant?: (messageId: string) => void\n /** Badge row (model, latency, tokens — app-defined). */\n meta?: React.ReactNode\n /** Deep-link chip row (career references, health citations). */\n chips?: React.ReactNode\n /** Attachment rail above the content. */\n attachments?: React.ReactNode\n labels?: Partial<ChatMessageLabels & ChatMessageEditorLabels & MessageVariantSwitcherLabels>\n compact?: boolean\n className?: string\n}\n\nconst actionButtonClass =\n 'rounded-[var(--as-radius-sm)] p-1 text-[var(--as-muted-fg)] transition-colors hover:bg-[var(--as-surface-raised)] 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\n/**\n * The family chat bubble: role-aligned, hover action row (copy / edit /\n * regenerate + app extras), variant switcher under branched messages,\n * reasoning and below-content slots, inline edit-and-resend, error +\n * interrupted states. Presentational — state lives app-side.\n */\nexport const ChatMessage = React.forwardRef<HTMLDivElement, ChatMessageProps>(\n function ChatMessage(\n {\n role,\n content,\n reasoning,\n children,\n status = 'done',\n error,\n actions,\n editing = false,\n variants,\n onSelectVariant,\n meta,\n chips,\n attachments,\n labels,\n compact = false,\n className,\n },\n ref,\n ) {\n const isUser = role === 'user'\n const isSystem = role === 'system'\n const showActions =\n actions !== undefined && (actions.onCopy !== undefined || actions.onEdit !== undefined || actions.onRegenerate !== undefined || (actions.extras?.length ?? 0) > 0)\n const editorLabels = { save: labels?.save, cancel: labels?.cancel, ariaLabel: labels?.ariaLabel }\n const switcherLabels = { group: labels?.group, variantOf: labels?.variantOf, previous: labels?.previous, next: labels?.next }\n\n if (isSystem) {\n return (\n <div\n ref={ref}\n data-as=\"chat-message\"\n data-role={role}\n className={cn('flex justify-center', className)}\n >\n <div className=\"rounded-full border border-[var(--as-border)] bg-[var(--as-surface)] px-3 py-1 text-xs text-[var(--as-muted-fg)]\">\n {content}\n </div>\n </div>\n )\n }\n\n return (\n <div\n ref={ref}\n data-as=\"chat-message\"\n data-role={role}\n data-status={status}\n className={cn('group/message flex w-full flex-col', isUser ? 'items-end' : 'items-start', className)}\n >\n {attachments ? <div className=\"mb-1.5 flex w-full flex-wrap justify-end gap-1.5\">{attachments}</div> : null}\n <div\n className={cn(\n 'relative flex max-w-[92%] flex-col gap-1.5 rounded-[var(--as-radius)] px-3 py-2 text-sm',\n compact && 'px-2.5 py-1.5',\n isUser\n ? 'rounded-br-[var(--as-radius-sm)] bg-[var(--as-primary)] text-[var(--as-primary-fg)]'\n : 'rounded-bl-[var(--as-radius-sm)] bg-[var(--as-muted)] text-[var(--as-fg)]',\n )}\n >\n {reasoning ? <div className=\"not-prose\">{reasoning}</div> : null}\n {editing ? (\n <ChatMessageEditor\n value={editing.value}\n onValueChange={editing.onValueChange}\n onSubmit={editing.onSubmit}\n onCancel={editing.onCancel}\n submitDisabled={editing.submitDisabled}\n labels={editorLabels}\n />\n ) : (\n <div className=\"min-w-0\">{content}</div>\n )}\n {status === 'interrupted' ? (\n <span className=\"self-start rounded-full bg-[var(--as-warning)]/15 px-2 py-0.5 text-[10px] font-medium uppercase tracking-wide text-[var(--as-warning)]\">\n {labels?.interrupted ?? 'Stopped'}\n </span>\n ) : null}\n {status === 'error' && error ? (\n <div\n role=\"alert\"\n className=\"flex flex-col gap-1 rounded-[var(--as-radius)] border border-[var(--as-danger)]/40 bg-[var(--as-danger)]/10 px-2.5 py-1.5 text-xs text-[var(--as-danger)]\"\n >\n <span className=\"font-mono font-semibold uppercase tracking-wide\">{error.code}</span>\n <span className=\"whitespace-pre-wrap break-words\">{error.message}</span>\n {error.retryable && actions?.onRetry ? (\n <Button variant=\"outline\" size=\"sm\" className=\"self-start\" onClick={actions.onRetry}>\n {labels?.retry ?? 'Retry'}\n </Button>\n ) : null}\n </div>\n ) : null}\n {chips ? <div className=\"flex flex-wrap gap-1.5\">{chips}</div> : null}\n {children ? <div className=\"flex flex-col gap-1.5\">{children}</div> : null}\n {showActions && !editing ? (\n <div\n className={cn(\n 'absolute top-1 flex items-center gap-0.5 rounded-[var(--as-radius)] border border-[var(--as-border)] bg-[var(--as-surface)] p-0.5 opacity-0 shadow-[var(--as-shadow-1)] transition-opacity focus-within:opacity-100 group-hover/message:opacity-100',\n isUser ? '-left-9' : '-right-9',\n )}\n >\n {actions?.onCopy ? (\n <button type=\"button\" className={actionButtonClass} aria-label={labels?.copy ?? 'Copy'} title={labels?.copy ?? 'Copy'} onClick={actions.onCopy}>\n <Copy className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\n {actions?.onEdit ? (\n <button type=\"button\" className={actionButtonClass} aria-label={labels?.edit ?? 'Edit'} title={labels?.edit ?? 'Edit'} onClick={actions.onEdit}>\n <Pencil className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\n {actions?.onRegenerate ? (\n <button type=\"button\" className={actionButtonClass} aria-label={labels?.regenerate ?? 'Regenerate'} title={labels?.regenerate ?? 'Regenerate'} onClick={actions.onRegenerate}>\n <RotateCcw className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\n {actions?.extras?.map((extra) => (\n <button\n key={extra.key}\n type=\"button\"\n className={cn(actionButtonClass, extra.danger && 'hover:text-[var(--as-danger)]')}\n aria-label={extra.label}\n title={extra.label}\n onClick={extra.onClick}\n >\n {extra.icon ? <extra.icon className=\"size-3.5\" aria-hidden /> : <TriangleAlert className=\"size-3.5\" aria-hidden />}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n {meta ? <div className=\"mt-0.5 flex flex-wrap items-center gap-1.5 px-1 text-[10px] text-[var(--as-muted-fg)]\">{meta}</div> : null}\n {variants && variants.count > 1 && onSelectVariant ? (\n <MessageVariantSwitcher variants={variants} onSelect={onSelectVariant} labels={switcherLabels} className=\"mt-0.5 px-1\" />\n ) : null}\n </div>\n )\n },\n)\n"]}
|