@adecore/agents-react 0.37.2 → 0.38.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/dist/chat/chat-client.d.ts +1 -0
- package/dist/chat/chat-client.js +2 -1
- package/dist/chat/chat-references.d.ts +16 -1
- package/dist/chat/chat-references.js +29 -3
- package/dist/chat/drafts.d.ts +2 -0
- package/dist/chat/drafts.js +21 -5
- package/dist/chat/index.d.ts +1 -1
- package/dist/chat/logic/visual-height.d.ts +1 -0
- package/dist/chat/logic/visual-height.js +1 -1
- package/dist/chat/mentions.d.ts +31 -14
- package/dist/chat/mentions.js +186 -41
- package/dist/chat/stash.d.ts +1 -0
- package/dist/chat/stash.js +4 -2
- package/dist/chat/ui/Composer.js +438 -429
- package/dist/chat/ui/ComposerInput.d.ts +1 -0
- package/dist/chat/ui/ComposerInput.js +2 -0
- package/dist/chat/ui/HostMenuItems.d.ts +4 -0
- package/dist/chat/ui/HostMenuItems.js +15 -0
- package/dist/chat/ui/Markdown.d.ts +3 -1
- package/dist/chat/ui/Markdown.js +194 -120
- package/dist/chat/ui/MessageActions.js +70 -66
- package/dist/chat/ui/ReferenceChip.d.ts +15 -0
- package/dist/chat/ui/ReferenceChip.js +255 -0
- package/dist/chat/ui/Timeline.js +52 -29
- package/dist/chat/ui/TimelineMenu.js +84 -78
- package/dist/chat/ui/VisualFrame.d.ts +8 -0
- package/dist/chat/ui/VisualFrame.js +217 -115
- package/dist/chat/ui/chip-clipboard.d.ts +9 -0
- package/dist/chat/ui/chip-clipboard.js +105 -0
- package/dist/chat/ui/chips.d.ts +5 -0
- package/dist/chat/ui/chips.js +15 -1
- package/dist/chat/ui/composer/ComposerMenu.js +140 -79
- package/dist/chat/ui/composer/DraftParts.d.ts +0 -4
- package/dist/chat/ui/composer/DraftParts.js +0 -41
- package/dist/chat/ui/composer/chip-paste.d.ts +15 -0
- package/dist/chat/ui/composer/chip-paste.js +104 -0
- package/dist/chat/ui/composer/chips.d.ts +5 -0
- package/dist/chat/ui/composer/chips.js +59 -9
- package/dist/chat/ui/composer/key-handler.js +9 -0
- package/dist/chat/ui/composer/use-composer-draft.d.ts +0 -1
- package/dist/chat/ui/composer/use-composer-draft.js +2 -10
- package/dist/chat/ui/composer/use-composer-menus.d.ts +12 -2
- package/dist/chat/ui/composer/use-composer-menus.js +192 -149
- package/dist/chat/ui/composer/use-composer-submit.js +17 -12
- package/dist/chat/ui/composer/use-draft-files.d.ts +7 -1
- package/dist/chat/ui/composer/use-draft-files.js +90 -58
- package/dist/chat/ui/composer/use-take-back.js +2 -1
- package/dist/chat/ui/index.d.ts +1 -1
- package/dist/chat/ui/index.js +1 -1
- package/dist/chat/ui/reference-icons.d.ts +3 -0
- package/dist/chat/ui/reference-icons.js +15 -0
- package/dist/chat/ui/reference-lookup.d.ts +7 -0
- package/dist/chat/ui/reference-lookup.js +6 -0
- package/dist/chat/ui/rehype-chips.d.ts +8 -1
- package/dist/chat/ui/rehype-chips.js +35 -11
- package/dist/chat/ui/rows/GeneratedImageRow.js +8 -4
- package/dist/chat/ui/rows/MessageRows.js +218 -158
- package/dist/chat/ui/rows/VisualRow.js +184 -142
- package/dist/chat/ui/rows/row-rhythm.js +6 -4
- package/dist/chat/ui/thread-references.d.ts +4 -0
- package/dist/chat/ui/thread-references.js +78 -0
- package/dist/host-hooks.d.ts +2 -0
- package/dist/host-hooks.js +7 -0
- package/dist/host.d.ts +14 -1
- package/dist/index.d.ts +1 -1
- package/dist/locales/en/agent-chat.d.ts +20 -3
- package/dist/locales/en/agent-chat.js +24 -7
- package/dist/locales/nl/agent-chat.d.ts +20 -3
- package/dist/locales/nl/agent-chat.js +24 -7
- package/package.json +8 -8
- package/src/chat/chat-client.ts +4 -1
- package/src/chat/chat-references.ts +44 -3
- package/src/chat/drafts.ts +24 -6
- package/src/chat/index.ts +1 -1
- package/src/chat/logic/visual-height.ts +1 -1
- package/src/chat/mentions.ts +202 -36
- package/src/chat/stash.ts +6 -2
- package/src/chat/ui/Composer.tsx +14 -4
- package/src/chat/ui/ComposerInput.tsx +4 -0
- package/src/chat/ui/HostMenuItems.tsx +11 -0
- package/src/chat/ui/Markdown.tsx +57 -25
- package/src/chat/ui/MessageActions.tsx +5 -2
- package/src/chat/ui/ReferenceChip.tsx +74 -0
- package/src/chat/ui/Timeline.tsx +24 -2
- package/src/chat/ui/TimelineMenu.tsx +7 -3
- package/src/chat/ui/VisualFrame.tsx +68 -21
- package/src/chat/ui/chip-clipboard.ts +115 -0
- package/src/chat/ui/chips.ts +20 -1
- package/src/chat/ui/composer/ComposerMenu.tsx +53 -37
- package/src/chat/ui/composer/DraftParts.tsx +0 -12
- package/src/chat/ui/composer/chip-paste.ts +122 -0
- package/src/chat/ui/composer/chips.ts +60 -10
- package/src/chat/ui/composer/key-handler.ts +9 -0
- package/src/chat/ui/composer/use-composer-draft.ts +1 -7
- package/src/chat/ui/composer/use-composer-menus.ts +68 -29
- package/src/chat/ui/composer/use-composer-submit.ts +13 -6
- package/src/chat/ui/composer/use-draft-files.ts +39 -5
- package/src/chat/ui/composer/use-take-back.ts +2 -1
- package/src/chat/ui/index.ts +1 -1
- package/src/chat/ui/reference-icons.ts +17 -0
- package/src/chat/ui/reference-lookup.ts +13 -0
- package/src/chat/ui/rehype-chips.ts +38 -13
- package/src/chat/ui/rows/GeneratedImageRow.tsx +9 -4
- package/src/chat/ui/rows/MessageRows.tsx +88 -64
- package/src/chat/ui/rows/VisualRow.tsx +5 -1
- package/src/chat/ui/rows/row-rhythm.ts +6 -4
- package/src/chat/ui/thread-references.ts +47 -0
- package/src/host-hooks.ts +9 -0
- package/src/host.ts +24 -1
- package/src/index.ts +1 -0
- package/src/locales/en/agent-chat.ts +24 -7
- package/src/locales/nl/agent-chat.ts +24 -7
- package/dist/chat/ui/ChatReferenceChip.d.ts +0 -4
- package/dist/chat/ui/ChatReferenceChip.js +0 -110
- package/src/chat/ui/ChatReferenceChip.tsx +0 -26
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { c as _c } from "react/compiler-runtime";
|
|
2
2
|
import { useTranslation } from 'react-i18next';
|
|
3
3
|
import clsx from 'clsx';
|
|
4
|
-
import {
|
|
4
|
+
import { SquareSlash, Zap } from 'lucide-react';
|
|
5
5
|
import { FileIcon, Icon, Menu, MiddleTruncate } from '@adecore/ui';
|
|
6
|
+
import { REFERENCE_ICONS } from '../reference-icons.js';
|
|
6
7
|
import { optionIdOf } from './menu-aria.js';
|
|
7
8
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
9
|
function splitPath(path) {
|
|
@@ -205,7 +206,7 @@ function SkillMenu(t0) {
|
|
|
205
206
|
return t4;
|
|
206
207
|
}
|
|
207
208
|
function MentionMenu(t0) {
|
|
208
|
-
const $ = _c(
|
|
209
|
+
const $ = _c(15);
|
|
209
210
|
const {
|
|
210
211
|
menus,
|
|
211
212
|
query
|
|
@@ -215,118 +216,165 @@ function MentionMenu(t0) {
|
|
|
215
216
|
} = useTranslation("agent-chat");
|
|
216
217
|
const {
|
|
217
218
|
listId,
|
|
218
|
-
chatMatches,
|
|
219
219
|
files,
|
|
220
220
|
mentionCount
|
|
221
221
|
} = menus;
|
|
222
|
-
const mentionsLabelId = `${listId}-chats`;
|
|
223
222
|
const filesLabelId = `${listId}-files`;
|
|
224
|
-
const filesLabelShown = query === ""
|
|
223
|
+
const filesLabelShown = query === "";
|
|
225
224
|
let t1;
|
|
226
|
-
if ($[0] !==
|
|
225
|
+
if ($[0] !== files || $[1] !== filesLabelId || $[2] !== filesLabelShown || $[3] !== listId || $[4] !== mentionCount || $[5] !== menus || $[6] !== t) {
|
|
227
226
|
t1 = mentionCount > 0 && /*#__PURE__*/_jsxs("div", {
|
|
228
227
|
id: listId,
|
|
229
228
|
role: "listbox",
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
"aria-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
229
|
+
...(filesLabelShown ? {
|
|
230
|
+
"aria-labelledby": filesLabelId
|
|
231
|
+
} : {
|
|
232
|
+
"aria-label": t("composer.mentions.files")
|
|
233
|
+
}),
|
|
234
|
+
children: [filesLabelShown && /*#__PURE__*/_jsx(Menu.Label, {
|
|
235
|
+
id: filesLabelId,
|
|
236
|
+
children: t("composer.mentions.here")
|
|
237
|
+
}), files.map((path, index) => {
|
|
238
|
+
const {
|
|
239
|
+
name,
|
|
240
|
+
dir
|
|
241
|
+
} = splitPath(path);
|
|
242
|
+
return /*#__PURE__*/_jsxs(MenuOption, {
|
|
238
243
|
menus: menus,
|
|
239
244
|
index: index,
|
|
240
245
|
className: "items-center",
|
|
241
|
-
onPick: () => menus.
|
|
242
|
-
children: [/*#__PURE__*/_jsx(
|
|
243
|
-
|
|
244
|
-
size: 14
|
|
245
|
-
className: "shrink-0 text-text-faint"
|
|
246
|
+
onPick: () => menus.chooseMention(path),
|
|
247
|
+
children: [/*#__PURE__*/_jsx(FileIcon, {
|
|
248
|
+
path: path,
|
|
249
|
+
size: 14
|
|
246
250
|
}), /*#__PURE__*/_jsx("span", {
|
|
247
|
-
className: "truncate text-text",
|
|
248
|
-
children:
|
|
251
|
+
className: "truncate font-mono text-text",
|
|
252
|
+
children: name
|
|
253
|
+
}), dir && /*#__PURE__*/_jsx(MiddleTruncate, {
|
|
254
|
+
text: dir,
|
|
255
|
+
tooltip: false,
|
|
256
|
+
className: "text-text-faint"
|
|
249
257
|
})]
|
|
250
|
-
},
|
|
251
|
-
}), files.length > 0 && /*#__PURE__*/_jsxs("div", {
|
|
252
|
-
role: "group",
|
|
253
|
-
...(filesLabelShown ? {
|
|
254
|
-
"aria-labelledby": filesLabelId
|
|
255
|
-
} : {
|
|
256
|
-
"aria-label": t("composer.mentions.files")
|
|
257
|
-
}),
|
|
258
|
-
children: [filesLabelShown && /*#__PURE__*/_jsx(Menu.Label, {
|
|
259
|
-
id: filesLabelId,
|
|
260
|
-
children: query === "" ? t("composer.mentions.here") : t("composer.mentions.files")
|
|
261
|
-
}), files.map((path, index_0) => {
|
|
262
|
-
const {
|
|
263
|
-
name,
|
|
264
|
-
dir
|
|
265
|
-
} = splitPath(path);
|
|
266
|
-
return /*#__PURE__*/_jsxs(MenuOption, {
|
|
267
|
-
menus: menus,
|
|
268
|
-
index: chatMatches.length + index_0,
|
|
269
|
-
className: "items-center",
|
|
270
|
-
onPick: () => menus.chooseMention(path),
|
|
271
|
-
children: [/*#__PURE__*/_jsx(FileIcon, {
|
|
272
|
-
path: path,
|
|
273
|
-
size: 14
|
|
274
|
-
}), /*#__PURE__*/_jsx("span", {
|
|
275
|
-
className: "truncate font-mono text-text",
|
|
276
|
-
children: name
|
|
277
|
-
}), dir && /*#__PURE__*/_jsx(MiddleTruncate, {
|
|
278
|
-
text: dir,
|
|
279
|
-
tooltip: false,
|
|
280
|
-
className: "text-text-faint"
|
|
281
|
-
})]
|
|
282
|
-
}, path);
|
|
283
|
-
})]
|
|
258
|
+
}, path);
|
|
284
259
|
})]
|
|
285
260
|
});
|
|
286
|
-
$[0] =
|
|
287
|
-
$[1] =
|
|
288
|
-
$[2] =
|
|
289
|
-
$[3] =
|
|
290
|
-
$[4] =
|
|
291
|
-
$[5] =
|
|
292
|
-
$[6] =
|
|
293
|
-
$[7] =
|
|
294
|
-
$[8] = query;
|
|
295
|
-
$[9] = t;
|
|
296
|
-
$[10] = t1;
|
|
261
|
+
$[0] = files;
|
|
262
|
+
$[1] = filesLabelId;
|
|
263
|
+
$[2] = filesLabelShown;
|
|
264
|
+
$[3] = listId;
|
|
265
|
+
$[4] = mentionCount;
|
|
266
|
+
$[5] = menus;
|
|
267
|
+
$[6] = t;
|
|
268
|
+
$[7] = t1;
|
|
297
269
|
} else {
|
|
298
|
-
t1 = $[
|
|
270
|
+
t1 = $[7];
|
|
299
271
|
}
|
|
300
272
|
let t2;
|
|
301
|
-
if ($[
|
|
273
|
+
if ($[8] !== mentionCount || $[9] !== query || $[10] !== t) {
|
|
302
274
|
t2 = mentionCount === 0 && /*#__PURE__*/_jsx("div", {
|
|
303
275
|
className: "px-2 py-1 text-xs text-text-faint",
|
|
304
276
|
children: query ? t("composer.mentions.noMatch") : t("composer.mentions.empty")
|
|
305
277
|
});
|
|
306
|
-
$[
|
|
307
|
-
$[
|
|
308
|
-
$[
|
|
309
|
-
$[
|
|
278
|
+
$[8] = mentionCount;
|
|
279
|
+
$[9] = query;
|
|
280
|
+
$[10] = t;
|
|
281
|
+
$[11] = t2;
|
|
310
282
|
} else {
|
|
311
|
-
t2 = $[
|
|
283
|
+
t2 = $[11];
|
|
312
284
|
}
|
|
313
285
|
let t3;
|
|
314
|
-
if ($[
|
|
286
|
+
if ($[12] !== t1 || $[13] !== t2) {
|
|
315
287
|
t3 = /*#__PURE__*/_jsxs("div", {
|
|
316
288
|
className: "border-b border-border px-1.5 py-1.5",
|
|
317
289
|
children: [t1, t2]
|
|
318
290
|
});
|
|
319
|
-
$[
|
|
320
|
-
$[
|
|
321
|
-
$[
|
|
291
|
+
$[12] = t1;
|
|
292
|
+
$[13] = t2;
|
|
293
|
+
$[14] = t3;
|
|
322
294
|
} else {
|
|
323
|
-
t3 = $[
|
|
295
|
+
t3 = $[14];
|
|
324
296
|
}
|
|
325
297
|
return t3;
|
|
326
298
|
}
|
|
299
|
+
/* The views, nodes and chats a `#` offers, what stands on this canvas first, each with its kind or what tells it apart. */
|
|
300
|
+
function ReferenceMenu(t0) {
|
|
301
|
+
const $ = _c(5);
|
|
302
|
+
const {
|
|
303
|
+
menus
|
|
304
|
+
} = t0;
|
|
305
|
+
const {
|
|
306
|
+
t
|
|
307
|
+
} = useTranslation("agent-chat");
|
|
308
|
+
const {
|
|
309
|
+
listId,
|
|
310
|
+
referenceMatches
|
|
311
|
+
} = menus;
|
|
312
|
+
let t1;
|
|
313
|
+
if ($[0] !== listId || $[1] !== menus || $[2] !== referenceMatches || $[3] !== t) {
|
|
314
|
+
const groups = ["canvas", "views"].map(group => ({
|
|
315
|
+
group,
|
|
316
|
+
items: referenceMatches.filter(item => item.group === group)
|
|
317
|
+
})).filter(_temp2);
|
|
318
|
+
t1 = /*#__PURE__*/_jsx("div", {
|
|
319
|
+
className: "border-b border-border px-1.5 py-1.5",
|
|
320
|
+
children: referenceMatches.length > 0 ? /*#__PURE__*/_jsx("div", {
|
|
321
|
+
id: listId,
|
|
322
|
+
role: "listbox",
|
|
323
|
+
"aria-label": t("composer.menu.references"),
|
|
324
|
+
children: groups.map(t2 => {
|
|
325
|
+
const {
|
|
326
|
+
group: group_0,
|
|
327
|
+
items
|
|
328
|
+
} = t2;
|
|
329
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
330
|
+
role: "group",
|
|
331
|
+
"aria-labelledby": `${listId}-${group_0}`,
|
|
332
|
+
children: [/*#__PURE__*/_jsx(Menu.Label, {
|
|
333
|
+
id: `${listId}-${group_0}`,
|
|
334
|
+
children: t(`composer.references.${group_0}`)
|
|
335
|
+
}), items.map(item_0 => {
|
|
336
|
+
const index = referenceMatches.indexOf(item_0);
|
|
337
|
+
return /*#__PURE__*/_jsxs(MenuOption, {
|
|
338
|
+
menus: menus,
|
|
339
|
+
index: index,
|
|
340
|
+
className: "items-center",
|
|
341
|
+
onPick: () => menus.chooseReference(item_0),
|
|
342
|
+
children: [/*#__PURE__*/_jsx(Icon, {
|
|
343
|
+
icon: REFERENCE_ICONS[item_0.kind],
|
|
344
|
+
size: 14,
|
|
345
|
+
className: "shrink-0 text-text-faint"
|
|
346
|
+
}), /*#__PURE__*/_jsx("span", {
|
|
347
|
+
className: "truncate text-text",
|
|
348
|
+
children: item_0.name
|
|
349
|
+
}), /*#__PURE__*/_jsx("span", {
|
|
350
|
+
className: "ml-auto shrink-0 truncate pl-2 text-text-faint",
|
|
351
|
+
children: item_0.detail ?? t(`composer.references.kinds.${item_0.kind}`)
|
|
352
|
+
})]
|
|
353
|
+
}, item_0.id);
|
|
354
|
+
})]
|
|
355
|
+
}, group_0);
|
|
356
|
+
})
|
|
357
|
+
}) : /*#__PURE__*/_jsx("div", {
|
|
358
|
+
className: "px-2 py-1 text-xs text-text-faint",
|
|
359
|
+
children: t("composer.references.noMatch")
|
|
360
|
+
})
|
|
361
|
+
});
|
|
362
|
+
$[0] = listId;
|
|
363
|
+
$[1] = menus;
|
|
364
|
+
$[2] = referenceMatches;
|
|
365
|
+
$[3] = t;
|
|
366
|
+
$[4] = t1;
|
|
367
|
+
} else {
|
|
368
|
+
t1 = $[4];
|
|
369
|
+
}
|
|
370
|
+
return t1;
|
|
371
|
+
}
|
|
327
372
|
/* Whichever picker the caret opened, over the box. */
|
|
373
|
+
function _temp2(entry) {
|
|
374
|
+
return entry.items.length > 0;
|
|
375
|
+
}
|
|
328
376
|
export function ComposerMenu(t0) {
|
|
329
|
-
const $ = _c(
|
|
377
|
+
const $ = _c(8);
|
|
330
378
|
const {
|
|
331
379
|
menus
|
|
332
380
|
} = t0;
|
|
@@ -370,5 +418,18 @@ export function ComposerMenu(t0) {
|
|
|
370
418
|
}
|
|
371
419
|
return t1;
|
|
372
420
|
}
|
|
421
|
+
if (menus.referenceMenuOpen) {
|
|
422
|
+
let t1;
|
|
423
|
+
if ($[6] !== menus) {
|
|
424
|
+
t1 = /*#__PURE__*/_jsx(ReferenceMenu, {
|
|
425
|
+
menus: menus
|
|
426
|
+
});
|
|
427
|
+
$[6] = menus;
|
|
428
|
+
$[7] = t1;
|
|
429
|
+
} else {
|
|
430
|
+
t1 = $[7];
|
|
431
|
+
}
|
|
432
|
+
return t1;
|
|
433
|
+
}
|
|
373
434
|
return null;
|
|
374
435
|
}
|
|
@@ -7,10 +7,6 @@ interface DraftQuoteProps {
|
|
|
7
7
|
onSourceGone(): void;
|
|
8
8
|
}
|
|
9
9
|
export declare function DraftQuote({ chatId, quote, source, onRemove, onSourceGone }: DraftQuoteProps): import("react").JSX.Element;
|
|
10
|
-
export declare function DraftChats({ chats, onRemove }: {
|
|
11
|
-
chats: readonly string[];
|
|
12
|
-
onRemove(id: string): void;
|
|
13
|
-
}): import("react").JSX.Element;
|
|
14
10
|
export declare function DraftAttachments({ attachments, onRemove }: {
|
|
15
11
|
attachments: readonly ChatAttachmentUpload[];
|
|
16
12
|
onRemove(index: number): void;
|
|
@@ -5,7 +5,6 @@ import { Icon, IconButton, Tooltip } from '@adecore/ui';
|
|
|
5
5
|
import { useChatScope } from '../../../scope.js';
|
|
6
6
|
import { formatBytes, isImageAttachment, uploadBytes } from '../../attachments.js';
|
|
7
7
|
import { jumpToTimelineItem } from '../../timeline-scroll.js';
|
|
8
|
-
import { ChatReferenceChip } from '../ChatReferenceChip.js';
|
|
9
8
|
import { UploadThumb } from '../UploadThumb.js';
|
|
10
9
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
11
10
|
const ROW = 'px-5 pt-4 @max-md/composer:px-3.5 @max-md/composer:pt-3';
|
|
@@ -86,46 +85,6 @@ export function DraftQuote(t0) {
|
|
|
86
85
|
}
|
|
87
86
|
return t4;
|
|
88
87
|
}
|
|
89
|
-
/* Other chats the message points at, beside the text rather than in it. */
|
|
90
|
-
export function DraftChats(t0) {
|
|
91
|
-
const $ = _c(7);
|
|
92
|
-
const {
|
|
93
|
-
chats,
|
|
94
|
-
onRemove
|
|
95
|
-
} = t0;
|
|
96
|
-
let t1;
|
|
97
|
-
if ($[0] !== chats || $[1] !== onRemove) {
|
|
98
|
-
let t2;
|
|
99
|
-
if ($[3] !== onRemove) {
|
|
100
|
-
t2 = id => /*#__PURE__*/_jsx(ChatReferenceChip, {
|
|
101
|
-
chatId: id,
|
|
102
|
-
onRemove: () => onRemove(id)
|
|
103
|
-
}, id);
|
|
104
|
-
$[3] = onRemove;
|
|
105
|
-
$[4] = t2;
|
|
106
|
-
} else {
|
|
107
|
-
t2 = $[4];
|
|
108
|
-
}
|
|
109
|
-
t1 = chats.map(t2);
|
|
110
|
-
$[0] = chats;
|
|
111
|
-
$[1] = onRemove;
|
|
112
|
-
$[2] = t1;
|
|
113
|
-
} else {
|
|
114
|
-
t1 = $[2];
|
|
115
|
-
}
|
|
116
|
-
let t2;
|
|
117
|
-
if ($[5] !== t1) {
|
|
118
|
-
t2 = /*#__PURE__*/_jsx("div", {
|
|
119
|
-
className: `flex flex-wrap gap-1.5 ${ROW}`,
|
|
120
|
-
children: t1
|
|
121
|
-
});
|
|
122
|
-
$[5] = t1;
|
|
123
|
-
$[6] = t2;
|
|
124
|
-
} else {
|
|
125
|
-
t2 = $[6];
|
|
126
|
-
}
|
|
127
|
-
return t2;
|
|
128
|
-
}
|
|
129
88
|
/* The files the message carries: an image as a thumbnail, anything else by its name and size. */
|
|
130
89
|
export function DraftAttachments(t0) {
|
|
131
90
|
const $ = _c(9);
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { EditorView } from '@codemirror/view';
|
|
2
|
+
import type { ChatDraft } from '../../drafts.js';
|
|
3
|
+
import type { Referable } from '../../chat-references.js';
|
|
4
|
+
import { type ClipboardChips, type ReferenceToken, type TextRange } from '../../mentions.js';
|
|
5
|
+
export interface PasteChoices {
|
|
6
|
+
skills: readonly string[];
|
|
7
|
+
referables: readonly Referable[];
|
|
8
|
+
referenced: readonly string[];
|
|
9
|
+
mentions: boolean;
|
|
10
|
+
}
|
|
11
|
+
export declare function pastedChipsIn(text: string, from: number, to: number, code: readonly TextRange[], choices: PasteChoices): ClipboardChips;
|
|
12
|
+
export declare function mayHoldChips(text: string): boolean;
|
|
13
|
+
export declare function withPastedChips(draft: ChatDraft, chips: ClipboardChips, choices: PasteChoices): ChatDraft;
|
|
14
|
+
export declare function pasteWithChips(view: EditorView, clip: string, copied: ClipboardChips | null, choices: PasteChoices): ClipboardChips | null;
|
|
15
|
+
export declare function copyWithChipsFromEditor(event: ClipboardEvent, view: EditorView, draft: Pick<ChatDraft, 'mentions' | 'skills'>, references: readonly ReferenceToken[]): boolean;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { chipRanges, clipboardChipsOf, hasClipboardChips, namedReferenceRanges, tokenizeChips, writeClipboardChips } from '../../mentions.js';
|
|
2
|
+
import { codeRanges } from './editor.js';
|
|
3
|
+
/*
|
|
4
|
+
* The chips a plain paste spells between `from` and `to` of the text it landed in: `$name` for a skill
|
|
5
|
+
* there is, `#Name` by the reply rule. Code spans and code blocks keep what they hold.
|
|
6
|
+
*/
|
|
7
|
+
export function pastedChipsIn(text, from, to, code, choices) {
|
|
8
|
+
const outside = [...code, {
|
|
9
|
+
from: 0,
|
|
10
|
+
to: from
|
|
11
|
+
}, {
|
|
12
|
+
from: to,
|
|
13
|
+
to: text.length
|
|
14
|
+
}];
|
|
15
|
+
const skills = chipRanges(text, [], [...choices.skills], outside);
|
|
16
|
+
const references = namedReferenceRanges(text, choices.referables, choices.referenced, outside);
|
|
17
|
+
return clipboardChipsOf(text.slice(from, to), [...skills, ...references].map(range => range.kind === 'skill' ? {
|
|
18
|
+
kind: 'skill',
|
|
19
|
+
name: range.value
|
|
20
|
+
} : {
|
|
21
|
+
kind: 'reference',
|
|
22
|
+
id: range.value,
|
|
23
|
+
name: text.slice(range.from + 1, range.to)
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
/* Whether a plain paste could make a chip at all, before it goes in as text. */
|
|
27
|
+
export function mayHoldChips(text) {
|
|
28
|
+
return /(^|[\s([{"'“‘])[$#]\p{L}/u.test(text);
|
|
29
|
+
}
|
|
30
|
+
/* The draft with the chips of a paste added, a chat beside the views and nodes as the picker keeps it. */
|
|
31
|
+
export function withPastedChips(draft, chips, choices) {
|
|
32
|
+
const add = (ids, more) => [...ids, ...more.filter((id, index) => !ids.includes(id) && more.indexOf(id) === index)];
|
|
33
|
+
const isChat = token => choices.referables.some(item => item.id === token.id && item.kind === 'chat');
|
|
34
|
+
const chats = chips.references.filter(isChat);
|
|
35
|
+
const references = chips.references.filter(token => !isChat(token));
|
|
36
|
+
return {
|
|
37
|
+
...draft,
|
|
38
|
+
mentions: choices.mentions ? add(draft.mentions, chips.mentions) : draft.mentions,
|
|
39
|
+
skills: add(draft.skills, chips.skills),
|
|
40
|
+
chats: add(draft.chats, chats.map(token => token.id)),
|
|
41
|
+
references: add(draft.references, references.map(token => token.id)),
|
|
42
|
+
referenceNames: chips.references.length === 0 ? draft.referenceNames : {
|
|
43
|
+
...draft.referenceNames,
|
|
44
|
+
...Object.fromEntries(chips.references.map(token => [token.id, token.name]))
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/*
|
|
49
|
+
* Puts a paste in the editor and says which chips it brings: the ones it was copied with, or the ones
|
|
50
|
+
* its plain text spells. Null when there are none, so the editor pastes it as it always does.
|
|
51
|
+
*/
|
|
52
|
+
export function pasteWithChips(view, clip, copied, choices) {
|
|
53
|
+
if (copied !== null && hasClipboardChips(copied)) {
|
|
54
|
+
view.dispatch(view.state.replaceSelection(copied.text), {
|
|
55
|
+
scrollIntoView: true,
|
|
56
|
+
userEvent: 'input.paste'
|
|
57
|
+
});
|
|
58
|
+
return copied;
|
|
59
|
+
}
|
|
60
|
+
if (!mayHoldChips(clip)) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const from = view.state.selection.main.from;
|
|
64
|
+
const inserted = view.state.replaceSelection(clip);
|
|
65
|
+
const state = view.state.update(inserted).state;
|
|
66
|
+
const to = state.selection.main.head;
|
|
67
|
+
const found = pastedChipsIn(state.doc.toString(), from, to, codeRanges(state), choices);
|
|
68
|
+
if (!hasClipboardChips(found)) {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
view.dispatch(inserted, {
|
|
72
|
+
scrollIntoView: true,
|
|
73
|
+
userEvent: 'input.paste'
|
|
74
|
+
});
|
|
75
|
+
return found;
|
|
76
|
+
}
|
|
77
|
+
/* A copy or a cut of a selection that holds chips, which carries them beside its text. False leaves it to the editor. */
|
|
78
|
+
export function copyWithChipsFromEditor(event, view, draft, references) {
|
|
79
|
+
const {
|
|
80
|
+
from,
|
|
81
|
+
to
|
|
82
|
+
} = view.state.selection.main;
|
|
83
|
+
if (from === to || event.clipboardData === null) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
const text = view.state.sliceDoc(from, to);
|
|
87
|
+
const chips = clipboardChipsOf(text, tokenizeChips(text, draft.mentions, draft.skills, references));
|
|
88
|
+
if (!hasClipboardChips(chips)) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
writeClipboardChips(event.clipboardData, chips);
|
|
92
|
+
event.preventDefault();
|
|
93
|
+
if (event.type === 'cut') {
|
|
94
|
+
view.dispatch({
|
|
95
|
+
changes: {
|
|
96
|
+
from,
|
|
97
|
+
to
|
|
98
|
+
},
|
|
99
|
+
scrollIntoView: true,
|
|
100
|
+
userEvent: 'delete.cut'
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return true;
|
|
104
|
+
}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { type Extension } from '@codemirror/state';
|
|
2
|
+
import type { ReferableKind } from '../../chat-references.js';
|
|
3
|
+
import { type ReferenceToken } from '../../mentions.js';
|
|
2
4
|
export interface ChipChoices {
|
|
3
5
|
mentions: string[];
|
|
4
6
|
skills: string[];
|
|
7
|
+
references?: ReadonlyArray<ReferenceToken & {
|
|
8
|
+
kind: ReferableKind | null;
|
|
9
|
+
}>;
|
|
5
10
|
}
|
|
6
11
|
export declare function chipDecorations(value: ChipChoices): Extension;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
import { createElement } from 'react';
|
|
2
|
+
import { createRoot } from 'react-dom/client';
|
|
1
3
|
import { syntaxTree } from '@codemirror/language';
|
|
2
|
-
import { Facet,
|
|
3
|
-
import { Decoration, EditorView } from '@codemirror/view';
|
|
4
|
+
import { Facet, StateField } from '@codemirror/state';
|
|
5
|
+
import { Decoration, EditorView, WidgetType } from '@codemirror/view';
|
|
6
|
+
import { Icon } from '@adecore/ui';
|
|
4
7
|
import { chipRanges } from '../../mentions.js';
|
|
5
|
-
import { CHIP_IN_EDITOR, MENTION_TONE, SKILL_TONE } from '../chips.js';
|
|
8
|
+
import { CHIP_IN_EDITOR, MENTION_TONE, REFERENCE_TONE, SKILL_TONE, TOKEN_ICON_IN_EDITOR } from '../chips.js';
|
|
9
|
+
import { REFERENCE_ICONS } from '../reference-icons.js';
|
|
6
10
|
import { codeRanges } from './editor.js';
|
|
7
11
|
const NO_CHOICES = {
|
|
8
12
|
mentions: [],
|
|
@@ -17,17 +21,63 @@ const mentionMark = Decoration.mark({
|
|
|
17
21
|
const skillMark = Decoration.mark({
|
|
18
22
|
class: `${SKILL_TONE} ${CHIP_IN_EDITOR}`
|
|
19
23
|
});
|
|
24
|
+
// Inclusive at the start, so the pill opens before the mark of the kind that replaces its `#` and holds it.
|
|
25
|
+
const referenceMark = Decoration.mark({
|
|
26
|
+
class: `${REFERENCE_TONE} ${CHIP_IN_EDITOR}`,
|
|
27
|
+
inclusiveStart: true
|
|
28
|
+
});
|
|
29
|
+
const roots = new WeakMap();
|
|
30
|
+
/* The kind's mark in place of the `#`, the way a sent message draws it. */
|
|
31
|
+
class ReferenceIcon extends WidgetType {
|
|
32
|
+
kind;
|
|
33
|
+
constructor(kind) {
|
|
34
|
+
super();
|
|
35
|
+
this.kind = kind;
|
|
36
|
+
}
|
|
37
|
+
eq(other) {
|
|
38
|
+
return other.kind === this.kind;
|
|
39
|
+
}
|
|
40
|
+
toDOM() {
|
|
41
|
+
const holder = document.createElement('span');
|
|
42
|
+
holder.className = TOKEN_ICON_IN_EDITOR;
|
|
43
|
+
const root = createRoot(holder);
|
|
44
|
+
root.render(createElement(Icon, {
|
|
45
|
+
icon: REFERENCE_ICONS[this.kind],
|
|
46
|
+
size: 12
|
|
47
|
+
}));
|
|
48
|
+
roots.set(holder, root);
|
|
49
|
+
return holder;
|
|
50
|
+
}
|
|
51
|
+
destroy(dom) {
|
|
52
|
+
const root = roots.get(dom);
|
|
53
|
+
roots.delete(dom);
|
|
54
|
+
// The editor drops a widget inside React's own commit, where a root may not unmount at once.
|
|
55
|
+
queueMicrotask(() => root?.unmount());
|
|
56
|
+
}
|
|
57
|
+
}
|
|
20
58
|
function chipMarks(state) {
|
|
21
59
|
const {
|
|
22
60
|
mentions,
|
|
23
|
-
skills
|
|
61
|
+
skills,
|
|
62
|
+
references = []
|
|
24
63
|
} = state.facet(choices);
|
|
25
|
-
const
|
|
64
|
+
const kinds = new Map(references.map(token => [token.id, token.kind]));
|
|
65
|
+
const marks = [];
|
|
26
66
|
// `@a.ts` in backticks is code, not a mention.
|
|
27
|
-
for (const range of chipRanges(state.doc.toString(), mentions, skills, codeRanges(state))) {
|
|
28
|
-
|
|
67
|
+
for (const range of chipRanges(state.doc.toString(), mentions, skills, codeRanges(state), references)) {
|
|
68
|
+
if (range.kind !== 'reference') {
|
|
69
|
+
marks.push((range.kind === 'skill' ? skillMark : mentionMark).range(range.from, range.to));
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
marks.push(referenceMark.range(range.from, range.to));
|
|
73
|
+
const kind = kinds.get(range.value);
|
|
74
|
+
if (kind !== undefined && kind !== null) {
|
|
75
|
+
marks.push(Decoration.replace({
|
|
76
|
+
widget: new ReferenceIcon(kind)
|
|
77
|
+
}).range(range.from, range.from + 1));
|
|
78
|
+
}
|
|
29
79
|
}
|
|
30
|
-
return
|
|
80
|
+
return Decoration.set(marks, true);
|
|
31
81
|
}
|
|
32
82
|
const chipField = StateField.define({
|
|
33
83
|
create: chipMarks,
|
|
@@ -35,7 +85,7 @@ const chipField = StateField.define({
|
|
|
35
85
|
update: (marks, tr) => tr.docChanged || tr.startState.facet(choices) !== tr.state.facet(choices) || syntaxTree(tr.startState) !== syntaxTree(tr.state) ? chipMarks(tr.state) : marks,
|
|
36
86
|
provide: field => EditorView.decorations.from(field)
|
|
37
87
|
});
|
|
38
|
-
/* Draws the chosen `@path` and
|
|
88
|
+
/* Draws the chosen `@path`, `$name` and `#name` tokens as chips; a new `ChipChoices` object is what redraws them. */
|
|
39
89
|
export function chipDecorations(value) {
|
|
40
90
|
return [choices.of(value), chipField];
|
|
41
91
|
}
|
|
@@ -76,6 +76,15 @@ function pickInMenu(e, {
|
|
|
76
76
|
return true;
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
+
if (menus.referenceMenuOpen && menus.referenceMatches.length > 0) {
|
|
80
|
+
if (menus.moveInMenu(e.key, menus.referenceMatches.length)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
if (e.key === 'Tab' || e.key === 'Enter') {
|
|
84
|
+
menus.chooseReferenceAt(activeIndex);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
79
88
|
return false;
|
|
80
89
|
}
|
|
81
90
|
/* Enter sends, adds a line, or carries a list on, by the send key and where the caret is. */
|
|
@@ -8,7 +8,6 @@ export interface ComposerDraft {
|
|
|
8
8
|
setText(next: string, mentions?: string[], skills?: string[]): void;
|
|
9
9
|
clear(): void;
|
|
10
10
|
removeQuote(): void;
|
|
11
|
-
removeChat(id: string): void;
|
|
12
11
|
removeAttachment(index: number): void;
|
|
13
12
|
}
|
|
14
13
|
export declare function useComposerDraft(chatId: string, inputRef: RefObject<ComposerInputHandle | null>): ComposerDraft;
|
|
@@ -44,17 +44,10 @@ export function useComposerDraft(chatId, inputRef) {
|
|
|
44
44
|
}));
|
|
45
45
|
inputRef.current?.focus();
|
|
46
46
|
};
|
|
47
|
-
const
|
|
47
|
+
const removeAttachment = index => {
|
|
48
48
|
setDraft(current_3 => ({
|
|
49
49
|
...current_3,
|
|
50
|
-
|
|
51
|
-
}));
|
|
52
|
-
inputRef.current?.focus();
|
|
53
|
-
};
|
|
54
|
-
const removeAttachment = index => {
|
|
55
|
-
setDraft(current_4 => ({
|
|
56
|
-
...current_4,
|
|
57
|
-
attachments: current_4.attachments.filter((_, i) => i !== index)
|
|
50
|
+
attachments: current_3.attachments.filter((_, i) => i !== index)
|
|
58
51
|
}));
|
|
59
52
|
};
|
|
60
53
|
return {
|
|
@@ -64,7 +57,6 @@ export function useComposerDraft(chatId, inputRef) {
|
|
|
64
57
|
setText,
|
|
65
58
|
clear,
|
|
66
59
|
removeQuote,
|
|
67
|
-
removeChat,
|
|
68
60
|
removeAttachment
|
|
69
61
|
};
|
|
70
62
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type RefObject } from 'react';
|
|
2
2
|
import type { EditorState } from '@codemirror/state';
|
|
3
3
|
import type { ChatInfo, ProviderCapabilities } from '@adecore/agent-contracts';
|
|
4
|
+
import { type Referable } from '../../chat-references.js';
|
|
4
5
|
import { type MentionQuery, type TextRange } from '../../mentions.js';
|
|
5
6
|
import type { ComposerInputHandle } from '../ComposerInput.js';
|
|
6
7
|
import type { ComposerDraft } from './use-composer-draft.js';
|
|
@@ -24,6 +25,7 @@ export declare function useComposerMenus({ chatId, info, capabilities, providerN
|
|
|
24
25
|
activeIndex: number;
|
|
25
26
|
inputAria: Record<string, string>;
|
|
26
27
|
hasSkills: boolean;
|
|
28
|
+
skillNames: string[];
|
|
27
29
|
commandQuery: string | null;
|
|
28
30
|
commands: ComposerCommand[];
|
|
29
31
|
commandMenuOpen: boolean;
|
|
@@ -36,14 +38,22 @@ export declare function useComposerMenus({ chatId, info, capabilities, providerN
|
|
|
36
38
|
mention: MentionQuery | null;
|
|
37
39
|
mentionMenuOpen: boolean;
|
|
38
40
|
mentionCount: number;
|
|
39
|
-
chatMatches: import("../../index.js").ProjectChat[];
|
|
40
41
|
files: string[];
|
|
42
|
+
referenceMenuOpen: boolean;
|
|
43
|
+
referenceMatches: Referable[];
|
|
44
|
+
referables: import("../../index.js").Referables;
|
|
45
|
+
referenceChips: {
|
|
46
|
+
id: string;
|
|
47
|
+
name: string;
|
|
48
|
+
kind: import("../../index.js").ReferableKind | null;
|
|
49
|
+
}[];
|
|
41
50
|
setMenuIndex: import("react").Dispatch<import("react").SetStateAction<number>>;
|
|
42
51
|
trackTriggers: (value: string, selection: TextRange, state: EditorState) => void;
|
|
43
52
|
close: () => void;
|
|
44
53
|
chooseMention: (path: string) => void;
|
|
45
|
-
chooseChat: (id: string) => void;
|
|
46
54
|
chooseMentionAt: (index: number) => void;
|
|
55
|
+
chooseReference: (item: Referable) => void;
|
|
56
|
+
chooseReferenceAt: (index: number) => void;
|
|
47
57
|
chooseSkill: (name: string) => void;
|
|
48
58
|
pickCommand: (command: ComposerCommand, index: number) => void;
|
|
49
59
|
moveInMenu: (key: string, count: number) => boolean;
|