@marimo-team/islands 0.25.3-dev250 → 0.25.3-dev251
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/{ConnectedDataExplorerComponent-BBihxHrr.js → ConnectedDataExplorerComponent-DGOAQFtf.js} +11 -11
- package/dist/{ErrorBoundary-Ks8L_DFj.js → ErrorBoundary-CZ19wGWT.js} +7 -7
- package/dist/{abnfDiagram-VCTEODGH-DBcJVxYP.js → abnfDiagram-VCTEODGH-DzrZZXRD.js} +2 -2
- package/dist/{any-language-editor-jGaR0EAo.js → any-language-editor-Be7dA2VK.js} +3 -3
- package/dist/{architectureDiagram-5GKGNRK7-BcHZXF4S.js → architectureDiagram-5GKGNRK7-iF_snyFL.js} +1 -1
- package/dist/{button-B6RjDKJx.js → button-0-RqY1DW.js} +2 -1
- package/dist/{capabilities-CkVzWJEX.js → capabilities-B6yy_CBN.js} +1 -1
- package/dist/{chat-ui-DgaVxFrc.js → chat-ui-zbfp80GW.js} +1547 -1482
- package/dist/{check-Z_vtI3OL.js → check-CSvxZk5I.js} +1 -1
- package/dist/{chunk-IMKFNOWR-CTZlwBAA.js → chunk-IMKFNOWR-B7xytD4B.js} +1 -1
- package/dist/{chunk-SHT3W25Y-53g_RZHm.js → chunk-SHT3W25Y-I8ZFP5L1.js} +1 -1
- package/dist/{chunk-SVP7TREG-P6abNGV_.js → chunk-SVP7TREG-Di-uAPdT.js} +1 -1
- package/dist/{chunk-TICWLB2K-BTJJqkyF.js → chunk-TICWLB2K-BFpUy0ud.js} +1 -1
- package/dist/{classDiagram-ZZMXUADV-BUGqOrTm.js → classDiagram-ZZMXUADV-Cqm4JGpx.js} +2 -2
- package/dist/{classDiagram-v2-VYDZK3BY-CXpQvO-s.js → classDiagram-v2-VYDZK3BY-DFHRJpN3.js} +2 -2
- package/dist/{code-visibility-CCCqFZYh.js → code-visibility-D2D_sL1T.js} +4 -4
- package/dist/{common-JXDK9IjO.js → common-DSIM5DHJ.js} +262 -262
- package/dist/{config-DbjzjwxX.js → config-mwEjAmvP.js} +2 -2
- package/dist/{copy-icon-CG57cxwb.js → copy-icon-DD8bdw4L.js} +3 -3
- package/dist/{createReducer-DePYJ0F3.js → createReducer-Bx81cw8_.js} +1 -1
- package/dist/{cynefinDiagram-5FMLGOSQ-DOcnl8wW.js → cynefinDiagram-5FMLGOSQ-cuGOeTBC.js} +1 -1
- package/dist/{dagre-GXQ25YYZ-CuHR9QfG.js → dagre-GXQ25YYZ-DJ76aC4k.js} +1 -1
- package/dist/{data-grid-overlay-editor-QAJSeJpH.js → data-grid-overlay-editor-ByfOIO6H.js} +1 -1
- package/dist/{diagram-S7CK7UJ4-BPiG4kso.js → diagram-S7CK7UJ4-DLLc0sw7.js} +1 -1
- package/dist/{diagram-UQ7AKVKN-_piBOvOC.js → diagram-UQ7AKVKN-Tz_d6qmk.js} +1 -1
- package/dist/{diagram-VX7I27RA-DCzVeJ8M.js → diagram-VX7I27RA-D7SzPrDN.js} +1 -1
- package/dist/{diagram-Z3DM3KII-D64CF1jQ.js → diagram-Z3DM3KII-qr37XV58.js} +1 -1
- package/dist/{dialog-DsZ49mmU.js → dialog-BHYPX87J.js} +3 -3
- package/dist/{dropdown-menu-BRiE7Vnp.js → dropdown-menu-Blu7V6Mk.js} +6 -6
- package/dist/{ebnfDiagram-PWID7BFC-BapQPML-.js → ebnfDiagram-PWID7BFC-BKOQb4J0.js} +2 -2
- package/dist/{erDiagram-RLTQ6QDP-CNQvC2_Q.js → erDiagram-RLTQ6QDP-CM15Vq68.js} +1 -1
- package/dist/{error-banner-IsonnvA0.js → error-banner-DbRFOd2O.js} +2 -2
- package/dist/{error-entries-CRPfxMqm.js → error-entries-BuIE3Ius.js} +9 -9
- package/dist/{feedback-button-Bg7zGcid.js → feedback-button-VT03EJ1h.js} +7 -7
- package/dist/{flowDiagram-HODETNUW-BBt6S6oe.js → flowDiagram-HODETNUW-Dt3N5yFT.js} +2 -2
- package/dist/{formats-BK4VefeF.js → formats-gGospKWJ.js} +2 -2
- package/dist/{glide-data-editor-BuFe7QfV.js → glide-data-editor-C94G7kD7.js} +10 -10
- package/dist/{glide-utils-CQddGpa-.js → glide-utils-qbkRZpEy.js} +3 -3
- package/dist/{globals-8EK96XwF.js → globals-D7JZ5hgJ.js} +2 -2
- package/dist/{html-to-image-Gx4q3ZoD.js → html-to-image-BXrAd5q8.js} +460 -455
- package/dist/{infoDiagram-27XIBGKW-Hd8Ifz82.js → infoDiagram-27XIBGKW-C7axJMCl.js} +1 -1
- package/dist/{ishikawaDiagram-5VMMS53U-CP7hnHWx.js → ishikawaDiagram-5VMMS53U-CdC9Eur7.js} +1 -1
- package/dist/{kanban-definition-UXKFOSKX-CX91sa9b.js → kanban-definition-UXKFOSKX-BHnMIgD7.js} +1 -1
- package/dist/{loader-BisjOLiW.js → loader-BVEtQ4F3.js} +1 -1
- package/dist/main.js +236 -236
- package/dist/{mermaid-Djb3Ni9t.js → mermaid-DFYN_PXd.js} +35 -35
- package/dist/{mindmap-definition-YA3MSWOX-DgCNo07O.js → mindmap-definition-YA3MSWOX-BagHoCGU.js} +1 -1
- package/dist/{number-overlay-editor-BDJF1c8h.js → number-overlay-editor-CdcscCHp.js} +1 -1
- package/dist/{pegDiagram-XKGWAZYB-SGJhnIKo.js → pegDiagram-XKGWAZYB-8IIZczip.js} +2 -2
- package/dist/{pieDiagram-E7YTZNPT-1stXIWCQ.js → pieDiagram-E7YTZNPT-CE6dKBIr.js} +1 -1
- package/dist/{process-output-D2ISIyIs.js → process-output-D2ZjxrHe.js} +4 -4
- package/dist/{railroadDiagram-O6MQD6OU-DY1mojzB.js → railroadDiagram-O6MQD6OU-CkexPq3b.js} +2 -2
- package/dist/{requirementDiagram-BXWQKSXE-gHzhUp0D.js → requirementDiagram-BXWQKSXE-B0-OkuAe.js} +1 -1
- package/dist/{reveal-component-B_hNJfj-.js → reveal-component-Cr9euMM2.js} +8 -8
- package/dist/{select-BSxlITBo.js → select-CcidPqlM.js} +5 -5
- package/dist/{sequenceDiagram-WJ2MYXX4-rjPtD9fB.js → sequenceDiagram-WJ2MYXX4-Dxysg8DX.js} +1 -1
- package/dist/{spec-Dq8RNplp.js → spec-ZwfZcgsm.js} +4 -4
- package/dist/{stateDiagram-D77RDMKH-DMNxjUxV.js → stateDiagram-D77RDMKH-DTEN3-OJ.js} +2 -2
- package/dist/{stateDiagram-v2-MP3YSRHH-CumAaqGo.js → stateDiagram-v2-MP3YSRHH-vktk3Xc5.js} +2 -2
- package/dist/{strings-BGW-fXVJ.js → strings-BYJNyKmg.js} +3 -3
- package/dist/style.css +1 -1
- package/dist/{swimlanes-42K2YHIH-BU14_Tej.js → swimlanes-42K2YHIH-Cjveh9OM.js} +1 -1
- package/dist/{swimlanesDiagram-VR7AAH4N-CieAnPqJ.js → swimlanesDiagram-VR7AAH4N-Bdr7Ev_2.js} +2 -2
- package/dist/{swiper-component-Dir1o8ml.js → swiper-component-Dvj-goaD.js} +2 -2
- package/dist/{timeline-definition-24CTP7MA-CrVj4E1K.js → timeline-definition-24CTP7MA-KIuDcefn.js} +1 -1
- package/dist/{toast-BWIPi3aF.js → toast-CkB5Jq9K.js} +4 -4
- package/dist/{tooltip-C3UnvsRe.js → tooltip-Bzl4k00l.js} +2 -2
- package/dist/{use-restore-focus-BWO0z1lo.js → use-restore-focus-CmflVLWJ.js} +1 -1
- package/dist/{useDateFormatter-ChB4eyim.js → useDateFormatter-CYo5fm8s.js} +2 -2
- package/dist/{useIframeCapabilities-cMNQ80CK.js → useIframeCapabilities-BIolGsF1.js} +1 -1
- package/dist/{useLifecycle-BquH9ET-.js → useLifecycle-GNgvNwI-.js} +2 -2
- package/dist/{useTheme-DgOLVISn.js → useTheme-BZ2GGLgm.js} +141 -139
- package/dist/{vega-component-Bwg_Kuh-.js → vega-component-DOtem7Hf.js} +7 -7
- package/dist/{vennDiagram-4TSXK5OY-ZLxQ8yhm.js → vennDiagram-4TSXK5OY-DrIOUHfb.js} +1 -1
- package/dist/{wardleyDiagram-VM6X3IG4-D88pcLY1.js → wardleyDiagram-VM6X3IG4-CJNjf4OH.js} +1 -1
- package/dist/{xychartDiagram-S5SC5T6Z-_13d4g8g.js → xychartDiagram-S5SC5T6Z-DEshFho-.js} +1 -1
- package/package.json +1 -1
- package/src/__tests__/fixtures/pair-config.ts +1 -1
- package/src/components/app-config/__tests__/state.test.tsx +50 -0
- package/src/components/app-config/ai-config.tsx +1 -1
- package/src/components/chat/__tests__/capabilities-popover.test.tsx +0 -1
- package/src/components/chat/__tests__/chat-display.test.tsx +125 -0
- package/src/components/chat/__tests__/chat-markdown.test.tsx +43 -0
- package/src/components/chat/__tests__/chat-utils.test.ts +51 -1
- package/src/components/chat/acp/__tests__/agent-panel-initialization.test.tsx +1 -1
- package/src/components/chat/acp/__tests__/agent-panel.test.tsx +22 -17
- package/src/components/chat/acp/agent-panel.tsx +4 -3
- package/src/components/chat/acp/blocks.tsx +10 -10
- package/src/components/chat/acp/common.tsx +4 -5
- package/src/components/chat/acp/model-selector.tsx +1 -1
- package/src/components/chat/capabilities-popover.tsx +1 -6
- package/src/components/chat/chat-components.tsx +7 -4
- package/src/components/chat/chat-display.tsx +51 -6
- package/src/components/chat/chat-history-popover.tsx +6 -1
- package/src/components/chat/chat-markdown.tsx +15 -0
- package/src/components/chat/chat-panel.tsx +105 -119
- package/src/components/chat/chat-typography.css +108 -0
- package/src/components/chat/chat-utils.ts +8 -3
- package/src/components/chat/notebook-access-selector.tsx +1 -1
- package/src/components/chat/reasoning-accordion.tsx +3 -3
- package/src/components/chat/tool-call/tool-activity-group.tsx +49 -0
- package/src/components/chat/tool-call/tool-history-row.tsx +3 -30
- package/src/components/chat/tool-call/tool-result.tsx +1 -1
- package/src/components/chat/use-chat-generation.ts +19 -0
- package/src/components/editor/actions/__tests__/pair-with-agent-commands.test.ts +18 -37
- package/src/components/editor/actions/__tests__/pair-with-agent-modal.test.tsx +5 -8
- package/src/components/editor/actions/__tests__/pair-with-agent.test.tsx +5 -19
- package/src/components/editor/actions/pair-with-agent-commands.ts +0 -1
- package/src/components/editor/actions/pair-with-agent-modal.tsx +7 -11
- package/src/components/editor/actions/pair-with-agent.tsx +3 -31
- package/src/components/editor/actions/useCellActionButton.tsx +1 -1
- package/src/components/editor/ai/ai-completion-editor.tsx +1 -1
- package/src/components/editor/ai/prompt-input.tsx +189 -0
- package/src/components/editor/cell/StagedAICell.tsx +3 -3
- package/src/components/editor/cell/code/cell-editor.tsx +14 -1
- package/src/components/editor/chrome/panels/panel-header.tsx +13 -0
- package/src/components/editor/chrome/types.ts +1 -1
- package/src/components/editor/chrome/wrapper/__tests__/pending-ai-cells.test.tsx +53 -45
- package/src/components/editor/chrome/wrapper/__tests__/useAskAiAboutCell.test.tsx +58 -0
- package/src/components/editor/chrome/wrapper/app-chrome.tsx +89 -72
- package/src/components/editor/chrome/wrapper/pending-ai-cells.tsx +5 -8
- package/src/components/editor/chrome/wrapper/useAskAiAboutCell.ts +36 -0
- package/src/components/editor/renderers/__tests__/add-cell-buttons.test.tsx +18 -0
- package/src/components/editor/renderers/cell-array.tsx +10 -67
- package/src/components/markdown/markdown-renderer.tsx +35 -20
- package/src/components/mcp/mcp-status-indicator.tsx +18 -14
- package/src/core/ai/__tests__/staged-cells.test.ts +1 -467
- package/src/core/ai/context/context.ts +2 -0
- package/src/core/ai/context/providers/__tests__/cell.test.ts +49 -0
- package/src/core/ai/context/providers/cell.ts +54 -0
- package/src/core/ai/staged-cells.ts +4 -280
- package/src/core/ai/state.ts +3 -0
- package/src/core/codemirror/__tests__/setup.test.ts +32 -0
- package/src/core/codemirror/cells/state.ts +1 -0
- package/src/core/codemirror/cm.ts +5 -1
- package/src/core/codemirror/config/types.ts +1 -1
- package/src/core/codemirror/language/languages/python.ts +3 -3
- package/src/core/codemirror/placeholder/__tests__/extensions.test.ts +16 -0
- package/src/core/codemirror/placeholder/extensions.ts +57 -19
- package/src/core/hotkeys/hotkeys.ts +2 -1
- package/src/core/notebook/document/__tests__/codemirror.test.ts +1 -0
- package/src/plugins/impl/chat/__tests__/chat-prompts.test.tsx +1 -1
- package/src/plugins/impl/chat/chat-ui.tsx +1 -1
- package/src/components/editor/ai/__tests__/staged-cell-submission.test.ts +0 -106
- package/src/components/editor/ai/add-cell-with-ai.tsx +0 -506
- package/src/components/editor/ai/staged-cell-submission.ts +0 -46
- package/src/components/editor/cell/__tests__/StagedAICell.test.tsx +0 -66
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import type {
|
|
4
4
|
ChatAddToolApproveResponseFunction,
|
|
5
5
|
DataUIPart,
|
|
6
|
+
DynamicToolUIPart,
|
|
6
7
|
ToolUIPart,
|
|
7
8
|
UIMessage,
|
|
8
9
|
} from "ai";
|
|
@@ -11,9 +12,10 @@ import React from "react";
|
|
|
11
12
|
import { renderHTML } from "@/plugins/core/RenderHTML";
|
|
12
13
|
import { logNever } from "@/utils/assertNever";
|
|
13
14
|
import { Logger } from "@/utils/Logger";
|
|
14
|
-
import {
|
|
15
|
+
import { ChatMarkdown } from "./chat-markdown";
|
|
15
16
|
import { AttachmentRenderer, SourceChip } from "./chat-components";
|
|
16
17
|
import { ReasoningAccordion } from "./reasoning-accordion";
|
|
18
|
+
import { ToolActivityGroup } from "./tool-call/tool-activity-group";
|
|
17
19
|
import { ToolCallView } from "./tool-call/tool-call-view";
|
|
18
20
|
|
|
19
21
|
export const renderUIMessage = ({
|
|
@@ -30,9 +32,52 @@ export const renderUIMessage = ({
|
|
|
30
32
|
isActive: boolean;
|
|
31
33
|
addToolApprovalResponse?: ChatAddToolApproveResponseFunction;
|
|
32
34
|
}) => {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
const content: React.ReactNode[] = [];
|
|
36
|
+
let activity: { part: ToolUIPart | DynamicToolUIPart; index: number }[] = [];
|
|
37
|
+
|
|
38
|
+
const flushActivity = () => {
|
|
39
|
+
if (activity.length === 0) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
content.push(
|
|
43
|
+
<ToolActivityGroup
|
|
44
|
+
key={activity[0].index}
|
|
45
|
+
tools={activity.map(({ part }) => ({
|
|
46
|
+
toolName: part.type === "dynamic-tool" ? part.toolName : part.type,
|
|
47
|
+
state: part.state,
|
|
48
|
+
}))}
|
|
49
|
+
isActive={isActive && isLast}
|
|
50
|
+
>
|
|
51
|
+
{activity.map(({ part, index }) => renderUIMessagePart(part, index))}
|
|
52
|
+
</ToolActivityGroup>,
|
|
53
|
+
);
|
|
54
|
+
activity = [];
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
message.parts.forEach((part, index) => {
|
|
58
|
+
// SDK step boundaries and invisible parts should not split visible activity.
|
|
59
|
+
if (
|
|
60
|
+
part.type === "step-start" ||
|
|
61
|
+
isDataPart(part) ||
|
|
62
|
+
(part.type === "text" && !part.text.trim())
|
|
63
|
+
) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (
|
|
67
|
+
(isToolPart(part) || part.type === "dynamic-tool") &&
|
|
68
|
+
part.state !== "output-error" &&
|
|
69
|
+
part.state !== "output-denied" &&
|
|
70
|
+
part.state !== "approval-requested"
|
|
71
|
+
) {
|
|
72
|
+
activity.push({ part, index });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
flushActivity();
|
|
76
|
+
content.push(renderUIMessagePart(part, index));
|
|
77
|
+
});
|
|
78
|
+
flushActivity();
|
|
79
|
+
|
|
80
|
+
return content;
|
|
36
81
|
|
|
37
82
|
function renderUIMessagePart(
|
|
38
83
|
part: UIMessage["parts"][number],
|
|
@@ -46,7 +91,7 @@ export const renderUIMessage = ({
|
|
|
46
91
|
toolName={part.type}
|
|
47
92
|
result={part.output}
|
|
48
93
|
errorText={part.state === "output-error" ? part.errorText : undefined}
|
|
49
|
-
className="my-
|
|
94
|
+
className="my-1"
|
|
50
95
|
state={part.state}
|
|
51
96
|
input={part.input}
|
|
52
97
|
approval={part.approval}
|
|
@@ -75,7 +120,7 @@ export const renderUIMessage = ({
|
|
|
75
120
|
</React.Fragment>
|
|
76
121
|
);
|
|
77
122
|
}
|
|
78
|
-
return <
|
|
123
|
+
return <ChatMarkdown key={index} content={part.text} />;
|
|
79
124
|
case "reasoning":
|
|
80
125
|
return (
|
|
81
126
|
<ReasoningAccordion
|
|
@@ -92,7 +92,12 @@ export const ChatHistoryPopover: React.FC<ChatHistoryPopoverProps> = ({
|
|
|
92
92
|
<Popover open={open} onOpenChange={setOpen}>
|
|
93
93
|
<Tooltip content="Previous chats">
|
|
94
94
|
<PopoverTrigger asChild={true}>
|
|
95
|
-
<Button
|
|
95
|
+
<Button
|
|
96
|
+
className="chat-control"
|
|
97
|
+
variant="text"
|
|
98
|
+
size="icon"
|
|
99
|
+
aria-label="Previous chats"
|
|
100
|
+
>
|
|
96
101
|
<ClockIcon className="h-4 w-4" />
|
|
97
102
|
</Button>
|
|
98
103
|
</PopoverTrigger>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
import { useAtomValue } from "jotai";
|
|
4
|
+
import { MarkdownRenderer } from "@/components/markdown/markdown-renderer";
|
|
5
|
+
import { aiAtom } from "@/core/config/config";
|
|
6
|
+
|
|
7
|
+
export function ChatMarkdown({ content }: { content: string }) {
|
|
8
|
+
const mode = useAtomValue(aiAtom)?.mode;
|
|
9
|
+
return (
|
|
10
|
+
<MarkdownRenderer
|
|
11
|
+
content={content}
|
|
12
|
+
allowNotebookInsertion={mode !== "agent" && mode !== "code_mode"}
|
|
13
|
+
/>
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -13,15 +13,14 @@ import {
|
|
|
13
13
|
import { useAtom, useAtomValue, useSetAtom, useStore } from "jotai";
|
|
14
14
|
import {
|
|
15
15
|
BotMessageSquareIcon,
|
|
16
|
-
ArrowRightIcon,
|
|
17
16
|
Loader2,
|
|
18
17
|
PlusIcon,
|
|
19
|
-
SparklesIcon,
|
|
20
18
|
SettingsIcon,
|
|
21
19
|
} from "lucide-react";
|
|
22
|
-
import { memo, useEffect, useRef, useState } from "react";
|
|
20
|
+
import { memo, useEffect, useMemo, useRef, useState } from "react";
|
|
23
21
|
import useEvent from "react-use-event-hook";
|
|
24
22
|
import { Button } from "@/components/ui/button";
|
|
23
|
+
import { LoadingEllipsis } from "@/components/icons/loading-ellipsis";
|
|
25
24
|
import { replaceMessagesInChat } from "@/core/ai/chat-utils";
|
|
26
25
|
import { useAIConfigActions } from "@/core/ai/config";
|
|
27
26
|
import { AI_SDK_UI_THROTTLE_MS } from "@/core/ai/constants";
|
|
@@ -50,20 +49,19 @@ import { AIModelDropdown } from "../ai/ai-model-dropdown";
|
|
|
50
49
|
import { useOpenSettingsToTab } from "../app-config/state";
|
|
51
50
|
import {
|
|
52
51
|
PairWithAgentBanner,
|
|
53
|
-
|
|
52
|
+
usePairWithAgentModal,
|
|
54
53
|
} from "../editor/actions/pair-with-agent";
|
|
55
|
-
import {
|
|
56
|
-
import { PromptInput } from "../editor/ai/add-cell-with-ai";
|
|
54
|
+
import { PromptInput } from "../editor/ai/prompt-input";
|
|
57
55
|
import {
|
|
58
56
|
addContextCompletion,
|
|
59
|
-
CONTEXT_TRIGGER,
|
|
60
57
|
isContextAttachment,
|
|
61
58
|
resolveChatContext,
|
|
62
59
|
} from "../editor/ai/completion-utils";
|
|
63
60
|
import { StreamingChunkTransport } from "../editor/ai/transport/chat-transport";
|
|
61
|
+
import { PanelHeaderActions } from "../editor/chrome/panels/panel-header";
|
|
64
62
|
import { PanelEmptyState } from "../editor/chrome/panels/empty-state";
|
|
65
63
|
import { CopyClipboardIcon } from "../icons/copy-icon";
|
|
66
|
-
import
|
|
64
|
+
import "./chat-typography.css";
|
|
67
65
|
import { MCPStatusIndicator } from "../mcp/mcp-status-indicator";
|
|
68
66
|
import { Tooltip, TooltipProvider } from "../ui/tooltip";
|
|
69
67
|
import {
|
|
@@ -100,6 +98,7 @@ import { getCodes } from "@/core/codemirror/copilot/getCodes";
|
|
|
100
98
|
import { focusInputAndMoveToEnd } from "@/core/codemirror/utils";
|
|
101
99
|
import ScrollToBottomButton from "./acp/scroll-to-bottom-button";
|
|
102
100
|
import { useChatControllerId } from "./use-chat-controller-id";
|
|
101
|
+
import { useChatGeneration } from "./use-chat-generation";
|
|
103
102
|
|
|
104
103
|
// Default mode for the AI
|
|
105
104
|
const DEFAULT_MODE = "ask";
|
|
@@ -116,7 +115,7 @@ const QueuedMessageDisplay = memo(
|
|
|
116
115
|
|
|
117
116
|
return (
|
|
118
117
|
<div className="flex justify-end">
|
|
119
|
-
<div className="w-[95%] bg-background border border-dashed p-2 rounded-
|
|
118
|
+
<div className="w-[95%] bg-background border border-dashed p-2 rounded-[10px] opacity-70">
|
|
120
119
|
{fileParts.map((filePart, idx) => (
|
|
121
120
|
<AttachmentRenderer attachment={filePart} key={idx} />
|
|
122
121
|
))}
|
|
@@ -149,40 +148,41 @@ const ChatHeader: React.FC<ChatHeaderProps> = ({
|
|
|
149
148
|
const { handleClick } = useOpenSettingsToTab();
|
|
150
149
|
|
|
151
150
|
return (
|
|
152
|
-
<
|
|
153
|
-
<
|
|
154
|
-
<
|
|
155
|
-
aria-label="New chat"
|
|
156
|
-
variant="text"
|
|
157
|
-
size="icon"
|
|
158
|
-
onClick={onNewChat}
|
|
159
|
-
>
|
|
160
|
-
<PlusIcon className="h-4 w-4" />
|
|
161
|
-
</Button>
|
|
162
|
-
</Tooltip>
|
|
163
|
-
<div className="flex items-center gap-2">
|
|
164
|
-
<Tooltip content="Pair your agent">
|
|
165
|
-
<PairWithAgentButton className="mr-1" label="Pair" />
|
|
166
|
-
</Tooltip>
|
|
167
|
-
<MCPStatusIndicator />
|
|
168
|
-
<Tooltip content="AI Settings">
|
|
151
|
+
<PanelHeaderActions>
|
|
152
|
+
<div className="mo-ai-panel flex w-full shrink-0 items-center font-sans text-sm">
|
|
153
|
+
<div className="flex w-full items-center gap-1">
|
|
169
154
|
<Button
|
|
170
|
-
variant="
|
|
171
|
-
size="
|
|
172
|
-
className="
|
|
173
|
-
onClick={
|
|
155
|
+
variant="ghost"
|
|
156
|
+
size="sm"
|
|
157
|
+
className="chat-control gap-1.5 font-normal"
|
|
158
|
+
onClick={onNewChat}
|
|
174
159
|
>
|
|
175
|
-
<
|
|
160
|
+
<PlusIcon className="size-4" aria-hidden={true} />
|
|
161
|
+
New chat
|
|
176
162
|
</Button>
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
163
|
+
<ChatHistoryPopover
|
|
164
|
+
activeChatId={activeChatId}
|
|
165
|
+
setActiveChat={setActiveChat}
|
|
166
|
+
onDeleteChats={onDeleteChats}
|
|
167
|
+
isLoading={isLoading}
|
|
168
|
+
/>
|
|
169
|
+
<div className="ml-auto flex items-center gap-2">
|
|
170
|
+
<MCPStatusIndicator />
|
|
171
|
+
<Tooltip content="AI Settings">
|
|
172
|
+
<Button
|
|
173
|
+
className="chat-control"
|
|
174
|
+
aria-label="AI Settings"
|
|
175
|
+
variant="ghost"
|
|
176
|
+
size="icon"
|
|
177
|
+
onClick={() => handleClick("ai")}
|
|
178
|
+
>
|
|
179
|
+
<SettingsIcon className="size-4" aria-hidden={true} />
|
|
180
|
+
</Button>
|
|
181
|
+
</Tooltip>
|
|
182
|
+
</div>
|
|
183
|
+
</div>
|
|
184
184
|
</div>
|
|
185
|
-
</
|
|
185
|
+
</PanelHeaderActions>
|
|
186
186
|
);
|
|
187
187
|
};
|
|
188
188
|
|
|
@@ -216,14 +216,14 @@ const ChatMessageDisplay: React.FC<ChatMessageProps> = memo(
|
|
|
216
216
|
);
|
|
217
217
|
|
|
218
218
|
return (
|
|
219
|
-
<div className="w-[95%] bg-background border p-1 rounded-
|
|
219
|
+
<div className="w-[95%] bg-background border p-1 rounded-[10px]">
|
|
220
220
|
{fileParts?.map((filePart, idx) => (
|
|
221
221
|
<AttachmentRenderer attachment={filePart} key={idx} />
|
|
222
222
|
))}
|
|
223
223
|
<PromptInput
|
|
224
224
|
key={message.id}
|
|
225
225
|
value={content}
|
|
226
|
-
placeholder="Type your message
|
|
226
|
+
placeholder="Type your message. Use @ to reference variables and cells."
|
|
227
227
|
onChange={() => {
|
|
228
228
|
// noop
|
|
229
229
|
}}
|
|
@@ -249,7 +249,7 @@ const ChatMessageDisplay: React.FC<ChatMessageProps> = memo(
|
|
|
249
249
|
|
|
250
250
|
return (
|
|
251
251
|
<div className="w-[95%] wrap-break-word">
|
|
252
|
-
<div className="absolute right-1 top-1 opacity-0 group-hover:opacity-100 transition-opacity">
|
|
252
|
+
<div className="absolute right-1 top-1 opacity-0 group-hover:opacity-100 group-focus-within:opacity-100 transition-opacity">
|
|
253
253
|
<CopyClipboardIcon className="h-3 w-3" value={content || ""} />
|
|
254
254
|
</div>
|
|
255
255
|
{renderUIMessage({
|
|
@@ -311,22 +311,22 @@ const ChatInputFooter: React.FC<ChatInputFooterProps> = memo(
|
|
|
311
311
|
|
|
312
312
|
return (
|
|
313
313
|
<TooltipProvider>
|
|
314
|
-
<div className="px-3 py-2 border-t border-border/20 flex
|
|
315
|
-
<div className="flex flex-
|
|
314
|
+
<div className="chat-input-footer px-3 py-2 border-t border-border/20 flex items-center gap-2">
|
|
315
|
+
<div className="chat-input-selectors flex min-w-0 flex-1 items-center gap-1">
|
|
316
316
|
<NotebookAccessSelector
|
|
317
317
|
value={currentMode}
|
|
318
318
|
onValueChange={saveModeChange}
|
|
319
319
|
/>
|
|
320
320
|
<AIModelDropdown
|
|
321
321
|
placeholder="Model"
|
|
322
|
-
triggerClassName="h-6 text-xs
|
|
322
|
+
triggerClassName="chat-control chat-selector h-6 text-xs rounded-sm min-w-0 max-w-[200px] flex-1"
|
|
323
323
|
iconSize="small"
|
|
324
324
|
showAddCustomModelDocs={true}
|
|
325
325
|
forRole="chat"
|
|
326
326
|
/>
|
|
327
|
-
<CapabilitiesPopover />
|
|
328
327
|
</div>
|
|
329
|
-
<div className="flex
|
|
328
|
+
<div className="chat-input-actions flex shrink-0 items-center gap-0.5 ml-auto">
|
|
329
|
+
<CapabilitiesPopover />
|
|
330
330
|
<AddContextButton
|
|
331
331
|
handleAddContext={onAddContext}
|
|
332
332
|
isLoading={isLoading}
|
|
@@ -354,9 +354,7 @@ const ChatInputFooter: React.FC<ChatInputFooterProps> = memo(
|
|
|
354
354
|
ChatInputFooter.displayName = "ChatInputFooter";
|
|
355
355
|
|
|
356
356
|
interface ChatInputProps {
|
|
357
|
-
placeholder?: string;
|
|
358
357
|
input: string;
|
|
359
|
-
inputClassName?: string;
|
|
360
358
|
setInput: (value: string) => void;
|
|
361
359
|
onSubmit: (e: KeyboardEvent | undefined, value: string) => void;
|
|
362
360
|
inputRef: React.RefObject<ReactCodeMirrorRef | null>;
|
|
@@ -369,9 +367,7 @@ interface ChatInputProps {
|
|
|
369
367
|
|
|
370
368
|
const ChatInput: React.FC<ChatInputProps> = memo(
|
|
371
369
|
({
|
|
372
|
-
placeholder,
|
|
373
370
|
input,
|
|
374
|
-
inputClassName,
|
|
375
371
|
setInput,
|
|
376
372
|
onSubmit,
|
|
377
373
|
inputRef,
|
|
@@ -381,6 +377,20 @@ const ChatInput: React.FC<ChatInputProps> = memo(
|
|
|
381
377
|
onAddFiles,
|
|
382
378
|
onClose,
|
|
383
379
|
}) => {
|
|
380
|
+
const openPairWithAgentModal = usePairWithAgentModal();
|
|
381
|
+
const placeholderAction = useMemo(
|
|
382
|
+
() =>
|
|
383
|
+
isWasm()
|
|
384
|
+
? undefined
|
|
385
|
+
: {
|
|
386
|
+
beforeText: "Type your message or ",
|
|
387
|
+
linkText: "pair your own coding agent",
|
|
388
|
+
afterText: ". Use @ to reference variables and cells.",
|
|
389
|
+
onClick: openPairWithAgentModal,
|
|
390
|
+
},
|
|
391
|
+
[openPairWithAgentModal],
|
|
392
|
+
);
|
|
393
|
+
|
|
384
394
|
const handleSendClick = useEvent(() => {
|
|
385
395
|
if (input.trim()) {
|
|
386
396
|
onSubmit(undefined, input);
|
|
@@ -388,8 +398,8 @@ const ChatInput: React.FC<ChatInputProps> = memo(
|
|
|
388
398
|
});
|
|
389
399
|
|
|
390
400
|
return (
|
|
391
|
-
<div className="relative shrink-0 flex flex-col
|
|
392
|
-
<div className=
|
|
401
|
+
<div className="relative shrink-0 flex flex-col">
|
|
402
|
+
<div className="px-2 py-1.5">
|
|
393
403
|
<PromptInput
|
|
394
404
|
className="max-h-[400px]"
|
|
395
405
|
inputRef={inputRef}
|
|
@@ -398,7 +408,8 @@ const ChatInput: React.FC<ChatInputProps> = memo(
|
|
|
398
408
|
onSubmit={onSubmit}
|
|
399
409
|
onClose={onClose}
|
|
400
410
|
onAddFiles={onAddFiles}
|
|
401
|
-
placeholder=
|
|
411
|
+
placeholder="Type your message. Use @ to reference variables and cells."
|
|
412
|
+
placeholderAction={placeholderAction}
|
|
402
413
|
/>
|
|
403
414
|
</div>
|
|
404
415
|
<ChatInputFooter
|
|
@@ -417,26 +428,6 @@ const ChatInput: React.FC<ChatInputProps> = memo(
|
|
|
417
428
|
|
|
418
429
|
ChatInput.displayName = "ChatInput";
|
|
419
430
|
|
|
420
|
-
const PairWithAgentCallout: React.FC<{
|
|
421
|
-
onPairWithAgent: () => void;
|
|
422
|
-
}> = ({ onPairWithAgent }) => {
|
|
423
|
-
if (isWasm()) {
|
|
424
|
-
return null;
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
return (
|
|
428
|
-
<Button
|
|
429
|
-
variant="text"
|
|
430
|
-
className="gap-1.5 text-sm text-link hover:underline"
|
|
431
|
-
onClick={onPairWithAgent}
|
|
432
|
-
>
|
|
433
|
-
<SparklesIcon className="h-3.5 w-3.5 shrink-0" />
|
|
434
|
-
<span>Pair your own agent with this notebook</span>
|
|
435
|
-
<ArrowRightIcon className="h-3 w-3 shrink-0" />
|
|
436
|
-
</Button>
|
|
437
|
-
);
|
|
438
|
-
};
|
|
439
|
-
|
|
440
431
|
const ChatPanel = () => {
|
|
441
432
|
const aiConfigured = useAtomValue(aiModelConfiguredAtom);
|
|
442
433
|
const { handleClick } = useOpenSettingsToTab();
|
|
@@ -494,7 +485,6 @@ const ChatPanelBody = () => {
|
|
|
494
485
|
});
|
|
495
486
|
const runtimeManager = useRuntimeManager();
|
|
496
487
|
const { invokeAiTool } = useRequestClient();
|
|
497
|
-
const { openModal, closeModal } = useImperativeModal();
|
|
498
488
|
|
|
499
489
|
const activeChatId = activeChat?.id;
|
|
500
490
|
const { chatControllerId, renewDraftChatId } =
|
|
@@ -638,7 +628,7 @@ const ChatPanelBody = () => {
|
|
|
638
628
|
},
|
|
639
629
|
);
|
|
640
630
|
|
|
641
|
-
const isLoading = status
|
|
631
|
+
const isLoading = useChatGeneration(status);
|
|
642
632
|
// useEvent reads the latest loading state, even when called after an await
|
|
643
633
|
// (e.g. resolving @-context) that outlives the original render's closure.
|
|
644
634
|
const submitOrQueue = useEvent((parts: ChatMessagePart[]) => {
|
|
@@ -784,10 +774,6 @@ const ChatPanelBody = () => {
|
|
|
784
774
|
});
|
|
785
775
|
});
|
|
786
776
|
|
|
787
|
-
const handlePairWithAgent = useEvent(() => {
|
|
788
|
-
openModal(<PairWithAgentModal onClose={closeModal} />);
|
|
789
|
-
});
|
|
790
|
-
|
|
791
777
|
const handleMessageEdit = useEvent(
|
|
792
778
|
async (index: number, newValue: string) => {
|
|
793
779
|
const editedMessage = messages[index];
|
|
@@ -878,14 +864,20 @@ const ChatPanelBody = () => {
|
|
|
878
864
|
return;
|
|
879
865
|
}
|
|
880
866
|
setPendingPrompt(null);
|
|
881
|
-
const { prompt, submit } = pendingPrompt;
|
|
867
|
+
const { prompt, submit, append } = pendingPrompt;
|
|
868
|
+
const applyPrompt = (draft: string) =>
|
|
869
|
+
append
|
|
870
|
+
? draft.includes(prompt.trim())
|
|
871
|
+
? draft
|
|
872
|
+
: `${draft}${draft ? " " : ""}${prompt}`
|
|
873
|
+
: prompt;
|
|
882
874
|
if (submit) {
|
|
883
875
|
void submitPendingPrompt(prompt);
|
|
884
876
|
} else if (isNewThread) {
|
|
885
|
-
setNewThreadInput(
|
|
877
|
+
setNewThreadInput(applyPrompt);
|
|
886
878
|
focusInputAndMoveToEnd(newThreadInputRef);
|
|
887
879
|
} else {
|
|
888
|
-
setInput(
|
|
880
|
+
setInput(applyPrompt);
|
|
889
881
|
focusInputAndMoveToEnd(newMessageInputRef);
|
|
890
882
|
}
|
|
891
883
|
}, [pendingPrompt, setPendingPrompt, isNewThread, submitPendingPrompt]);
|
|
@@ -893,10 +885,8 @@ const ChatPanelBody = () => {
|
|
|
893
885
|
const chatInput = isNewThread ? (
|
|
894
886
|
<ChatInput
|
|
895
887
|
key="new-thread-input"
|
|
896
|
-
placeholder={`Ask anything, ${CONTEXT_TRIGGER} to include context about tables or dataframes`}
|
|
897
888
|
input={newThreadInput}
|
|
898
889
|
inputRef={newThreadInputRef}
|
|
899
|
-
inputClassName="px-1 py-0"
|
|
900
890
|
setInput={setNewThreadInput}
|
|
901
891
|
onSubmit={handleNewThreadSubmit}
|
|
902
892
|
isLoading={isLoading}
|
|
@@ -920,12 +910,7 @@ const ChatPanelBody = () => {
|
|
|
920
910
|
);
|
|
921
911
|
|
|
922
912
|
const filesPills = files && files.length > 0 && (
|
|
923
|
-
<div
|
|
924
|
-
className={cn(
|
|
925
|
-
"flex flex-row gap-1 flex-wrap p-1",
|
|
926
|
-
isNewThread && "py-2 px-1",
|
|
927
|
-
)}
|
|
928
|
-
>
|
|
913
|
+
<div className="flex flex-row gap-1 flex-wrap px-3 pt-2">
|
|
929
914
|
{files?.map((file) => (
|
|
930
915
|
<FileAttachmentPill
|
|
931
916
|
file={file}
|
|
@@ -936,8 +921,15 @@ const ChatPanelBody = () => {
|
|
|
936
921
|
</div>
|
|
937
922
|
);
|
|
938
923
|
|
|
924
|
+
const composer = (
|
|
925
|
+
<div className="@container rounded-[10px] border border-border bg-background">
|
|
926
|
+
{filesPills}
|
|
927
|
+
{chatInput}
|
|
928
|
+
</div>
|
|
929
|
+
);
|
|
930
|
+
|
|
939
931
|
return (
|
|
940
|
-
<div className="flex flex-col h-
|
|
932
|
+
<div className="mo-ai-panel flex flex-col flex-1 min-h-0 font-prose text-sm leading-6">
|
|
941
933
|
<TooltipProvider>
|
|
942
934
|
<ChatHeader
|
|
943
935
|
onNewChat={handleNewChat}
|
|
@@ -950,20 +942,10 @@ const ChatPanelBody = () => {
|
|
|
950
942
|
|
|
951
943
|
<div className="flex-1 flex flex-col overflow-hidden relative min-h-0">
|
|
952
944
|
<div
|
|
953
|
-
className="flex-1 px-3 bg-
|
|
945
|
+
className="flex-1 px-3 bg-background gap-4 py-3 flex flex-col overflow-y-auto"
|
|
954
946
|
ref={scrollContainerRef}
|
|
955
947
|
onScroll={handleScroll}
|
|
956
948
|
>
|
|
957
|
-
{isNewThread && (
|
|
958
|
-
<div className="flex flex-col gap-2">
|
|
959
|
-
<div className="rounded-md border bg-background">
|
|
960
|
-
{filesPills}
|
|
961
|
-
{chatInput}
|
|
962
|
-
</div>
|
|
963
|
-
<PairWithAgentCallout onPairWithAgent={handlePairWithAgent} />
|
|
964
|
-
</div>
|
|
965
|
-
)}
|
|
966
|
-
|
|
967
949
|
{messages.map((message, idx) => (
|
|
968
950
|
<ChatMessageDisplay
|
|
969
951
|
key={message.id}
|
|
@@ -981,12 +963,6 @@ const ChatPanelBody = () => {
|
|
|
981
963
|
<QueuedMessageDisplay key={message.id} message={message} />
|
|
982
964
|
))}
|
|
983
965
|
|
|
984
|
-
{isLoading && (
|
|
985
|
-
<div className="flex justify-center py-4">
|
|
986
|
-
<Loader2 className="h-4 w-4 animate-spin" />
|
|
987
|
-
</div>
|
|
988
|
-
)}
|
|
989
|
-
|
|
990
966
|
{error && (
|
|
991
967
|
<div className="flex items-center justify-center space-x-2 mb-4">
|
|
992
968
|
<ErrorBanner error={error || new Error("Unknown error")} />
|
|
@@ -1015,20 +991,30 @@ const ChatPanelBody = () => {
|
|
|
1015
991
|
</div>
|
|
1016
992
|
|
|
1017
993
|
{isLoading && (
|
|
1018
|
-
<div className="
|
|
1019
|
-
<
|
|
1020
|
-
|
|
994
|
+
<div className="flex shrink-0 items-center gap-2 px-3 pt-2 text-xs text-muted-foreground">
|
|
995
|
+
<div className="flex items-center gap-1.5">
|
|
996
|
+
<div aria-hidden={true}>
|
|
997
|
+
<LoadingEllipsis
|
|
998
|
+
size={3}
|
|
999
|
+
gap="gap-0.5"
|
|
1000
|
+
className="motion-reduce:[&_svg]:animate-none"
|
|
1001
|
+
/>
|
|
1002
|
+
</div>
|
|
1003
|
+
<output>Working</output>
|
|
1004
|
+
</div>
|
|
1005
|
+
<span aria-hidden={true} className="h-3 w-px bg-border" />
|
|
1006
|
+
<Button
|
|
1007
|
+
variant="text"
|
|
1008
|
+
size="xs"
|
|
1009
|
+
className="chat-control"
|
|
1010
|
+
onClick={stop}
|
|
1011
|
+
>
|
|
1012
|
+
Stop generation
|
|
1021
1013
|
</Button>
|
|
1022
1014
|
</div>
|
|
1023
1015
|
)}
|
|
1024
1016
|
|
|
1025
|
-
|
|
1026
|
-
{!isNewThread && (
|
|
1027
|
-
<>
|
|
1028
|
-
{filesPills}
|
|
1029
|
-
{chatInput}
|
|
1030
|
-
</>
|
|
1031
|
-
)}
|
|
1017
|
+
<div className="shrink-0 p-3">{composer}</div>
|
|
1032
1018
|
</div>
|
|
1033
1019
|
);
|
|
1034
1020
|
};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
|
+
|
|
3
|
+
.mo-ai-panel {
|
|
4
|
+
.chat-control {
|
|
5
|
+
color: var(--muted-foreground);
|
|
6
|
+
background: transparent;
|
|
7
|
+
border-color: transparent;
|
|
8
|
+
box-shadow: none;
|
|
9
|
+
opacity: 1;
|
|
10
|
+
|
|
11
|
+
&.chat-selector {
|
|
12
|
+
color: var(--foreground);
|
|
13
|
+
background: var(--slate-2);
|
|
14
|
+
border-color: var(--border);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
&:not(:disabled):is(:hover, [data-state="open"], [data-active="true"]) {
|
|
18
|
+
color: var(--foreground);
|
|
19
|
+
background: var(--slate-3);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
&[data-active="true"] {
|
|
23
|
+
border-color: var(--border);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
&:focus-visible {
|
|
27
|
+
outline: 1px solid var(--muted-foreground);
|
|
28
|
+
outline-offset: 2px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
&:disabled {
|
|
32
|
+
opacity: 0.5;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.lucide-chevron-down {
|
|
37
|
+
width: 0.75rem;
|
|
38
|
+
height: 0.75rem;
|
|
39
|
+
stroke-width: 1.5;
|
|
40
|
+
opacity: 0.5;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.mo-markdown-renderer {
|
|
44
|
+
font-family: inherit;
|
|
45
|
+
font-size: 0.875rem;
|
|
46
|
+
line-height: 1.5;
|
|
47
|
+
|
|
48
|
+
:is(h1, h2, h3, h4, h5, h6) {
|
|
49
|
+
font-family: inherit;
|
|
50
|
+
font-size: 0.875rem;
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
line-height: 1.5;
|
|
53
|
+
margin-block: 1rem 0.5rem;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
:is(h1, h2) {
|
|
57
|
+
font-size: 1rem;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
> :first-child {
|
|
61
|
+
margin-top: 0;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
:is(pre, code, .cm-editor) {
|
|
65
|
+
font-family: var(--monospace-font);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.cm-editor {
|
|
69
|
+
font-size: 0.8125rem;
|
|
70
|
+
line-height: 1.5;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.mo-ai-prompt {
|
|
75
|
+
font-family: var(--text-font), sans-serif;
|
|
76
|
+
.cm-clickable-placeholder:hover {
|
|
77
|
+
color: var(--foreground);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.cm-placeholder {
|
|
81
|
+
font-family: var(--text-font), sans-serif;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.cm-editor,
|
|
85
|
+
.cm-scroller {
|
|
86
|
+
font-family: inherit;
|
|
87
|
+
font-size: inherit;
|
|
88
|
+
line-height: inherit;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
@container (max-width: 380px) {
|
|
94
|
+
.chat-input-footer {
|
|
95
|
+
flex-wrap: wrap;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.chat-input-selectors {
|
|
99
|
+
flex-basis: 100%;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
@container (max-width: 360px) {
|
|
104
|
+
.sidebar-panel-actions:not(:empty) {
|
|
105
|
+
order: 1;
|
|
106
|
+
flex-basis: 100%;
|
|
107
|
+
}
|
|
108
|
+
}
|