@parallelworks/ui 0.50.0 → 0.52.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/README.md +204 -18
- package/dist/ai/agent/toolStrings.d.ts +2 -0
- package/dist/ai/agent/toolStrings.js +20 -18
- package/dist/ai/ai.css +12 -0
- package/dist/ai/components/AllocationSelector.js +5 -1
- package/dist/ai/components/AttachmentManager.js +51 -42
- package/dist/ai/components/AttachmentUpload.d.ts +4 -2
- package/dist/ai/components/AttachmentUpload.js +9 -9
- package/dist/ai/components/BlockedGroupBanner.js +8 -14
- package/dist/ai/components/BranchNavigator.js +11 -12
- package/dist/ai/components/ChatEmptyState.js +12 -19
- package/dist/ai/components/ChatInput.d.ts +4 -3
- package/dist/ai/components/ChatInput.js +27 -13
- package/dist/ai/components/ChatMessage.js +45 -121
- package/dist/ai/components/ChatMessageList.d.ts +5 -2
- package/dist/ai/components/ChatMessageList.js +89 -51
- package/dist/ai/components/ChatSidebar.js +11 -7
- package/dist/ai/components/ChatThread.js +1 -13
- package/dist/ai/components/DragOverlay.js +3 -3
- package/dist/ai/components/MessageAttachments.d.ts +10 -0
- package/dist/ai/components/MessageAttachments.js +78 -0
- package/dist/ai/components/ModelSelector.js +4 -4
- package/dist/ai/components/PastedText.js +2 -2
- package/dist/ai/components/ProviderIssueBanner.js +19 -23
- package/dist/ai/components/ShareDialog.js +2 -2
- package/dist/ai/components/agent/ActivityLine.d.ts +0 -2
- package/dist/ai/components/agent/ActivityLine.js +8 -51
- package/dist/ai/components/agent/AgentMessageParts.js +117 -56
- package/dist/ai/core/ChatProvider.d.ts +16 -5
- package/dist/ai/core/ChatProvider.js +41 -8
- package/dist/ai/core/config.js +4 -3
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.js +3 -3
- package/dist/ai/strings.d.ts +29 -3
- package/dist/ai/strings.js +81 -26
- package/dist/ai/types.d.ts +4 -0
- package/dist/ai/ui/Notice.d.ts +2 -2
- package/dist/ai/ui/Notice.js +29 -62
- package/dist/ai/ui/sidebar.d.ts +5 -3
- package/dist/ai/ui/sidebar.js +21 -9
- package/dist/components/ActionMenu.d.ts +1 -0
- package/dist/components/ActionMenu.js +6 -1
- package/dist/components/AppLink.d.ts +26 -0
- package/dist/components/AppLink.js +51 -0
- package/dist/components/Avatar.d.ts +2 -1
- package/dist/components/Avatar.js +4 -2
- package/dist/components/Button.d.ts +15 -5
- package/dist/components/Button.js +47 -40
- package/dist/components/Callout.d.ts +31 -7
- package/dist/components/Callout.js +51 -24
- package/dist/components/Card.d.ts +11 -6
- package/dist/components/Card.js +14 -8
- package/dist/components/Checkbox.js +2 -1
- package/dist/components/ColorInput.js +5 -3
- package/dist/components/Combobox.js +49 -19
- package/dist/components/ConfirmModal.d.ts +19 -8
- package/dist/components/ConfirmModal.js +31 -53
- package/dist/components/CopyButton.d.ts +38 -0
- package/dist/components/CopyButton.js +68 -0
- package/dist/components/CreateModal.js +118 -111
- package/dist/components/DatePicker.js +12 -8
- package/dist/components/DescriptionList.d.ts +51 -17
- package/dist/components/DescriptionList.js +117 -31
- package/dist/components/Disclosure.js +1 -1
- package/dist/components/Drawer.js +10 -16
- package/dist/components/Field.d.ts +15 -5
- package/dist/components/Field.js +41 -9
- package/dist/components/IconButton.d.ts +14 -5
- package/dist/components/IconButton.js +25 -14
- package/dist/components/InfoTip.d.ts +4 -1
- package/dist/components/InfoTip.js +2 -1
- package/dist/components/Input.d.ts +14 -8
- package/dist/components/Input.js +46 -31
- package/dist/components/Loader.js +1 -1
- package/dist/components/MenuEntries.d.ts +43 -12
- package/dist/components/MenuEntries.js +34 -19
- package/dist/components/Meter.js +5 -4
- package/dist/components/Modal.d.ts +28 -4
- package/dist/components/Modal.js +37 -14
- package/dist/components/Overview.d.ts +20 -12
- package/dist/components/Overview.js +14 -9
- package/dist/components/PageHeader.d.ts +47 -65
- package/dist/components/PageHeader.js +275 -153
- package/dist/components/PageHeaderAction.d.ts +67 -0
- package/dist/components/PageHeaderAction.js +107 -0
- package/dist/components/Pagination.js +6 -16
- package/dist/components/Popover.js +3 -2
- package/dist/components/Provider.d.ts +79 -19
- package/dist/components/Provider.js +140 -130
- package/dist/components/Radio.js +2 -1
- package/dist/components/RefreshButton.js +7 -8
- package/dist/components/RequiredMark.js +1 -1
- package/dist/components/RunStatusIcon.js +2 -2
- package/dist/components/Section.js +1 -1
- package/dist/components/Select.d.ts +4 -9
- package/dist/components/Select.js +24 -11
- package/dist/components/SettingModeOption.d.ts +1 -1
- package/dist/components/SettingModeOption.js +7 -1
- package/dist/components/SettingsCard.d.ts +5 -3
- package/dist/components/SettingsCard.js +27 -20
- package/dist/components/Slider.js +1 -1
- package/dist/components/StatusBadge.js +2 -2
- package/dist/components/StatusIcons.js +2 -2
- package/dist/components/Switch.js +5 -4
- package/dist/components/Table.d.ts +30 -20
- package/dist/components/Table.js +50 -73
- package/dist/components/Tabs.d.ts +3 -7
- package/dist/components/Tabs.js +6 -10
- package/dist/components/ThemeEditor.js +24 -14
- package/dist/components/Toast.d.ts +11 -3
- package/dist/components/Toast.js +47 -22
- package/dist/components/buttonClasses.js +2 -2
- package/dist/components/comboboxItems.d.ts +4 -0
- package/dist/components/comboboxItems.js +6 -1
- package/dist/components/dismiss.d.ts +12 -0
- package/dist/components/dismiss.js +19 -0
- package/dist/components/fieldBox.d.ts +4 -0
- package/dist/components/fieldBox.js +7 -3
- package/dist/components/floating.d.ts +3 -3
- package/dist/components/floating.js +1 -1
- package/dist/components/markdownCodeBreaks.js +3 -4
- package/dist/components/pageHeaderStore.d.ts +41 -0
- package/dist/components/pageHeaderStore.js +67 -0
- package/dist/components/pathBreaks.d.ts +8 -0
- package/dist/components/pathBreaks.js +28 -0
- package/dist/components/segmented.js +1 -1
- package/dist/components/shortcutKey.d.ts +2 -1
- package/dist/components/shortcutKey.js +19 -2
- package/dist/components/splitter.js +1 -1
- package/dist/components/tone.d.ts +5 -2
- package/dist/components/tone.js +15 -6
- package/dist/components/useCssIsDark.js +40 -18
- package/dist/components/useTheme.js +9 -10
- package/dist/dev.d.ts +9 -0
- package/dist/dev.js +14 -0
- package/dist/editor/Editor.d.ts +3 -2
- package/dist/editor/Editor.js +11 -2
- package/dist/editor/EditorField.d.ts +2 -1
- package/dist/editor/EditorField.js +11 -29
- package/dist/editor/FormCodePanel.d.ts +7 -3
- package/dist/editor/FormCodePanel.js +14 -7
- package/dist/editor/Monaco.d.ts +14 -5
- package/dist/editor/Monaco.js +163 -112
- package/dist/editor/index.d.ts +5 -5
- package/dist/editor/index.js +3 -3
- package/dist/editor/themes.d.ts +8 -5
- package/dist/editor/themes.js +58 -30
- package/dist/editor/yaml.d.ts +6 -2
- package/dist/editor/yaml.js +11 -2
- package/dist/file-explorer/FileExplorer.js +143 -124
- package/dist/file-explorer/FileExplorerContext.js +1 -1
- package/dist/file-explorer/FilePreview/StreamedBadge.js +3 -1
- package/dist/file-explorer/FilePreview/Viewer.js +2 -2
- package/dist/file-explorer/FilePreview/index.js +4 -4
- package/dist/file-explorer/FileRow.js +1 -1
- package/dist/file-explorer/FileRowsWindow.js +34 -3
- package/dist/file-explorer/FileTable.js +3 -1
- package/dist/file-explorer/TreeView.js +37 -14
- package/dist/file-explorer/helpers.d.ts +2 -1
- package/dist/file-explorer/helpers.js +21 -20
- package/dist/file-explorer/toasts.js +27 -19
- package/dist/file-explorer/treeRows.d.ts +6 -0
- package/dist/file-explorer/treeRows.js +19 -1
- package/dist/file-explorer/useNearEnd.js +3 -6
- package/dist/form/Fields/CheckboxGroupField.js +12 -5
- package/dist/form/Fields/DurationField.js +1 -1
- package/dist/form/Fields/LabelField.js +1 -1
- package/dist/form/Fields/ObjectField.d.ts +1 -1
- package/dist/form/Fields/ObjectField.js +3 -2
- package/dist/form/Fields/StringField.js +16 -29
- package/dist/form/Fields/TextAreaField.js +3 -4
- package/dist/form/Form.js +3 -8
- package/dist/form/Wizard/WizardNavigation.js +1 -4
- package/dist/form/Wizard/WizardStepIndicator.js +1 -1
- package/dist/form/Wizard/utils.js +1 -1
- package/dist/form/fieldFrame.d.ts +1 -1
- package/dist/form/fieldFrame.js +2 -2
- package/dist/form/types/fieldComponentTypes.d.ts +2 -1
- package/dist/graph/AnnotationBanner.d.ts +1 -2
- package/dist/graph/AnnotationBanner.js +30 -32
- package/dist/graph/Connectors.js +4 -1
- package/dist/graph/DependencyGraph.js +2 -2
- package/dist/graph/GraphEditor.js +12 -10
- package/dist/graph/GraphEditorDialogs.js +2 -2
- package/dist/graph/GraphNode.js +7 -4
- package/dist/graph/InputDialog.js +1 -1
- package/dist/graph/InputsEditor.js +14 -11
- package/dist/graph/MatrixGroup.js +9 -3
- package/dist/graph/ProblemsButton.js +2 -2
- package/dist/graph/Reveal.js +18 -10
- package/dist/graph/ShortcutsButton.d.ts +11 -2
- package/dist/graph/ShortcutsButton.js +15 -4
- package/dist/graph/TreeView.js +35 -18
- package/dist/graph/WorkflowSettingsDialog.js +1 -1
- package/dist/graph/editorChrome.js +1 -1
- package/dist/graph/editorFields.js +1 -1
- package/dist/graph/editorRows.js +16 -10
- package/dist/graph/editorStrings.d.ts +7 -0
- package/dist/graph/editorStrings.js +8 -1
- package/dist/graph/fieldProblems.js +1 -1
- package/dist/graph/inputRefs.js +1 -1
- package/dist/graph/settingsViews.js +11 -18
- package/dist/graph/stepWith.js +2 -2
- package/dist/icons.d.ts +2 -0
- package/dist/icons.js +4 -2
- package/dist/index.d.ts +12 -12
- package/dist/index.js +16 -16
- package/dist/list/ActionToolbar.d.ts +44 -8
- package/dist/list/ActionToolbar.js +301 -102
- package/dist/list/ListPage.d.ts +15 -23
- package/dist/list/ListPage.js +46 -45
- package/dist/list/ListTable.d.ts +32 -7
- package/dist/list/ListTable.js +48 -12
- package/dist/list/ListViewControls.js +2 -2
- package/dist/list/UserHoverCard.js +7 -15
- package/dist/list/index.d.ts +2 -2
- package/dist/list/index.js +2 -2
- package/dist/list/listSearch.js +12 -10
- package/dist/list/listView.d.ts +10 -1
- package/dist/list/listView.js +15 -1
- package/dist/list/rowMenu.d.ts +2 -2
- package/dist/logviewer/LogViewer.d.ts +4 -2
- package/dist/logviewer/LogViewer.js +88 -70
- package/dist/logviewer/logviewer.css +3 -2
- package/dist/reducedMotion.d.ts +5 -0
- package/dist/reducedMotion.js +20 -0
- package/dist/safeUrl.d.ts +1 -1
- package/dist/safeUrl.js +4 -2
- package/dist/styles/theme.css +24 -10
- package/dist/styles.css +1 -1
- package/dist/theme/derive.d.ts +1 -1
- package/dist/theme/derive.js +46 -21
- package/dist/theme/fit.js +10 -4
- package/package.json +1 -1
- package/dist/components/Breadcrumbs.d.ts +0 -37
- package/dist/components/Breadcrumbs.js +0 -90
- package/dist/components/CopyToClipboard.d.ts +0 -17
- package/dist/components/CopyToClipboard.js +0 -66
- package/dist/components/Sort.d.ts +0 -9
- package/dist/components/Sort.js +0 -42
|
@@ -7,7 +7,7 @@ import { useChatConfig } from "../core/config.js";
|
|
|
7
7
|
import { useChat } from "../core/ChatProvider.js";
|
|
8
8
|
import { ATTACHMENTS_INFINITE_KEY } from "./attachmentKeys.js";
|
|
9
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
-
import {
|
|
10
|
+
import { useCallback, useImperativeHandle, useRef, useState } from "react";
|
|
11
11
|
import { mutate } from "swr";
|
|
12
12
|
//#region src/ai/components/AttachmentUpload.tsx
|
|
13
13
|
var DEFAULT_MAX_FILE_SIZE = 26214400;
|
|
@@ -18,7 +18,7 @@ function getFileIcon(mimeType) {
|
|
|
18
18
|
if (mimeType === "application/pdf") return PdfIcon;
|
|
19
19
|
return FileIcon;
|
|
20
20
|
}
|
|
21
|
-
|
|
21
|
+
function AttachmentUpload({ conversationId, attachments, onAttachmentsChange, disabled = false, maxFiles = DEFAULT_MAX_FILES, maxFileSize = DEFAULT_MAX_FILE_SIZE, ref }) {
|
|
22
22
|
const { adapter } = useChat();
|
|
23
23
|
const t = useChatConfig().strings.attachmentUpload;
|
|
24
24
|
const { common } = useStrings();
|
|
@@ -125,7 +125,7 @@ var AttachmentUpload = forwardRef(function AttachmentUpload({ conversationId, at
|
|
|
125
125
|
children: attachments.map((attachment, index) => {
|
|
126
126
|
const Icon = getFileIcon(attachment.mimeType);
|
|
127
127
|
return /* @__PURE__ */ jsxs("div", {
|
|
128
|
-
className: cx("flex items-center gap-2 px-2 py-1 rounded border theme-border theme-muted-panel", attachment.error && "border-
|
|
128
|
+
className: cx("flex items-center gap-2 px-2 py-1 rounded border theme-border theme-muted-panel", attachment.error && "border-(--theme-error)"),
|
|
129
129
|
children: [
|
|
130
130
|
/* @__PURE__ */ jsx(Icon, { className: "w-4 h-4 theme-muted-text" }),
|
|
131
131
|
/* @__PURE__ */ jsx("span", {
|
|
@@ -137,22 +137,22 @@ var AttachmentUpload = forwardRef(function AttachmentUpload({ conversationId, at
|
|
|
137
137
|
children: formatBytes(attachment.size)
|
|
138
138
|
}),
|
|
139
139
|
attachment.uploading && /* @__PURE__ */ jsx("span", {
|
|
140
|
-
className: "text-xs
|
|
140
|
+
className: "text-xs theme-muted-text animate-pulse",
|
|
141
141
|
children: t.uploading
|
|
142
142
|
}),
|
|
143
143
|
attachment.error && /* @__PURE__ */ jsx("span", {
|
|
144
144
|
role: "img",
|
|
145
145
|
"aria-label": attachment.error,
|
|
146
146
|
title: attachment.error,
|
|
147
|
-
children: /* @__PURE__ */ jsx(WarningIcon, { className: "h-3.5 w-3.5 text-
|
|
147
|
+
children: /* @__PURE__ */ jsx(WarningIcon, { className: "h-3.5 w-3.5 text-(--theme-error)" })
|
|
148
148
|
}),
|
|
149
149
|
/* @__PURE__ */ jsx("button", {
|
|
150
150
|
type: "button",
|
|
151
151
|
onClick: () => handleRemove(index),
|
|
152
|
-
className: "p-0.5 rounded hover:bg-
|
|
152
|
+
className: "p-0.5 rounded hover:bg-(--theme-error-muted)",
|
|
153
153
|
title: common.remove,
|
|
154
154
|
disabled,
|
|
155
|
-
children: /* @__PURE__ */ jsx(TrashIcon, { className: "w-3 h-3 text-
|
|
155
|
+
children: /* @__PURE__ */ jsx(TrashIcon, { className: "w-3 h-3 text-(--theme-error)" })
|
|
156
156
|
})
|
|
157
157
|
]
|
|
158
158
|
}, attachment.id || index);
|
|
@@ -162,7 +162,7 @@ var AttachmentUpload = forwardRef(function AttachmentUpload({ conversationId, at
|
|
|
162
162
|
onDragOver: handleDragOver,
|
|
163
163
|
onDragLeave: handleDragLeave,
|
|
164
164
|
onDrop: handleDrop,
|
|
165
|
-
className: cx("relative block w-full border-2 border-dashed rounded-lg p-3 text-center transition-colors", isDragging ? "border-
|
|
165
|
+
className: cx("relative block w-full border-2 border-dashed rounded-lg p-3 text-center transition-colors", isDragging ? "border-(--theme-accent) bg-(--theme-accent)/10" : "theme-border hover:theme-border", disabled ? "opacity-50 cursor-not-allowed" : "cursor-pointer"),
|
|
166
166
|
onClick: disabled ? void 0 : handleClick,
|
|
167
167
|
children: [/* @__PURE__ */ jsxs("span", {
|
|
168
168
|
className: "flex items-center justify-center gap-2 text-sm theme-muted-text",
|
|
@@ -173,6 +173,6 @@ var AttachmentUpload = forwardRef(function AttachmentUpload({ conversationId, at
|
|
|
173
173
|
})]
|
|
174
174
|
})]
|
|
175
175
|
})] });
|
|
176
|
-
}
|
|
176
|
+
}
|
|
177
177
|
//#endregion
|
|
178
178
|
export { AttachmentUpload as default };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Callout } from "../../components/Callout.js";
|
|
2
2
|
import { useChatConfig } from "../core/config.js";
|
|
3
3
|
import { useChat } from "../core/ChatProvider.js";
|
|
4
4
|
import { getProviderKeyFromModelId } from "./ModelSelector.js";
|
|
5
|
-
import { jsx
|
|
5
|
+
import { jsx } from "react/jsx-runtime";
|
|
6
6
|
//#region src/ai/components/BlockedGroupBanner.tsx
|
|
7
7
|
function BlockedGroupBanner() {
|
|
8
8
|
const { strings } = useChatConfig();
|
|
@@ -11,18 +11,12 @@ function BlockedGroupBanner() {
|
|
|
11
11
|
const providerKey = getProviderKeyFromModelId(selectedProvider);
|
|
12
12
|
const provider = providers.find((p) => `${p.user}:${p.name}` === providerKey);
|
|
13
13
|
if (!provider?.groupBlocked || !provider.group) return null;
|
|
14
|
-
return /* @__PURE__ */
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
children: strings.blockedGroup.title.replace("{group}", provider.group)
|
|
21
|
-
}), /* @__PURE__ */ jsx("p", {
|
|
22
|
-
className: "text-xs text-amber-600/80 mt-0.5",
|
|
23
|
-
children: strings.blockedGroup.message
|
|
24
|
-
})]
|
|
25
|
-
})]
|
|
14
|
+
return /* @__PURE__ */ jsx(Callout, {
|
|
15
|
+
tone: "warning",
|
|
16
|
+
size: "sm",
|
|
17
|
+
className: "mx-4 mt-2",
|
|
18
|
+
title: strings.blockedGroup.title(provider.group),
|
|
19
|
+
children: strings.blockedGroup.message
|
|
26
20
|
});
|
|
27
21
|
}
|
|
28
22
|
//#endregion
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ChevronLeftIcon, ChevronRightIcon } from "../../icons.js";
|
|
2
|
+
import { IconButton } from "../../components/IconButton.js";
|
|
2
3
|
import { useChatConfig } from "../core/config.js";
|
|
3
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
5
|
import { useMemo } from "react";
|
|
@@ -26,14 +27,13 @@ function BranchNavigator({ messages, currentMessageId, onNavigate }) {
|
|
|
26
27
|
return /* @__PURE__ */ jsxs("div", {
|
|
27
28
|
className: "inline-flex items-center text-xs theme-muted-text",
|
|
28
29
|
children: [
|
|
29
|
-
/* @__PURE__ */ jsx(
|
|
30
|
-
|
|
30
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
31
|
+
label: t.previous,
|
|
31
32
|
onClick: handlePrev,
|
|
32
33
|
disabled: !hasPrev,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
children: /* @__PURE__ */ jsx(ChevronLeftIcon, { className: "w-3.5 h-3.5" })
|
|
34
|
+
size: "md",
|
|
35
|
+
className: "size-7 hover:not-disabled:not-aria-disabled:chat-tint disabled:opacity-30",
|
|
36
|
+
icon: /* @__PURE__ */ jsx(ChevronLeftIcon, {})
|
|
37
37
|
}),
|
|
38
38
|
/* @__PURE__ */ jsxs("span", {
|
|
39
39
|
className: "min-w-[3ch] text-center tabular-nums",
|
|
@@ -43,14 +43,13 @@ function BranchNavigator({ messages, currentMessageId, onNavigate }) {
|
|
|
43
43
|
siblings.length
|
|
44
44
|
]
|
|
45
45
|
}),
|
|
46
|
-
/* @__PURE__ */ jsx(
|
|
47
|
-
|
|
46
|
+
/* @__PURE__ */ jsx(IconButton, {
|
|
47
|
+
label: t.next,
|
|
48
48
|
onClick: handleNext,
|
|
49
49
|
disabled: !hasNext,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
children: /* @__PURE__ */ jsx(ChevronRightIcon, { className: "w-3.5 h-3.5" })
|
|
50
|
+
size: "md",
|
|
51
|
+
className: "size-7 hover:not-disabled:not-aria-disabled:chat-tint disabled:opacity-30",
|
|
52
|
+
icon: /* @__PURE__ */ jsx(ChevronRightIcon, {})
|
|
54
53
|
})
|
|
55
54
|
]
|
|
56
55
|
});
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { AddIcon, CloudIcon } from "../../icons.js";
|
|
2
2
|
import { keyedByContent } from "../../components/keys.js";
|
|
3
3
|
import { useStrings } from "../../components/Provider.js";
|
|
4
|
+
import { Button } from "../../components/Button.js";
|
|
5
|
+
import { Callout } from "../../components/Callout.js";
|
|
4
6
|
import { useChatConfig } from "../core/config.js";
|
|
5
7
|
import { useChat } from "../core/ChatProvider.js";
|
|
6
8
|
import BlockedGroupBanner from "./BlockedGroupBanner.js";
|
|
7
9
|
import { getGreeting } from "../core/greeting.js";
|
|
8
10
|
import useDragDrop from "../core/useDragDrop.js";
|
|
9
|
-
import { NoticeCard } from "../ui/Notice.js";
|
|
10
11
|
import { ComposerControls, ConnectToolsLink } from "./ComposerChrome.js";
|
|
11
12
|
import DragOverlay from "./DragOverlay.js";
|
|
12
13
|
import ChatInput from "./ChatInput.js";
|
|
@@ -79,26 +80,18 @@ function ChatEmptyState({ targetSession }) {
|
|
|
79
80
|
/* @__PURE__ */ jsx(ProviderIssueBanner, {}),
|
|
80
81
|
sessionUnreachable && !sessionBannerDismissed && /* @__PURE__ */ jsx("div", {
|
|
81
82
|
className: "mx-4 mt-2",
|
|
82
|
-
children: /* @__PURE__ */
|
|
83
|
+
children: /* @__PURE__ */ jsx(Callout, {
|
|
83
84
|
tone: "warning",
|
|
85
|
+
size: "sm",
|
|
86
|
+
title: t.sessionUnreachableTitle(targetSession?.split(":").pop() ?? ""),
|
|
87
|
+
action: /* @__PURE__ */ jsx(Button, {
|
|
88
|
+
size: "sm",
|
|
89
|
+
variant: "outline",
|
|
90
|
+
onClick: () => refreshModels(),
|
|
91
|
+
children: common.retry
|
|
92
|
+
}),
|
|
84
93
|
onDismiss: () => setSessionBannerDismissed(true),
|
|
85
|
-
|
|
86
|
-
children: [
|
|
87
|
-
/* @__PURE__ */ jsx("span", {
|
|
88
|
-
className: "block font-medium",
|
|
89
|
-
children: t.sessionUnreachableTitle(targetSession?.split(":").pop() ?? "")
|
|
90
|
-
}),
|
|
91
|
-
/* @__PURE__ */ jsx("span", {
|
|
92
|
-
className: "mt-0.5 block",
|
|
93
|
-
children: t.sessionUnreachableBody
|
|
94
|
-
}),
|
|
95
|
-
/* @__PURE__ */ jsx("button", {
|
|
96
|
-
type: "button",
|
|
97
|
-
onClick: () => refreshModels(),
|
|
98
|
-
className: "mt-1 font-medium underline-offset-2 hover:underline",
|
|
99
|
-
children: common.retry
|
|
100
|
-
})
|
|
101
|
-
]
|
|
94
|
+
children: t.sessionUnreachableBody
|
|
102
95
|
})
|
|
103
96
|
}),
|
|
104
97
|
/* @__PURE__ */ jsxs("div", {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type ReactNode } from 'react';
|
|
1
|
+
import { type ReactNode, type Ref } from 'react';
|
|
2
2
|
import type { AttachmentMeta, MessagePaste } from '../types.js';
|
|
3
3
|
import { type SlashMenuConfig } from './SlashMenu.js';
|
|
4
4
|
import { type ComposerPastes } from './usePasteCards.js';
|
|
@@ -43,10 +43,11 @@ interface ChatInputProps {
|
|
|
43
43
|
stopping?: boolean;
|
|
44
44
|
};
|
|
45
45
|
pastes?: ComposerPastes | undefined;
|
|
46
|
+
ref?: Ref<ChatInputHandle> | undefined;
|
|
46
47
|
}
|
|
47
48
|
export interface ChatInputHandle {
|
|
48
49
|
addFiles: (files: FileList | File[]) => void;
|
|
49
50
|
focus: () => void;
|
|
50
51
|
}
|
|
51
|
-
|
|
52
|
-
export
|
|
52
|
+
export default function ChatInput({ onSend, disabled, placeholder, conversationId, onEditLastMessage, allowEmpty, attachments: attachmentsWanted, requireModel, inputLabel, sendLabel, sendTestId, slash, notices, activity, context, reserveContext, settingsLeft, settingsRight, hint, turn, pastes, ref, }: ChatInputProps): import("react").JSX.Element;
|
|
53
|
+
export {};
|
|
@@ -11,7 +11,7 @@ import { PasteFileCard } from "./PastedText.js";
|
|
|
11
11
|
import { SlashMenu, useSlashMenu } from "./SlashMenu.js";
|
|
12
12
|
import { usePasteCards } from "./usePasteCards.js";
|
|
13
13
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
|
-
import {
|
|
14
|
+
import { useCallback, useEffect, useImperativeHandle, useLayoutEffect, useRef, useState } from "react";
|
|
15
15
|
//#region src/ai/components/ChatInput.tsx
|
|
16
16
|
/** An optional box that is still empty should not wear the filled look of
|
|
17
17
|
* one waiting to send something. */
|
|
@@ -19,7 +19,7 @@ function sendability({ hasText, canFlushQueue, allowEmpty, disabled, modelReady,
|
|
|
19
19
|
const canSend = (hasText || canFlushQueue || allowEmpty) && !disabled && modelReady && pendingCount === 0;
|
|
20
20
|
return {
|
|
21
21
|
canSend,
|
|
22
|
-
|
|
22
|
+
emphasized: canSend && (hasText || !allowEmpty)
|
|
23
23
|
};
|
|
24
24
|
}
|
|
25
25
|
function keyAction(e, empty, canEditLast) {
|
|
@@ -39,13 +39,13 @@ function AttachButton({ open, disabled, label, onClick }) {
|
|
|
39
39
|
children: /* @__PURE__ */ jsx(AddIcon, { className: cx("h-5 w-5 transition-transform duration-200", open && "rotate-45") })
|
|
40
40
|
});
|
|
41
41
|
}
|
|
42
|
-
function SendButton({ onClick, enabled,
|
|
42
|
+
function SendButton({ onClick, enabled, emphasized, label, testId }) {
|
|
43
43
|
return /* @__PURE__ */ jsx("button", {
|
|
44
44
|
type: "button",
|
|
45
45
|
onClick,
|
|
46
46
|
disabled: !enabled,
|
|
47
47
|
"data-testid": testId,
|
|
48
|
-
className: cx("flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full transition-[background-color,color,transform] duration-150 active:scale-95",
|
|
48
|
+
className: cx("flex h-8 w-8 flex-shrink-0 items-center justify-center rounded-full transition-[background-color,color,transform] duration-150 active:scale-95", emphasized ? "theme-accent hover:opacity-90" : "chat-send-idle", !enabled && "cursor-not-allowed active:scale-100"),
|
|
49
49
|
"aria-label": label,
|
|
50
50
|
title: label,
|
|
51
51
|
children: /* @__PURE__ */ jsx(ArrowUpIcon, { className: "h-4 w-4" })
|
|
@@ -64,8 +64,12 @@ function streamControls(chat, turn) {
|
|
|
64
64
|
queuedCount: chat.queuedMessages.length
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
+
function fitToContent(el) {
|
|
68
|
+
el.style.height = "auto";
|
|
69
|
+
el.style.height = `${el.scrollHeight}px`;
|
|
70
|
+
}
|
|
67
71
|
var draftsSwept = false;
|
|
68
|
-
|
|
72
|
+
function ChatInput({ onSend, disabled = false, placeholder, conversationId, onEditLastMessage, allowEmpty = false, attachments: attachmentsWanted = true, requireModel = true, inputLabel, sendLabel, sendTestId, slash, notices, activity, context, reserveContext = false, settingsLeft, settingsRight = /* @__PURE__ */ jsx(ComposerControls, {}), hint, turn, pastes, ref }) {
|
|
69
73
|
const [input, setInput] = useState(() => readDraft(conversationId));
|
|
70
74
|
useEffect(() => {
|
|
71
75
|
if (!draftsSwept) {
|
|
@@ -98,12 +102,22 @@ var ChatInput = forwardRef(function ChatInput({ onSend, disabled = false, placeh
|
|
|
98
102
|
textareaRef.current?.focus();
|
|
99
103
|
}
|
|
100
104
|
}), []);
|
|
101
|
-
|
|
102
|
-
if (textareaRef.current)
|
|
103
|
-
textareaRef.current.style.height = "auto";
|
|
104
|
-
textareaRef.current.style.height = `${textareaRef.current.scrollHeight}px`;
|
|
105
|
-
}
|
|
105
|
+
useLayoutEffect(() => {
|
|
106
|
+
if (textareaRef.current) fitToContent(textareaRef.current);
|
|
106
107
|
}, [input]);
|
|
108
|
+
useLayoutEffect(() => {
|
|
109
|
+
const el = textareaRef.current;
|
|
110
|
+
if (!el || typeof ResizeObserver === "undefined") return;
|
|
111
|
+
let width = el.clientWidth;
|
|
112
|
+
const observer = new ResizeObserver(() => {
|
|
113
|
+
if (el.clientWidth !== width) {
|
|
114
|
+
width = el.clientWidth;
|
|
115
|
+
fitToContent(el);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
observer.observe(el);
|
|
119
|
+
return () => observer.disconnect();
|
|
120
|
+
}, []);
|
|
107
121
|
const previousConversationRef = useRef(conversationId);
|
|
108
122
|
useEffect(() => {
|
|
109
123
|
if (previousConversationRef.current !== conversationId) {
|
|
@@ -119,7 +133,7 @@ var ChatInput = forwardRef(function ChatInput({ onSend, disabled = false, placeh
|
|
|
119
133
|
const uploadedCount = attachments.filter((a) => a.uploaded).length;
|
|
120
134
|
const pendingCount = attachments.length - uploadedCount;
|
|
121
135
|
const canFlushQueue = !isStreaming && queuedCount > 0 && !disabled;
|
|
122
|
-
const { canSend,
|
|
136
|
+
const { canSend, emphasized } = sendability({
|
|
123
137
|
hasText: input.trim().length > 0 || cards.length > 0,
|
|
124
138
|
canFlushQueue,
|
|
125
139
|
allowEmpty,
|
|
@@ -195,7 +209,7 @@ var ChatInput = forwardRef(function ChatInput({ onSend, disabled = false, placeh
|
|
|
195
209
|
}) : /* @__PURE__ */ jsx(SendButton, {
|
|
196
210
|
onClick: handleSubmit,
|
|
197
211
|
enabled: canSend,
|
|
198
|
-
|
|
212
|
+
emphasized,
|
|
199
213
|
label: sendLabel ?? t.sendMessage,
|
|
200
214
|
testId: sendTestId
|
|
201
215
|
});
|
|
@@ -297,6 +311,6 @@ var ChatInput = forwardRef(function ChatInput({ onSend, disabled = false, placeh
|
|
|
297
311
|
] })]
|
|
298
312
|
})]
|
|
299
313
|
});
|
|
300
|
-
}
|
|
314
|
+
}
|
|
301
315
|
//#endregion
|
|
302
316
|
export { ChatInput as default };
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { cx } from "../../cx.js";
|
|
2
|
-
import {
|
|
3
|
-
import { safeUrl } from "../../safeUrl.js";
|
|
2
|
+
import { EditIcon, RetryIcon } from "../../icons.js";
|
|
4
3
|
import { useStrings } from "../../components/Provider.js";
|
|
5
|
-
import { useCopy } from "../../components/useCopy.js";
|
|
6
4
|
import { Avatar } from "../../components/Avatar.js";
|
|
7
|
-
import {
|
|
5
|
+
import { Button } from "../../components/Button.js";
|
|
6
|
+
import { IconButton } from "../../components/IconButton.js";
|
|
7
|
+
import { Callout } from "../../components/Callout.js";
|
|
8
|
+
import { CopyButton } from "../../components/CopyButton.js";
|
|
9
|
+
import { formatDuration } from "../../format.js";
|
|
8
10
|
import { RelativeTime } from "../../components/relativeTime.js";
|
|
9
11
|
import { useChatConfig } from "../core/config.js";
|
|
10
12
|
import Markdown from "../ui/Markdown.js";
|
|
@@ -13,26 +15,19 @@ import { Reasoning } from "./Reasoning.js";
|
|
|
13
15
|
import AgentMessageParts from "./agent/AgentMessageParts.js";
|
|
14
16
|
import BranchNavigator from "./BranchNavigator.js";
|
|
15
17
|
import { UserMessageText } from "./PastedText.js";
|
|
18
|
+
import MessageAttachments from "./MessageAttachments.js";
|
|
16
19
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
17
20
|
import { memo, useEffect, useRef, useState } from "react";
|
|
18
21
|
import { DateTime } from "luxon";
|
|
19
22
|
//#region src/ai/components/ChatMessage.tsx
|
|
23
|
+
/** A message action: the chat's square, tinted from the ink on hover. */
|
|
24
|
+
var actionClasses = "size-7 hover:not-disabled:not-aria-disabled:chat-tint";
|
|
20
25
|
var COLLAPSE_THRESHOLD = 680;
|
|
21
26
|
function parseTimestamp(iso) {
|
|
22
27
|
if (!iso) return null;
|
|
23
28
|
const dt = DateTime.fromISO(iso);
|
|
24
29
|
return dt.isValid ? dt : null;
|
|
25
30
|
}
|
|
26
|
-
function triggerDownload(url, filename) {
|
|
27
|
-
const href = safeUrl(url);
|
|
28
|
-
if (!href) return;
|
|
29
|
-
const a = document.createElement("a");
|
|
30
|
-
a.href = href;
|
|
31
|
-
a.download = filename;
|
|
32
|
-
document.body.appendChild(a);
|
|
33
|
-
a.click();
|
|
34
|
-
document.body.removeChild(a);
|
|
35
|
-
}
|
|
36
31
|
function ChatMessage({ message, allMessages, isStreaming = false, latest = false, isEditing = false, showAuthor = false, currentUsername, attachmentDownloadUrl, onOpenAttachment, onNavigateBranch, onEdit, onSaveEdit, onCancelEdit, onRegenerate, onRetry, onOpenReasoning, onApprovalAnswer, flush }) {
|
|
37
32
|
const isUser = message.role === "user";
|
|
38
33
|
const isTool = message.role === "tool";
|
|
@@ -47,8 +42,6 @@ function ChatMessage({ message, allMessages, isStreaming = false, latest = false
|
|
|
47
42
|
const showTurnDurationLabel = !isUser && !isStreaming && !hasReasoning && (!!message.reasoningDuration || toolCallCount > 0);
|
|
48
43
|
const { messageMeta: t, thinking: tThinking } = useChatConfig().strings;
|
|
49
44
|
const { common } = useStrings();
|
|
50
|
-
const { copy, copied } = useCopy();
|
|
51
|
-
const [showActions, setShowActions] = useState(false);
|
|
52
45
|
const [editContent, setEditContent] = useState(message.content || "");
|
|
53
46
|
const textareaRef = useRef(null);
|
|
54
47
|
const contentRef = useRef(null);
|
|
@@ -106,16 +99,9 @@ function ChatMessage({ message, allMessages, isStreaming = false, latest = false
|
|
|
106
99
|
const timestamp = parseTimestamp(message.timestamp);
|
|
107
100
|
const totalTokens = message.tokensUsed?.total_tokens;
|
|
108
101
|
const collapsed = !isUser && collapsible && !expanded && !isStreaming && !latest;
|
|
109
|
-
const copyToClipboard = async () => {
|
|
110
|
-
if (message.content) await copy(message.content, { quiet: true });
|
|
111
|
-
};
|
|
112
102
|
return /* @__PURE__ */ jsx("div", {
|
|
113
103
|
role: "none",
|
|
114
104
|
className: cx("group w-full", isUser ? "pt-8 pb-5" : "py-3", !flush && "px-4"),
|
|
115
|
-
onMouseEnter: () => setShowActions(true),
|
|
116
|
-
onMouseLeave: () => setShowActions(false),
|
|
117
|
-
onFocus: () => setShowActions(true),
|
|
118
|
-
onBlur: () => setShowActions(false),
|
|
119
105
|
children: isEditing ? /* @__PURE__ */ jsxs("div", {
|
|
120
106
|
className: "w-full",
|
|
121
107
|
children: [/* @__PURE__ */ jsx("textarea", {
|
|
@@ -124,7 +110,8 @@ function ChatMessage({ message, allMessages, isStreaming = false, latest = false
|
|
|
124
110
|
onChange: handleTextareaChange,
|
|
125
111
|
onKeyDown: handleKeyDown,
|
|
126
112
|
className: "chat-composer block w-full min-h-[100px] max-h-[200px] overflow-y-auto px-4 py-3.5 rounded-[1.25rem] bg-(--theme-panel-bg) theme-text text-[1rem] leading-relaxed resize-none focus:outline-none",
|
|
127
|
-
placeholder: t.editPlaceholder
|
|
113
|
+
placeholder: t.editPlaceholder,
|
|
114
|
+
"aria-label": t.edit
|
|
128
115
|
}), /* @__PURE__ */ jsxs("div", {
|
|
129
116
|
className: "flex items-center justify-end gap-2 mt-2.5",
|
|
130
117
|
children: [/* @__PURE__ */ jsx("button", {
|
|
@@ -212,110 +199,47 @@ function ChatMessage({ message, allMessages, isStreaming = false, latest = false
|
|
|
212
199
|
className: "inline-flex items-center mt-1 text-[11px] italic theme-muted-text",
|
|
213
200
|
children: t.stopped
|
|
214
201
|
}),
|
|
215
|
-
hasError && /* @__PURE__ */
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
className: "flex items-center gap-1 px-2 py-1 text-xs font-medium text-red-700 hover:bg-red-500/15 rounded transition-colors",
|
|
227
|
-
children: [/* @__PURE__ */ jsx(RetryIcon, { className: "w-3 h-3" }), common.retry]
|
|
228
|
-
})
|
|
229
|
-
]
|
|
202
|
+
hasError && /* @__PURE__ */ jsx(Callout, {
|
|
203
|
+
tone: "error",
|
|
204
|
+
size: "sm",
|
|
205
|
+
className: "mt-2",
|
|
206
|
+
action: onRetry && /* @__PURE__ */ jsxs(Button, {
|
|
207
|
+
size: "sm",
|
|
208
|
+
variant: "outline",
|
|
209
|
+
onClick: () => onRetry(message.id),
|
|
210
|
+
children: [/* @__PURE__ */ jsx(RetryIcon, {}), common.retry]
|
|
211
|
+
}),
|
|
212
|
+
children: message.error
|
|
230
213
|
}),
|
|
231
|
-
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx(
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
if (isImage && downloadUrl) return /* @__PURE__ */ jsx("div", {
|
|
237
|
-
className: "block rounded-lg overflow-hidden border theme-border",
|
|
238
|
-
...onOpenAttachment ? {
|
|
239
|
-
onClick: () => onOpenAttachment(att),
|
|
240
|
-
role: "button",
|
|
241
|
-
style: { cursor: "pointer" }
|
|
242
|
-
} : {},
|
|
243
|
-
children: /* @__PURE__ */ jsx("img", {
|
|
244
|
-
src: downloadUrl,
|
|
245
|
-
alt: att.filename || "Image attachment",
|
|
246
|
-
className: "max-w-[200px] max-h-[200px] object-cover",
|
|
247
|
-
loading: "lazy"
|
|
248
|
-
})
|
|
249
|
-
}, att.id);
|
|
250
|
-
if (downloadUrl) return /* @__PURE__ */ jsxs("button", {
|
|
251
|
-
type: "button",
|
|
252
|
-
onClick: () => onOpenAttachment ? onOpenAttachment(att) : triggerDownload(downloadUrl, att.filename || "File"),
|
|
253
|
-
className: "inline-flex items-center gap-1.5 text-xs px-2.5 py-1.5 rounded-lg bg-(--theme-muted-panel-bg) hover:theme-hover transition-colors cursor-pointer",
|
|
254
|
-
children: [
|
|
255
|
-
/* @__PURE__ */ jsx(FileIcon, { className: "w-3.5 h-3.5 flex-shrink-0" }),
|
|
256
|
-
/* @__PURE__ */ jsx("span", {
|
|
257
|
-
className: "truncate max-w-[150px]",
|
|
258
|
-
children: att.filename || "File"
|
|
259
|
-
}),
|
|
260
|
-
att.size ? /* @__PURE__ */ jsxs("span", {
|
|
261
|
-
className: "theme-muted-text",
|
|
262
|
-
children: [
|
|
263
|
-
"(",
|
|
264
|
-
formatBytes(att.size),
|
|
265
|
-
")"
|
|
266
|
-
]
|
|
267
|
-
}) : null,
|
|
268
|
-
/* @__PURE__ */ jsx(DownloadIcon, { className: "w-3 h-3 flex-shrink-0" })
|
|
269
|
-
]
|
|
270
|
-
}, att.id);
|
|
271
|
-
return /* @__PURE__ */ jsxs("div", {
|
|
272
|
-
className: "inline-flex items-center gap-1.5 text-xs px-2.5 py-1.5 rounded-lg bg-(--theme-muted-panel-bg) theme-muted-text",
|
|
273
|
-
...onOpenAttachment ? {
|
|
274
|
-
onClick: () => onOpenAttachment(att),
|
|
275
|
-
role: "button",
|
|
276
|
-
style: { cursor: "pointer" }
|
|
277
|
-
} : {},
|
|
278
|
-
children: [
|
|
279
|
-
/* @__PURE__ */ jsx(FileIcon, { className: "w-3.5 h-3.5 flex-shrink-0" }),
|
|
280
|
-
/* @__PURE__ */ jsx("span", {
|
|
281
|
-
className: "truncate max-w-[150px]",
|
|
282
|
-
children: att.filename || "File"
|
|
283
|
-
}),
|
|
284
|
-
att.size ? /* @__PURE__ */ jsxs("span", {
|
|
285
|
-
className: "theme-muted-text",
|
|
286
|
-
children: [
|
|
287
|
-
"(",
|
|
288
|
-
formatBytes(att.size),
|
|
289
|
-
")"
|
|
290
|
-
]
|
|
291
|
-
}) : null
|
|
292
|
-
]
|
|
293
|
-
}, att.id);
|
|
294
|
-
})
|
|
214
|
+
message.attachments && message.attachments.length > 0 && /* @__PURE__ */ jsx(MessageAttachments, {
|
|
215
|
+
attachments: message.attachments,
|
|
216
|
+
downloadUrl: attachmentDownloadUrl,
|
|
217
|
+
onOpen: onOpenAttachment,
|
|
218
|
+
className: isRightAligned ? "justify-end" : void 0
|
|
295
219
|
}),
|
|
296
220
|
!isStreaming && !isEditing && /* @__PURE__ */ jsxs("div", {
|
|
297
|
-
className: cx("chat-actions flex items-center gap-0.5 transition-opacity duration-150", isRightAligned ? "absolute right-0 top-full -mr-1.5 mt-0.5" : "-ml-1.5 mt-2", isRightAligned &&
|
|
221
|
+
className: cx("chat-actions flex items-center gap-0.5 transition-opacity duration-150", isRightAligned ? "absolute right-0 top-full -mr-1.5 mt-0.5" : "-ml-1.5 mt-2", isRightAligned && "pointer-events-none opacity-0 group-focus-within:pointer-events-auto group-focus-within:opacity-100 group-hover:pointer-events-auto group-hover:opacity-100"),
|
|
298
222
|
children: [
|
|
299
|
-
/* @__PURE__ */ jsx(
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
223
|
+
message.content && /* @__PURE__ */ jsx(CopyButton, {
|
|
224
|
+
text: message.content ?? "",
|
|
225
|
+
label: t.copyLabel,
|
|
226
|
+
quiet: true,
|
|
227
|
+
size: "md",
|
|
228
|
+
className: actionClasses
|
|
305
229
|
}),
|
|
306
|
-
isUser && !isOtherUser && onEdit && /* @__PURE__ */ jsx(
|
|
307
|
-
|
|
230
|
+
isUser && !isOtherUser && onEdit && /* @__PURE__ */ jsx(IconButton, {
|
|
231
|
+
label: t.edit,
|
|
308
232
|
onClick: () => onEdit(message.id),
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
233
|
+
size: "md",
|
|
234
|
+
className: actionClasses,
|
|
235
|
+
icon: /* @__PURE__ */ jsx(EditIcon, {})
|
|
312
236
|
}),
|
|
313
|
-
!isUser && onRegenerate && /* @__PURE__ */ jsx(
|
|
314
|
-
|
|
237
|
+
!isUser && onRegenerate && /* @__PURE__ */ jsx(IconButton, {
|
|
238
|
+
label: t.regenerate,
|
|
315
239
|
onClick: () => onRegenerate(message.id),
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
240
|
+
size: "md",
|
|
241
|
+
className: actionClasses,
|
|
242
|
+
icon: /* @__PURE__ */ jsx(RetryIcon, {})
|
|
319
243
|
}),
|
|
320
244
|
!isUser && onNavigateBranch && /* @__PURE__ */ jsx(BranchNavigator, {
|
|
321
245
|
messages: allMessages,
|
|
@@ -323,7 +247,7 @@ function ChatMessage({ message, allMessages, isStreaming = false, latest = false
|
|
|
323
247
|
onNavigate: onNavigateBranch
|
|
324
248
|
}),
|
|
325
249
|
(timestamp || !isUser && (message.model || totalTokens)) && /* @__PURE__ */ jsxs("span", {
|
|
326
|
-
className: cx("chat-meta flex items-center gap-2 ml-2 text-xs tabular-nums theme-muted-text transition-opacity duration-150 select-none",
|
|
250
|
+
className: cx("chat-meta flex items-center gap-2 ml-2 text-xs tabular-nums theme-muted-text transition-opacity duration-150 select-none", "opacity-0 group-focus-within:opacity-100 group-hover:opacity-100"),
|
|
327
251
|
children: [
|
|
328
252
|
/* @__PURE__ */ jsx(RelativeTime, { value: timestamp }),
|
|
329
253
|
!isUser && message.model && /* @__PURE__ */ jsx("span", { children: message.model }),
|
|
@@ -3,6 +3,8 @@ import type { ApprovalAnswerValue, ChatMessage as Message } from '../types.js';
|
|
|
3
3
|
interface ChatMessageListProps {
|
|
4
4
|
messages: Message[];
|
|
5
5
|
allMessages: Message[];
|
|
6
|
+
/** The reply being written. Left unset, the list shows the chat provider's
|
|
7
|
+
* own stream; a host that streams elsewhere passes its reply, or null. */
|
|
6
8
|
streamingMessage?: Message | null;
|
|
7
9
|
queuedMessages?: Message[];
|
|
8
10
|
onRemoveQueued?: (id: string) => void;
|
|
@@ -30,7 +32,8 @@ interface ChatMessageListProps {
|
|
|
30
32
|
isStreaming?: boolean;
|
|
31
33
|
/** Rows without their own side padding, for a host that pads the column. */
|
|
32
34
|
flush?: boolean;
|
|
33
|
-
/** Names the list
|
|
35
|
+
/** Names the list, a live log, for assistive technology. Defaults to the
|
|
36
|
+
* chat strings' `thread.label`. */
|
|
34
37
|
label?: string;
|
|
35
38
|
/** Rendered after the last message, inside the scrolling column. */
|
|
36
39
|
footer?: ReactNode;
|
|
@@ -38,5 +41,5 @@ interface ChatMessageListProps {
|
|
|
38
41
|
* for the first frame is not announced twice. */
|
|
39
42
|
workingIndicator?: boolean;
|
|
40
43
|
}
|
|
41
|
-
export default function ChatMessageList({ messages, allMessages, streamingMessage, queuedMessages, onRemoveQueued, canRemoveQueued, queueDelivery, editingMessageId, showAuthor, currentUsername, onNavigateBranch, onEditMessage, onSaveEdit, onCancelEdit, onRegenerateMessage, onRetryMessage, onOpenReasoning, onApprovalAnswer, inputElement, isStreaming: isStreamingProp, flush, label, footer, workingIndicator, }: ChatMessageListProps): import("react").JSX.Element;
|
|
44
|
+
export default function ChatMessageList({ messages, allMessages, streamingMessage: streamingMessageProp, queuedMessages, onRemoveQueued, canRemoveQueued, queueDelivery, editingMessageId, showAuthor, currentUsername, onNavigateBranch, onEditMessage, onSaveEdit, onCancelEdit, onRegenerateMessage, onRetryMessage, onOpenReasoning, onApprovalAnswer, inputElement, isStreaming: isStreamingProp, flush, label, footer, workingIndicator, }: ChatMessageListProps): import("react").JSX.Element;
|
|
42
45
|
export {};
|