@townco/ui 0.1.7 → 0.1.9
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/core/hooks/index.d.ts +1 -0
- package/dist/core/hooks/index.d.ts.map +1 -0
- package/dist/core/hooks/index.js +1 -0
- package/dist/core/hooks/index.js.map +1 -0
- package/dist/core/hooks/use-chat-input.d.ts +17 -17
- package/dist/core/hooks/use-chat-input.d.ts.map +1 -0
- package/dist/core/hooks/use-chat-input.js +64 -55
- package/dist/core/hooks/use-chat-input.js.map +1 -0
- package/dist/core/hooks/use-chat-messages.d.ts +11 -11
- package/dist/core/hooks/use-chat-messages.d.ts.map +1 -0
- package/dist/core/hooks/use-chat-messages.js +121 -114
- package/dist/core/hooks/use-chat-messages.js.map +1 -0
- package/dist/core/hooks/use-chat-session.d.ts +5 -5
- package/dist/core/hooks/use-chat-session.d.ts.map +1 -0
- package/dist/core/hooks/use-chat-session.js +78 -80
- package/dist/core/hooks/use-chat-session.js.map +1 -0
- package/dist/core/hooks/use-media-query.d.ts +39 -0
- package/dist/core/hooks/use-media-query.js +84 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/schemas/chat.d.ts +83 -56
- package/dist/core/schemas/chat.d.ts.map +1 -0
- package/dist/core/schemas/chat.js +27 -25
- package/dist/core/schemas/chat.js.map +1 -0
- package/dist/core/schemas/index.d.ts.map +1 -0
- package/dist/core/schemas/index.js.map +1 -0
- package/dist/core/store/chat-store.d.ts +28 -22
- package/dist/core/store/chat-store.d.ts.map +1 -0
- package/dist/core/store/chat-store.js +59 -50
- package/dist/core/store/chat-store.js.map +1 -0
- package/dist/gui/components/Button.d.ts +23 -7
- package/dist/gui/components/Button.d.ts.map +1 -0
- package/dist/gui/components/Button.js +40 -27
- package/dist/gui/components/Button.js.map +1 -0
- package/dist/gui/components/Card.d.ts +26 -7
- package/dist/gui/components/Card.d.ts.map +1 -0
- package/dist/gui/components/Card.js +54 -8
- package/dist/gui/components/Card.js.map +1 -0
- package/dist/gui/components/ChatHeader.d.ts +38 -0
- package/dist/gui/components/ChatHeader.js +86 -0
- package/dist/gui/components/ChatInput.d.ts +19 -1
- package/dist/gui/components/ChatInput.d.ts.map +1 -0
- package/dist/gui/components/ChatInput.js +94 -11
- package/dist/gui/components/ChatInput.js.map +1 -0
- package/dist/gui/components/ChatInputCommandMenu.d.ts +20 -0
- package/dist/gui/components/ChatInputCommandMenu.js +62 -0
- package/dist/gui/components/ChatInterface.d.ts +12 -0
- package/dist/gui/components/ChatInterface.d.ts.map +1 -0
- package/dist/gui/components/ChatInterface.js +204 -0
- package/dist/gui/components/ChatInterface.js.map +1 -0
- package/dist/gui/components/ChatLayout.d.ts +52 -0
- package/dist/gui/components/ChatLayout.js +105 -0
- package/dist/gui/components/ChatPanelTabContent.d.ts +18 -0
- package/dist/gui/components/ChatPanelTabContent.js +15 -0
- package/dist/gui/components/ChatPreview.d.ts +12 -0
- package/dist/gui/components/ChatPreview.d.ts.map +1 -0
- package/dist/gui/components/ChatPreview.js +214 -0
- package/dist/gui/components/ChatPreview.js.map +1 -0
- package/dist/gui/components/ChatSecondaryPanel.d.ts +14 -11
- package/dist/gui/components/ChatSecondaryPanel.d.ts.map +1 -0
- package/dist/gui/components/ChatSecondaryPanel.js +115 -38
- package/dist/gui/components/ChatSecondaryPanel.js.map +1 -0
- package/dist/gui/components/ChatSidebar.d.ts +14 -0
- package/dist/gui/components/ChatSidebar.js +23 -0
- package/dist/gui/components/ChatStatus.d.ts +4 -2
- package/dist/gui/components/ChatStatus.d.ts.map +1 -0
- package/dist/gui/components/ChatStatus.js +45 -34
- package/dist/gui/components/ChatStatus.js.map +1 -0
- package/dist/gui/components/ChatView.d.ts +8 -0
- package/dist/gui/components/ChatView.d.ts.map +1 -0
- package/dist/gui/components/ChatView.js +42 -0
- package/dist/gui/components/ChatView.js.map +1 -0
- package/dist/gui/components/ConfigPanel.d.ts +20 -0
- package/dist/gui/components/ConfigPanel.d.ts.map +1 -0
- package/dist/gui/components/ConfigPanel.js +225 -0
- package/dist/gui/components/ConfigPanel.js.map +1 -0
- package/dist/gui/components/Conversation.d.ts +17 -14
- package/dist/gui/components/Conversation.d.ts.map +1 -0
- package/dist/gui/components/Conversation.js +143 -83
- package/dist/gui/components/Conversation.js.map +1 -0
- package/dist/gui/components/Dialog.d.ts +57 -11
- package/dist/gui/components/Dialog.d.ts.map +1 -0
- package/dist/gui/components/Dialog.js +84 -8
- package/dist/gui/components/Dialog.js.map +1 -0
- package/dist/gui/components/DropdownMenu.d.ts +27 -0
- package/dist/gui/components/DropdownMenu.js +68 -0
- package/dist/gui/components/HeightTransition.d.ts +12 -7
- package/dist/gui/components/HeightTransition.d.ts.map +1 -0
- package/dist/gui/components/HeightTransition.js +88 -77
- package/dist/gui/components/HeightTransition.js.map +1 -0
- package/dist/gui/components/Input.d.ts +13 -6
- package/dist/gui/components/Input.d.ts.map +1 -0
- package/dist/gui/components/Input.js +27 -16
- package/dist/gui/components/Input.js.map +1 -0
- package/dist/gui/components/InputBox.d.ts +21 -0
- package/dist/gui/components/InputBox.d.ts.map +1 -0
- package/dist/gui/components/InputBox.js +90 -0
- package/dist/gui/components/InputBox.js.map +1 -0
- package/dist/gui/components/Label.d.ts +7 -1
- package/dist/gui/components/Label.d.ts.map +1 -0
- package/dist/gui/components/Label.js +12 -2
- package/dist/gui/components/Label.js.map +1 -0
- package/dist/gui/components/MarkdownRenderer.d.ts +6 -4
- package/dist/gui/components/MarkdownRenderer.d.ts.map +1 -0
- package/dist/gui/components/MarkdownRenderer.js +178 -81
- package/dist/gui/components/MarkdownRenderer.js.map +1 -0
- package/dist/gui/components/Message.d.ts +4 -0
- package/dist/gui/components/Message.d.ts.map +1 -0
- package/dist/gui/components/Message.js +77 -3
- package/dist/gui/components/Message.js.map +1 -0
- package/dist/gui/components/MessageContent.d.ts +29 -22
- package/dist/gui/components/MessageContent.d.ts.map +1 -0
- package/dist/gui/components/MessageContent.js +1 -1
- package/dist/gui/components/MessageContent.js.map +1 -0
- package/dist/gui/components/MessageList.d.ts.map +1 -0
- package/dist/gui/components/MessageList.js.map +1 -0
- package/dist/gui/components/PlaygroundLayout.d.ts +14 -0
- package/dist/gui/components/PlaygroundLayout.d.ts.map +1 -0
- package/dist/gui/components/PlaygroundLayout.js +49 -0
- package/dist/gui/components/PlaygroundLayout.js.map +1 -0
- package/dist/gui/components/Reasoning.d.ts +30 -24
- package/dist/gui/components/Reasoning.d.ts.map +1 -0
- package/dist/gui/components/Reasoning.js +187 -60
- package/dist/gui/components/Reasoning.js.map +1 -0
- package/dist/gui/components/Response.d.ts +11 -9
- package/dist/gui/components/Response.d.ts.map +1 -0
- package/dist/gui/components/Response.js +229 -90
- package/dist/gui/components/Response.js.map +1 -0
- package/dist/gui/components/Select.d.ts +69 -10
- package/dist/gui/components/Select.d.ts.map +1 -0
- package/dist/gui/components/Select.js +118 -12
- package/dist/gui/components/Select.js.map +1 -0
- package/dist/gui/components/Sonner.d.ts +5 -0
- package/dist/gui/components/Sonner.js +23 -0
- package/dist/gui/components/StatusBar.d.ts +12 -0
- package/dist/gui/components/StatusBar.d.ts.map +1 -0
- package/dist/gui/components/StatusBar.js +58 -0
- package/dist/gui/components/StatusBar.js.map +1 -0
- package/dist/gui/components/Tabs.d.ts +24 -4
- package/dist/gui/components/Tabs.d.ts.map +1 -0
- package/dist/gui/components/Tabs.js +32 -4
- package/dist/gui/components/Tabs.js.map +1 -0
- package/dist/gui/components/Task.d.ts +28 -24
- package/dist/gui/components/Task.d.ts.map +1 -0
- package/dist/gui/components/Task.js +164 -31
- package/dist/gui/components/Task.js.map +1 -0
- package/dist/gui/components/Textarea.d.ts +15 -7
- package/dist/gui/components/Textarea.d.ts.map +1 -0
- package/dist/gui/components/Textarea.js +63 -46
- package/dist/gui/components/Textarea.js.map +1 -0
- package/dist/gui/components/ThinkingBlock.d.ts +20 -10
- package/dist/gui/components/ThinkingBlock.d.ts.map +1 -0
- package/dist/gui/components/ThinkingBlock.js +134 -35
- package/dist/gui/components/ThinkingBlock.js.map +1 -0
- package/dist/gui/components/TodoList.d.ts +12 -10
- package/dist/gui/components/TodoList.d.ts.map +1 -0
- package/dist/gui/components/TodoList.js +22 -7
- package/dist/gui/components/TodoList.js.map +1 -0
- package/dist/gui/components/TodoListItem.d.ts +9 -6
- package/dist/gui/components/TodoListItem.d.ts.map +1 -0
- package/dist/gui/components/TodoListItem.js +18 -4
- package/dist/gui/components/TodoListItem.js.map +1 -0
- package/dist/gui/components/index.d.ts +9 -1
- package/dist/gui/components/index.d.ts.map +1 -0
- package/dist/gui/components/index.js +11 -1
- package/dist/gui/components/index.js.map +1 -0
- package/dist/gui/index.d.ts.map +1 -0
- package/dist/gui/index.js.map +1 -0
- package/dist/gui/lib/utils.d.ts.map +1 -0
- package/dist/gui/lib/utils.js +1 -1
- package/dist/gui/lib/utils.js.map +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.js +0 -1
- package/dist/sdk/client/acp-client.d.ts +88 -76
- package/dist/sdk/client/acp-client.d.ts.map +1 -0
- package/dist/sdk/client/acp-client.js +215 -217
- package/dist/sdk/client/acp-client.js.map +1 -0
- package/dist/sdk/client/index.d.ts.map +1 -0
- package/dist/sdk/client/index.js.map +1 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/schemas/agent.d.ts +111 -64
- package/dist/sdk/schemas/agent.d.ts.map +1 -0
- package/dist/sdk/schemas/agent.js +24 -24
- package/dist/sdk/schemas/agent.js.map +1 -0
- package/dist/sdk/schemas/index.d.ts.map +1 -0
- package/dist/sdk/schemas/index.js.map +1 -0
- package/dist/sdk/schemas/message.d.ts +245 -147
- package/dist/sdk/schemas/message.d.ts.map +1 -0
- package/dist/sdk/schemas/message.js +40 -40
- package/dist/sdk/schemas/message.js.map +1 -0
- package/dist/sdk/schemas/session.d.ts +219 -135
- package/dist/sdk/schemas/session.d.ts.map +1 -0
- package/dist/sdk/schemas/session.js +27 -27
- package/dist/sdk/schemas/session.js.map +1 -0
- package/dist/sdk/transports/http.d.ts +55 -55
- package/dist/sdk/transports/http.d.ts.map +1 -0
- package/dist/sdk/transports/http.js +472 -469
- package/dist/sdk/transports/http.js.map +1 -0
- package/dist/sdk/transports/index.d.ts.map +1 -0
- package/dist/sdk/transports/index.js.map +1 -0
- package/dist/sdk/transports/stdio.d.ts +20 -20
- package/dist/sdk/transports/stdio.d.ts.map +1 -0
- package/dist/sdk/transports/stdio.js.map +1 -0
- package/dist/sdk/transports/types.d.ts +42 -42
- package/dist/sdk/transports/types.d.ts.map +1 -0
- package/dist/sdk/transports/types.js.map +1 -0
- package/dist/sdk/transports/websocket.d.ts +12 -12
- package/dist/sdk/transports/websocket.d.ts.map +1 -0
- package/dist/sdk/transports/websocket.js +52 -46
- package/dist/sdk/transports/websocket.js.map +1 -0
- package/dist/tui/components/ChatView.d.ts +4 -2
- package/dist/tui/components/ChatView.d.ts.map +1 -0
- package/dist/tui/components/ChatView.js +51 -18
- package/dist/tui/components/ChatView.js.map +1 -0
- package/dist/tui/components/GameOfLife.d.ts.map +1 -0
- package/dist/tui/components/GameOfLife.js +64 -35
- package/dist/tui/components/GameOfLife.js.map +1 -0
- package/dist/tui/components/InputBox.d.ts +18 -11
- package/dist/tui/components/InputBox.d.ts.map +1 -0
- package/dist/tui/components/InputBox.js +70 -10
- package/dist/tui/components/InputBox.js.map +1 -0
- package/dist/tui/components/MessageList.d.ts +4 -2
- package/dist/tui/components/MessageList.d.ts.map +1 -0
- package/dist/tui/components/MessageList.js +37 -10
- package/dist/tui/components/MessageList.js.map +1 -0
- package/dist/tui/components/ReadlineInput.d.ts +12 -6
- package/dist/tui/components/ReadlineInput.d.ts.map +1 -0
- package/dist/tui/components/ReadlineInput.js +252 -237
- package/dist/tui/components/ReadlineInput.js.map +1 -0
- package/dist/tui/components/SingleSelect.d.ts +15 -9
- package/dist/tui/components/SingleSelect.js +84 -43
- package/dist/tui/components/StatusBar.d.ts +11 -6
- package/dist/tui/components/StatusBar.d.ts.map +1 -0
- package/dist/tui/components/StatusBar.js +102 -67
- package/dist/tui/components/StatusBar.js.map +1 -0
- package/dist/tui/components/index.d.ts.map +1 -0
- package/dist/tui/components/index.js.map +1 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js.map +1 -0
- package/package.json +6 -4
- package/src/styles/global.css +2 -0
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { Slot } from "@radix-ui/react-slot";
|
|
3
|
+
import { Mic, Paperclip, SquareSlash } from "lucide-react";
|
|
3
4
|
import * as React from "react";
|
|
4
5
|
import { useChatInput as useCoreChatInput } from "../../core/hooks/use-chat-input.js";
|
|
5
6
|
import { useChatStore } from "../../core/store/chat-store.js";
|
|
6
7
|
import { cn } from "../lib/utils.js";
|
|
7
8
|
import { Button } from "./Button.js";
|
|
9
|
+
import { ChatInputCommandMenu as ChatInputCommandMenuComponent, } from "./ChatInputCommandMenu.js";
|
|
8
10
|
const ChatInputContext = React.createContext(undefined);
|
|
9
11
|
const useChatInputContext = () => {
|
|
10
12
|
const context = React.useContext(ChatInputContext);
|
|
@@ -27,6 +29,15 @@ const ChatInputRoot = React.forwardRef(({ client, value: valueProp, onChange: on
|
|
|
27
29
|
const isSubmitting = hookData
|
|
28
30
|
? hookData.isSubmitting || storeIsStreaming
|
|
29
31
|
: isSubmittingProp || false;
|
|
32
|
+
// Command menu state
|
|
33
|
+
const [showCommandMenu, setShowCommandMenu] = React.useState(false);
|
|
34
|
+
const [commandMenuQuery, setCommandMenuQuery] = React.useState("");
|
|
35
|
+
const [selectedMenuIndex, setSelectedMenuIndex] = React.useState(0);
|
|
36
|
+
const [menuItemCount, setMenuItemCount] = React.useState(0);
|
|
37
|
+
const [triggerCounter, setTriggerCounter] = React.useState(0);
|
|
38
|
+
const triggerMenuSelect = React.useCallback(() => {
|
|
39
|
+
setTriggerCounter((prev) => prev + 1);
|
|
40
|
+
}, []);
|
|
30
41
|
const handleSubmit = async (e) => {
|
|
31
42
|
e.preventDefault();
|
|
32
43
|
if (value.trim() && !isSubmitting && !disabled) {
|
|
@@ -58,11 +69,21 @@ const ChatInputRoot = React.forwardRef(({ client, value: valueProp, onChange: on
|
|
|
58
69
|
disabled,
|
|
59
70
|
isSubmitting,
|
|
60
71
|
submitOnEnter,
|
|
61
|
-
|
|
72
|
+
showCommandMenu,
|
|
73
|
+
setShowCommandMenu,
|
|
74
|
+
commandMenuQuery,
|
|
75
|
+
setCommandMenuQuery,
|
|
76
|
+
selectedMenuIndex,
|
|
77
|
+
setSelectedMenuIndex,
|
|
78
|
+
menuItemCount,
|
|
79
|
+
setMenuItemCount,
|
|
80
|
+
triggerMenuSelect,
|
|
81
|
+
triggerCounter,
|
|
82
|
+
}, children: _jsx("form", { ref: ref, onSubmit: handleSubmit, className: cn("relative w-full divide-y rounded-xl border bg-background shadow-md", className), ...props, children: children }) }));
|
|
62
83
|
});
|
|
63
84
|
ChatInputRoot.displayName = "ChatInput.Root";
|
|
64
85
|
const ChatInputField = React.forwardRef(({ asChild = false, className, onKeyDown, children, ...props }, ref) => {
|
|
65
|
-
const { value, onChange, onSubmit, disabled, isSubmitting, submitOnEnter } = useChatInputContext();
|
|
86
|
+
const { value, onChange, onSubmit, disabled, isSubmitting, submitOnEnter, showCommandMenu, setShowCommandMenu, setCommandMenuQuery, setSelectedMenuIndex, menuItemCount, triggerMenuSelect, } = useChatInputContext();
|
|
66
87
|
const textareaRef = React.useRef(null);
|
|
67
88
|
const handleRef = React.useCallback((node) => {
|
|
68
89
|
textareaRef.current = node;
|
|
@@ -74,6 +95,30 @@ const ChatInputField = React.forwardRef(({ asChild = false, className, onKeyDown
|
|
|
74
95
|
}
|
|
75
96
|
}, [ref]);
|
|
76
97
|
const handleKeyDown = (e) => {
|
|
98
|
+
// Handle arrow keys and Enter when command menu is open
|
|
99
|
+
if (showCommandMenu && menuItemCount > 0) {
|
|
100
|
+
if (e.key === "ArrowDown") {
|
|
101
|
+
e.preventDefault();
|
|
102
|
+
setSelectedMenuIndex((prev) => (prev + 1) % menuItemCount);
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
else if (e.key === "ArrowUp") {
|
|
106
|
+
e.preventDefault();
|
|
107
|
+
setSelectedMenuIndex((prev) => (prev - 1 + menuItemCount) % menuItemCount);
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
else if (e.key === "Enter" && !e.shiftKey) {
|
|
111
|
+
e.preventDefault();
|
|
112
|
+
triggerMenuSelect();
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
else if (e.key === "Escape") {
|
|
116
|
+
e.preventDefault();
|
|
117
|
+
setShowCommandMenu(false);
|
|
118
|
+
setCommandMenuQuery("");
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
77
122
|
// Handle Enter without Shift - only submit if not already submitting
|
|
78
123
|
if (submitOnEnter && e.key === "Enter" && !e.shiftKey) {
|
|
79
124
|
// Only prevent default and submit if conditions are met
|
|
@@ -89,7 +134,19 @@ const ChatInputField = React.forwardRef(({ asChild = false, className, onKeyDown
|
|
|
89
134
|
onKeyDown?.(e);
|
|
90
135
|
};
|
|
91
136
|
const handleChange = (e) => {
|
|
92
|
-
|
|
137
|
+
const newValue = e.target.value;
|
|
138
|
+
onChange(newValue);
|
|
139
|
+
// Check if user typed "/" at the start to trigger command menu
|
|
140
|
+
if (newValue.startsWith("/") && !newValue.includes("\n")) {
|
|
141
|
+
setShowCommandMenu(true);
|
|
142
|
+
// Extract search query (everything after "/")
|
|
143
|
+
const query = newValue.slice(1);
|
|
144
|
+
setCommandMenuQuery(query);
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
setShowCommandMenu(false);
|
|
148
|
+
setCommandMenuQuery("");
|
|
149
|
+
}
|
|
93
150
|
// Auto-resize
|
|
94
151
|
const textarea = textareaRef.current;
|
|
95
152
|
if (!textarea)
|
|
@@ -116,22 +173,48 @@ const ChatInputField = React.forwardRef(({ asChild = false, className, onKeyDown
|
|
|
116
173
|
if (asChild && React.isValidElement(children)) {
|
|
117
174
|
return React.cloneElement(children, fieldProps);
|
|
118
175
|
}
|
|
119
|
-
return (_jsx("textarea", { ...fieldProps, className: cn("w-full resize-none rounded-none border-none p-
|
|
176
|
+
return (_jsx("textarea", { ...fieldProps, className: cn("w-full resize-none rounded-none border-none p-4 shadow-none", "outline-none ring-0 field-sizing-content max-h-[6lh]", "bg-transparent dark:bg-transparent focus-visible:ring-0", "text-sm placeholder:text-muted-foreground", "disabled:cursor-not-allowed disabled:opacity-50", className) }));
|
|
120
177
|
});
|
|
121
178
|
ChatInputField.displayName = "ChatInput.Field";
|
|
122
179
|
const ChatInputSubmit = React.forwardRef(({ asChild = false, className, disabled: disabledProp, children, ...props }, ref) => {
|
|
123
180
|
const { value, disabled, isSubmitting } = useChatInputContext();
|
|
124
181
|
const isDisabled = disabledProp || disabled || isSubmitting || !value.trim();
|
|
125
182
|
const Comp = asChild ? Slot : Button;
|
|
126
|
-
return (_jsx(Comp, { ref: ref, type: "submit", disabled: isDisabled, size: "icon", className: cn(!asChild &&
|
|
127
|
-
"gap-1.5 rounded-lg bg-transparent text-foreground hover:bg-transparent", className), ...props, children: children }));
|
|
183
|
+
return (_jsx(Comp, { ref: ref, type: "submit", disabled: isDisabled, variant: !asChild ? "default" : undefined, size: "icon", className: cn(!asChild && "gap-1.5 rounded-full", className), ...props, children: children }));
|
|
128
184
|
});
|
|
129
185
|
ChatInputSubmit.displayName = "ChatInput.Submit";
|
|
130
186
|
const ChatInputToolbar = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
131
|
-
return (_jsx("div", { ref: ref, className: cn("flex items-center justify-between p-
|
|
187
|
+
return (_jsx("div", { ref: ref, className: cn("flex items-center justify-between p-2", className), ...props, children: children }));
|
|
132
188
|
});
|
|
133
189
|
ChatInputToolbar.displayName = "ChatInput.Toolbar";
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
190
|
+
const ChatInputActions = React.forwardRef(({ asChild = false, className, children, onClick, ...props }, ref) => {
|
|
191
|
+
const { value, onChange, setShowCommandMenu, setCommandMenuQuery } = useChatInputContext();
|
|
192
|
+
const handleClick = (e) => {
|
|
193
|
+
// Trigger command menu by setting "/" in the input
|
|
194
|
+
if (!value.startsWith("/")) {
|
|
195
|
+
onChange("/");
|
|
196
|
+
setShowCommandMenu(true);
|
|
197
|
+
setCommandMenuQuery("");
|
|
198
|
+
}
|
|
199
|
+
onClick?.(e);
|
|
200
|
+
};
|
|
201
|
+
const Comp = asChild ? Slot : Button;
|
|
202
|
+
return (_jsx(Comp, { ref: ref, type: "button", variant: "ghost", size: "icon", className: cn("rounded-full", className), onClick: handleClick, ...props, children: children || _jsx(SquareSlash, { className: "size-4" }) }));
|
|
203
|
+
});
|
|
204
|
+
ChatInputActions.displayName = "ChatInput.Actions";
|
|
205
|
+
const ChatInputAttachment = React.forwardRef(({ asChild = false, className, children, ...props }, ref) => {
|
|
206
|
+
const Comp = asChild ? Slot : Button;
|
|
207
|
+
return (_jsx(Comp, { ref: ref, type: "button", variant: "ghost", size: "icon", className: cn("rounded-full", className), ...props, children: children || _jsx(Paperclip, { className: "size-4" }) }));
|
|
208
|
+
});
|
|
209
|
+
ChatInputAttachment.displayName = "ChatInput.Attachment";
|
|
210
|
+
const ChatInputVoiceInput = React.forwardRef(({ asChild = false, className, children, ...props }, ref) => {
|
|
211
|
+
const Comp = asChild ? Slot : Button;
|
|
212
|
+
return (_jsx(Comp, { ref: ref, type: "button", variant: "ghost", size: "icon", className: cn("rounded-full", className), ...props, children: children || _jsx(Mic, { className: "size-4" }) }));
|
|
213
|
+
});
|
|
214
|
+
ChatInputVoiceInput.displayName = "ChatInput.VoiceInput";
|
|
215
|
+
const ChatInputCommandMenu = React.forwardRef(({ commands = [], className, onChange: _, ...props }, ref) => {
|
|
216
|
+
const { showCommandMenu, commandMenuQuery, selectedMenuIndex, setSelectedMenuIndex, setMenuItemCount, triggerCounter, onChange, } = useChatInputContext();
|
|
217
|
+
return (_jsx(ChatInputCommandMenuComponent, { ref: ref, commands: commands, showCommandMenu: showCommandMenu, commandMenuQuery: commandMenuQuery, selectedMenuIndex: selectedMenuIndex, setSelectedMenuIndex: setSelectedMenuIndex, setMenuItemCount: setMenuItemCount, triggerCounter: triggerCounter, onChange: onChange, className: className, ...props }));
|
|
218
|
+
});
|
|
219
|
+
ChatInputCommandMenu.displayName = "ChatInput.CommandMenu";
|
|
220
|
+
export { ChatInputRoot as Root, ChatInputField as Field, ChatInputSubmit as Submit, ChatInputToolbar as Toolbar, ChatInputActions as Actions, ChatInputAttachment as Attachment, ChatInputVoiceInput as VoiceInput, ChatInputCommandMenu as CommandMenu, };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatInput.js","sourceRoot":"","sources":["../../../src/gui/components/ChatInput.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface CommandMenuItem {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
icon?: React.ReactNode;
|
|
7
|
+
category?: string;
|
|
8
|
+
onSelect: () => void;
|
|
9
|
+
}
|
|
10
|
+
export interface ChatInputCommandMenuProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "onChange"> {
|
|
11
|
+
commands?: CommandMenuItem[];
|
|
12
|
+
showCommandMenu: boolean;
|
|
13
|
+
commandMenuQuery: string;
|
|
14
|
+
selectedMenuIndex: number;
|
|
15
|
+
setSelectedMenuIndex: (index: number) => void;
|
|
16
|
+
setMenuItemCount: (count: number) => void;
|
|
17
|
+
triggerCounter: number;
|
|
18
|
+
onChange: (value: string) => void;
|
|
19
|
+
}
|
|
20
|
+
export declare const ChatInputCommandMenu: React.ForwardRefExoticComponent<ChatInputCommandMenuProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
|
+
import { cn } from "../lib/utils.js";
|
|
4
|
+
/* -------------------------------------------------------------------------------------------------
|
|
5
|
+
* ChatInputCommandMenu
|
|
6
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
7
|
+
export const ChatInputCommandMenu = React.forwardRef(({ commands = [], showCommandMenu, commandMenuQuery, selectedMenuIndex, setSelectedMenuIndex, setMenuItemCount, triggerCounter, onChange, className, ...props }, ref) => {
|
|
8
|
+
// Fuzzy search implementation
|
|
9
|
+
const fuzzyMatch = React.useCallback((text, query) => {
|
|
10
|
+
const lowerText = text.toLowerCase();
|
|
11
|
+
const lowerQuery = query.toLowerCase();
|
|
12
|
+
if (!query)
|
|
13
|
+
return 1; // Show all when no query
|
|
14
|
+
if (lowerText.includes(lowerQuery)) {
|
|
15
|
+
// Exact substring match gets high score
|
|
16
|
+
return 1 - lowerQuery.length / lowerText.length;
|
|
17
|
+
}
|
|
18
|
+
// Fuzzy matching - check if all query chars appear in order
|
|
19
|
+
let queryIndex = 0;
|
|
20
|
+
for (let i = 0; i < lowerText.length && queryIndex < lowerQuery.length; i++) {
|
|
21
|
+
if (lowerText[i] === lowerQuery[queryIndex]) {
|
|
22
|
+
queryIndex++;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (queryIndex === lowerQuery.length) {
|
|
26
|
+
// All chars found, score based on how spread out they are
|
|
27
|
+
return 0.5 - queryIndex / lowerText.length;
|
|
28
|
+
}
|
|
29
|
+
return 0; // No match
|
|
30
|
+
}, []);
|
|
31
|
+
// Filter and sort commands by relevance
|
|
32
|
+
const filteredCommands = React.useMemo(() => {
|
|
33
|
+
return commands
|
|
34
|
+
.map((cmd) => ({
|
|
35
|
+
...cmd,
|
|
36
|
+
score: Math.max(fuzzyMatch(cmd.label, commandMenuQuery), cmd.description ? fuzzyMatch(cmd.description, commandMenuQuery) : 0),
|
|
37
|
+
}))
|
|
38
|
+
.filter((cmd) => cmd.score > 0)
|
|
39
|
+
.sort((a, b) => b.score - a.score);
|
|
40
|
+
}, [commands, commandMenuQuery, fuzzyMatch]);
|
|
41
|
+
// Update menu item count
|
|
42
|
+
React.useEffect(() => {
|
|
43
|
+
setMenuItemCount(filteredCommands.length);
|
|
44
|
+
}, [filteredCommands.length, setMenuItemCount]);
|
|
45
|
+
// Reset selected index when filtered results change
|
|
46
|
+
React.useEffect(() => {
|
|
47
|
+
setSelectedMenuIndex(0);
|
|
48
|
+
}, [setSelectedMenuIndex]);
|
|
49
|
+
// Handle selection when triggered
|
|
50
|
+
React.useEffect(() => {
|
|
51
|
+
if (triggerCounter > 0 && filteredCommands[selectedMenuIndex]) {
|
|
52
|
+
filteredCommands[selectedMenuIndex].onSelect();
|
|
53
|
+
// Clear the input after selection
|
|
54
|
+
onChange("");
|
|
55
|
+
}
|
|
56
|
+
}, [triggerCounter, filteredCommands, selectedMenuIndex, onChange]);
|
|
57
|
+
if (!showCommandMenu || filteredCommands.length === 0) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return (_jsxs("div", { ref: ref, className: cn("absolute bottom-full left-0 z-50 mb-2 w-full max-w-md", "rounded-md border border-border bg-card p-2 shadow-lg", className), ...props, children: [_jsx("div", { className: "text-xs font-semibold text-muted-foreground px-2 py-1", children: "Commands" }), _jsx("div", { className: "max-h-64 overflow-y-auto", children: filteredCommands.map((command, index) => (_jsxs("button", { type: "button", onClick: () => command.onSelect(), className: cn("w-full rounded-sm px-2 py-2 text-left text-sm transition-colors", "flex items-start gap-2", "hover:bg-muted", index === selectedMenuIndex && "bg-muted"), children: [command.icon && (_jsx("span", { className: "shrink-0 mt-0.5", children: command.icon })), _jsxs("div", { className: "flex-1 min-w-0", children: [_jsx("div", { className: "font-medium", children: command.label }), command.description && (_jsx("div", { className: "text-xs text-muted-foreground truncate", children: command.description }))] })] }, command.id))) })] }));
|
|
61
|
+
});
|
|
62
|
+
ChatInputCommandMenu.displayName = "ChatInputCommandMenu";
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { type DisplayMessage } from "./MessageList.js";
|
|
2
|
+
interface ChatInterfaceProps {
|
|
3
|
+
initialMessages?: DisplayMessage[];
|
|
4
|
+
thinkingDisplayStyle?: "collapsible" | "inline";
|
|
5
|
+
status?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function ChatInterface({
|
|
8
|
+
initialMessages,
|
|
9
|
+
thinkingDisplayStyle,
|
|
10
|
+
status,
|
|
11
|
+
}: ChatInterfaceProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
//# sourceMappingURL=ChatInterface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatInterface.d.ts","sourceRoot":"","sources":["../../../src/gui/components/ChatInterface.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAe,KAAK,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAQpE,UAAU,kBAAkB;IAC1B,eAAe,CAAC,EAAE,cAAc,EAAE,CAAC;IACnC,oBAAoB,CAAC,EAAE,aAAa,GAAG,QAAQ,CAAC;IAChD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA2FD,wBAAgB,aAAa,CAAC,EAC5B,eAAiC,EACjC,oBAAoC,EACpC,MAAoB,GACrB,EAAE,kBAAkB,2CA+FpB"}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { ChevronDown } from "lucide-react";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
|
+
import { ChatInput } from "./ChatInput.js";
|
|
5
|
+
import { ChatSecondaryPanel } from "./ChatSecondaryPanel.js";
|
|
6
|
+
import { ChatStatus } from "./ChatStatus.js";
|
|
7
|
+
import { HeightTransition } from "./HeightTransition.js";
|
|
8
|
+
import { MessageList } from "./MessageList.js";
|
|
9
|
+
|
|
10
|
+
const SAMPLE_TODOS = [
|
|
11
|
+
{
|
|
12
|
+
id: "1",
|
|
13
|
+
text: "Identify the last 25 Winter Olympics host countries",
|
|
14
|
+
status: "completed",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
id: "2",
|
|
18
|
+
text: "For each host country, find the tallest mountain",
|
|
19
|
+
status: "in_progress",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
id: "3",
|
|
23
|
+
text: "Gather key details for each mountain (name, elevation, location)",
|
|
24
|
+
status: "pending",
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
id: "4",
|
|
28
|
+
text: "Verify information using reliable sources (geographical databases, official records)",
|
|
29
|
+
status: "pending",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: "5",
|
|
33
|
+
text: "Compile findings into a summary table or document",
|
|
34
|
+
status: "pending",
|
|
35
|
+
},
|
|
36
|
+
];
|
|
37
|
+
const SAMPLE_MESSAGES = [
|
|
38
|
+
{
|
|
39
|
+
id: "msg-1",
|
|
40
|
+
role: "user",
|
|
41
|
+
content: "Hello! Can you help me understand how to use markdown?",
|
|
42
|
+
timestamp: new Date().toISOString(),
|
|
43
|
+
isStreaming: false,
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
id: "msg-2",
|
|
47
|
+
role: "assistant",
|
|
48
|
+
content: `Sure! Markdown is a lightweight markup language. Here are some basics:
|
|
49
|
+
|
|
50
|
+
## Headings
|
|
51
|
+
Use \`#\` for headings. More \`#\` symbols make smaller headings.
|
|
52
|
+
|
|
53
|
+
## Lists
|
|
54
|
+
- Unordered lists use dashes
|
|
55
|
+
- Or asterisks
|
|
56
|
+
- Or plus signs
|
|
57
|
+
|
|
58
|
+
1. Ordered lists
|
|
59
|
+
2. Use numbers
|
|
60
|
+
3. Like this
|
|
61
|
+
|
|
62
|
+
## Code
|
|
63
|
+
Inline code uses \`backticks\` and code blocks use triple backticks:
|
|
64
|
+
|
|
65
|
+
\`\`\`javascript
|
|
66
|
+
function hello() {
|
|
67
|
+
console.log("Hello world!");
|
|
68
|
+
}
|
|
69
|
+
\`\`\`
|
|
70
|
+
|
|
71
|
+
## Links and emphasis
|
|
72
|
+
[This is a link](https://example.com)
|
|
73
|
+
|
|
74
|
+
You can make text **bold** or *italic*.
|
|
75
|
+
|
|
76
|
+
> Blockquotes use the > character
|
|
77
|
+
|
|
78
|
+
## Tables
|
|
79
|
+
| Header 1 | Header 2 |
|
|
80
|
+
|----------|----------|
|
|
81
|
+
| Cell 1 | Cell 2 |
|
|
82
|
+
| Cell 3 | Cell 4 |`,
|
|
83
|
+
timestamp: new Date().toISOString(),
|
|
84
|
+
isStreaming: false,
|
|
85
|
+
metadata: {
|
|
86
|
+
thinking: "Let me provide a comprehensive overview of markdown syntax...",
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
id: "msg-3",
|
|
91
|
+
role: "user",
|
|
92
|
+
content: "That's really helpful, thank you!",
|
|
93
|
+
timestamp: new Date().toISOString(),
|
|
94
|
+
isStreaming: false,
|
|
95
|
+
},
|
|
96
|
+
];
|
|
97
|
+
export function ChatInterface({
|
|
98
|
+
initialMessages = SAMPLE_MESSAGES,
|
|
99
|
+
thinkingDisplayStyle = "collapsible",
|
|
100
|
+
status = "Connected",
|
|
101
|
+
}) {
|
|
102
|
+
const [messages, setMessages] = useState(initialMessages);
|
|
103
|
+
const [currentStatus, setCurrentStatus] = useState(status);
|
|
104
|
+
const [config, setConfig] = useState(null);
|
|
105
|
+
const [isHeaderExpanded, setIsHeaderExpanded] = useState(false);
|
|
106
|
+
const [todos] = useState(SAMPLE_TODOS);
|
|
107
|
+
// Listen for config and status updates from parent window
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
const handleMessage = (event) => {
|
|
110
|
+
if (event.data.type === "CONFIG_UPDATE") {
|
|
111
|
+
const newConfig = event.data.config;
|
|
112
|
+
setConfig(newConfig);
|
|
113
|
+
applyConfigToDocument(newConfig);
|
|
114
|
+
} else if (event.data.type === "STATUS_UPDATE") {
|
|
115
|
+
setCurrentStatus(event.data.status);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
window.addEventListener("message", handleMessage);
|
|
119
|
+
// Request config from parent on mount
|
|
120
|
+
if (window.parent !== window) {
|
|
121
|
+
window.parent.postMessage({ type: "REQUEST_CONFIG" }, "*");
|
|
122
|
+
}
|
|
123
|
+
return () => {
|
|
124
|
+
window.removeEventListener("message", handleMessage);
|
|
125
|
+
};
|
|
126
|
+
}, []);
|
|
127
|
+
const applyConfigToDocument = (cfg) => {
|
|
128
|
+
const root = document.documentElement;
|
|
129
|
+
root.setAttribute("data-theme", cfg.colorScheme);
|
|
130
|
+
root.style.setProperty("--color-accent", cfg.accentColor);
|
|
131
|
+
root.style.setProperty("--font-family", cfg.typography);
|
|
132
|
+
root.style.setProperty("--font-size", `${cfg.fontSize}px`);
|
|
133
|
+
};
|
|
134
|
+
return _jsxs("div", {
|
|
135
|
+
className:
|
|
136
|
+
"flex flex-col h-screen bg-[var(--color-bg)] text-[var(--color-text)]",
|
|
137
|
+
children: [
|
|
138
|
+
_jsxs("div", {
|
|
139
|
+
className:
|
|
140
|
+
"relative border-b border-[var(--color-border)] bg-[var(--color-surface)] z-10",
|
|
141
|
+
children: [
|
|
142
|
+
_jsxs("div", {
|
|
143
|
+
className: "flex items-center justify-between px-6 py-4",
|
|
144
|
+
children: [
|
|
145
|
+
_jsx("h1", {
|
|
146
|
+
className: "text-xl font-semibold m-0",
|
|
147
|
+
children: "Chat Interface",
|
|
148
|
+
}),
|
|
149
|
+
_jsxs("div", {
|
|
150
|
+
className: "flex items-center gap-3",
|
|
151
|
+
children: [
|
|
152
|
+
_jsx(ChatStatus, { children: currentStatus }),
|
|
153
|
+
_jsx("button", {
|
|
154
|
+
onClick: () => setIsHeaderExpanded(!isHeaderExpanded),
|
|
155
|
+
className:
|
|
156
|
+
"p-1 rounded hover:bg-[var(--color-bg)] transition-colors",
|
|
157
|
+
"aria-label": isHeaderExpanded
|
|
158
|
+
? "Collapse header"
|
|
159
|
+
: "Expand header",
|
|
160
|
+
children: _jsx(ChevronDown, {
|
|
161
|
+
className: `w-5 h-5 text-[var(--color-text)] transition-transform duration-200 ${isHeaderExpanded ? "rotate-180" : ""}`,
|
|
162
|
+
}),
|
|
163
|
+
}),
|
|
164
|
+
],
|
|
165
|
+
}),
|
|
166
|
+
],
|
|
167
|
+
}),
|
|
168
|
+
_jsx("div", {
|
|
169
|
+
className: "absolute top-full left-0 right-0 z-20",
|
|
170
|
+
children: _jsx(HeightTransition, {
|
|
171
|
+
children:
|
|
172
|
+
isHeaderExpanded &&
|
|
173
|
+
_jsx("div", {
|
|
174
|
+
className:
|
|
175
|
+
"bg-[var(--color-surface)] border-b border-[var(--color-border)] px-6 py-4 shadow-lg",
|
|
176
|
+
children: _jsx(ChatSecondaryPanel, { todos: todos }),
|
|
177
|
+
}),
|
|
178
|
+
}),
|
|
179
|
+
}),
|
|
180
|
+
],
|
|
181
|
+
}),
|
|
182
|
+
_jsx("div", {
|
|
183
|
+
className: "flex-1 overflow-y-auto py-4",
|
|
184
|
+
children: _jsx(MessageList, {
|
|
185
|
+
messages: messages,
|
|
186
|
+
thinkingDisplayStyle:
|
|
187
|
+
config?.thinkingDisplayStyle || thinkingDisplayStyle,
|
|
188
|
+
}),
|
|
189
|
+
}),
|
|
190
|
+
_jsx("div", {
|
|
191
|
+
className:
|
|
192
|
+
"border-t border-[var(--color-border)] px-6 py-4 bg-[var(--color-surface)]",
|
|
193
|
+
children: _jsx(ChatInput, {
|
|
194
|
+
value: "",
|
|
195
|
+
onChange: () => {},
|
|
196
|
+
onSubmit: () => {},
|
|
197
|
+
disabled: true,
|
|
198
|
+
placeholder: "Type a message...",
|
|
199
|
+
}),
|
|
200
|
+
}),
|
|
201
|
+
],
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
//# sourceMappingURL=ChatInterface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatInterface.js","sourceRoot":"","sources":["../../../src/gui/components/ChatInterface.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
type PanelSize = "hidden" | "small" | "large";
|
|
3
|
+
type PanelTabType = "todo" | "files" | "database";
|
|
4
|
+
interface ChatLayoutContextValue {
|
|
5
|
+
sidebarOpen: boolean;
|
|
6
|
+
setSidebarOpen: (open: boolean) => void;
|
|
7
|
+
panelSize: PanelSize;
|
|
8
|
+
setPanelSize: (size: PanelSize) => void;
|
|
9
|
+
activeTab: PanelTabType;
|
|
10
|
+
setActiveTab: (tab: PanelTabType) => void;
|
|
11
|
+
}
|
|
12
|
+
declare const useChatLayoutContext: () => ChatLayoutContextValue;
|
|
13
|
+
export interface ChatLayoutRootProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
14
|
+
/** Initial sidebar open state */
|
|
15
|
+
defaultSidebarOpen?: boolean;
|
|
16
|
+
/** Initial panel size state */
|
|
17
|
+
defaultPanelSize?: PanelSize;
|
|
18
|
+
/** Initial active tab */
|
|
19
|
+
defaultActiveTab?: PanelTabType;
|
|
20
|
+
}
|
|
21
|
+
declare const ChatLayoutRoot: React.ForwardRefExoticComponent<ChatLayoutRootProps & React.RefAttributes<HTMLDivElement>>;
|
|
22
|
+
export interface ChatLayoutHeaderProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
23
|
+
}
|
|
24
|
+
declare const ChatLayoutHeader: React.ForwardRefExoticComponent<ChatLayoutHeaderProps & React.RefAttributes<HTMLDivElement>>;
|
|
25
|
+
export interface ChatLayoutMainProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
26
|
+
}
|
|
27
|
+
declare const ChatLayoutMain: React.ForwardRefExoticComponent<ChatLayoutMainProps & React.RefAttributes<HTMLDivElement>>;
|
|
28
|
+
export interface ChatLayoutBodyProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
29
|
+
/** Whether to show toaster */
|
|
30
|
+
showToaster?: boolean;
|
|
31
|
+
}
|
|
32
|
+
declare const ChatLayoutBody: React.ForwardRefExoticComponent<ChatLayoutBodyProps & React.RefAttributes<HTMLDivElement>>;
|
|
33
|
+
export interface ChatLayoutMessagesProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
34
|
+
/** Callback when scroll position changes */
|
|
35
|
+
onScrollChange?: (isAtBottom: boolean) => void;
|
|
36
|
+
/** Whether to show scroll to bottom button */
|
|
37
|
+
showScrollToBottom?: boolean;
|
|
38
|
+
}
|
|
39
|
+
declare const ChatLayoutMessages: React.ForwardRefExoticComponent<ChatLayoutMessagesProps & React.RefAttributes<HTMLDivElement>>;
|
|
40
|
+
export interface ChatLayoutFooterProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
41
|
+
}
|
|
42
|
+
declare const ChatLayoutFooter: React.ForwardRefExoticComponent<ChatLayoutFooterProps & React.RefAttributes<HTMLDivElement>>;
|
|
43
|
+
export interface ChatLayoutSidebarProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
44
|
+
}
|
|
45
|
+
declare const ChatLayoutSidebar: React.ForwardRefExoticComponent<ChatLayoutSidebarProps & React.RefAttributes<HTMLDivElement>>;
|
|
46
|
+
export interface ChatLayoutAsideProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
47
|
+
/** Show panel on these breakpoints (default: lg and above) */
|
|
48
|
+
breakpoint?: "md" | "lg" | "xl" | "2xl";
|
|
49
|
+
}
|
|
50
|
+
declare const ChatLayoutAside: React.ForwardRefExoticComponent<ChatLayoutAsideProps & React.RefAttributes<HTMLDivElement>>;
|
|
51
|
+
export { ChatLayoutRoot as Root, ChatLayoutHeader as Header, ChatLayoutMain as Main, ChatLayoutBody as Body, ChatLayoutMessages as Messages, ChatLayoutFooter as Footer, ChatLayoutSidebar as Sidebar, ChatLayoutAside as Aside, useChatLayoutContext, };
|
|
52
|
+
export type { PanelSize, PanelTabType };
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ArrowDown } from "lucide-react";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
import { Toaster } from "./Sonner.js";
|
|
6
|
+
const ChatLayoutContext = React.createContext(undefined);
|
|
7
|
+
const useChatLayoutContext = () => {
|
|
8
|
+
const context = React.useContext(ChatLayoutContext);
|
|
9
|
+
if (!context) {
|
|
10
|
+
throw new Error("ChatLayout components must be used within ChatLayout.Root");
|
|
11
|
+
}
|
|
12
|
+
return context;
|
|
13
|
+
};
|
|
14
|
+
const ChatLayoutRoot = React.forwardRef(({ defaultSidebarOpen = false, defaultPanelSize = "hidden", defaultActiveTab = "todo", className, children, ...props }, ref) => {
|
|
15
|
+
const [sidebarOpen, setSidebarOpen] = React.useState(defaultSidebarOpen);
|
|
16
|
+
const [panelSize, setPanelSize] = React.useState(defaultPanelSize);
|
|
17
|
+
const [activeTab, setActiveTab] = React.useState(defaultActiveTab);
|
|
18
|
+
return (_jsx(ChatLayoutContext.Provider, { value: {
|
|
19
|
+
sidebarOpen,
|
|
20
|
+
setSidebarOpen,
|
|
21
|
+
panelSize,
|
|
22
|
+
setPanelSize,
|
|
23
|
+
activeTab,
|
|
24
|
+
setActiveTab,
|
|
25
|
+
}, children: _jsx("div", { ref: ref, className: cn("flex h-screen flex-row bg-background text-foreground", className), ...props, children: children }) }));
|
|
26
|
+
});
|
|
27
|
+
ChatLayoutRoot.displayName = "ChatLayout.Root";
|
|
28
|
+
const ChatLayoutHeader = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
29
|
+
return (_jsx("div", { ref: ref, className: cn("relative z-10 border-b border-border bg-card shrink-0", className), ...props, children: children }));
|
|
30
|
+
});
|
|
31
|
+
ChatLayoutHeader.displayName = "ChatLayout.Header";
|
|
32
|
+
const ChatLayoutMain = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
33
|
+
return (_jsx("div", { ref: ref, className: cn("flex flex-1 flex-col overflow-hidden", className), ...props, children: children }));
|
|
34
|
+
});
|
|
35
|
+
ChatLayoutMain.displayName = "ChatLayout.Main";
|
|
36
|
+
const ChatLayoutBody = React.forwardRef(({ showToaster = true, className, children, ...props }, ref) => {
|
|
37
|
+
return (_jsxs("div", { ref: ref, className: cn("relative flex flex-1 flex-col overflow-hidden", className), ...props, children: [children, showToaster && _jsx(Toaster, {})] }));
|
|
38
|
+
});
|
|
39
|
+
ChatLayoutBody.displayName = "ChatLayout.Body";
|
|
40
|
+
const ChatLayoutMessages = React.forwardRef(({ className, children, onScrollChange, showScrollToBottom = true, ...props }, ref) => {
|
|
41
|
+
const [showScrollButton, setShowScrollButton] = React.useState(false);
|
|
42
|
+
const scrollContainerRef = React.useRef(null);
|
|
43
|
+
// Merge refs
|
|
44
|
+
React.useImperativeHandle(ref, () => scrollContainerRef.current);
|
|
45
|
+
// Check if user is at bottom of scroll
|
|
46
|
+
const checkScrollPosition = React.useCallback(() => {
|
|
47
|
+
const container = scrollContainerRef.current;
|
|
48
|
+
if (!container)
|
|
49
|
+
return;
|
|
50
|
+
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
51
|
+
const distanceFromBottom = scrollHeight - scrollTop - clientHeight;
|
|
52
|
+
const isAtBottom = distanceFromBottom < 100; // 100px threshold
|
|
53
|
+
setShowScrollButton(!isAtBottom && showScrollToBottom);
|
|
54
|
+
onScrollChange?.(isAtBottom);
|
|
55
|
+
}, [onScrollChange, showScrollToBottom]);
|
|
56
|
+
// Handle scroll events
|
|
57
|
+
const handleScroll = React.useCallback(() => {
|
|
58
|
+
checkScrollPosition();
|
|
59
|
+
}, [checkScrollPosition]);
|
|
60
|
+
// Scroll to bottom function
|
|
61
|
+
const scrollToBottom = React.useCallback(() => {
|
|
62
|
+
const container = scrollContainerRef.current;
|
|
63
|
+
if (!container)
|
|
64
|
+
return;
|
|
65
|
+
container.scrollTo({
|
|
66
|
+
top: container.scrollHeight,
|
|
67
|
+
behavior: "smooth",
|
|
68
|
+
});
|
|
69
|
+
}, []);
|
|
70
|
+
// Check scroll position on mount and when children change
|
|
71
|
+
React.useEffect(() => {
|
|
72
|
+
checkScrollPosition();
|
|
73
|
+
}, [checkScrollPosition]);
|
|
74
|
+
return (_jsxs("div", { className: "relative flex-1 overflow-hidden", children: [_jsx("div", { ref: scrollContainerRef, className: cn("h-full overflow-y-auto", className), onScroll: handleScroll, ...props, children: children }), showScrollButton && (_jsx("button", { type: "button", onClick: scrollToBottom, className: cn("absolute bottom-4 left-1/2 -translate-x-1/2 z-10", "flex items-center justify-center p-2 rounded-full", "bg-card border border-border shadow-lg", "text-foreground", "hover:bg-accent hover:text-accent-foreground", "transition-all duration-200 ease-in-out", "animate-in fade-in slide-in-from-bottom-2"), "aria-label": "Scroll to bottom", children: _jsx(ArrowDown, { className: "h-4 w-4" }) }))] }));
|
|
75
|
+
});
|
|
76
|
+
ChatLayoutMessages.displayName = "ChatLayout.Messages";
|
|
77
|
+
const ChatLayoutFooter = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
78
|
+
return (_jsx("div", { ref: ref, className: cn("bg-linear-to-t from-background to-transparent px-4 pb-4", className), ...props, children: children }));
|
|
79
|
+
});
|
|
80
|
+
ChatLayoutFooter.displayName = "ChatLayout.Footer";
|
|
81
|
+
const ChatLayoutSidebar = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
82
|
+
const { sidebarOpen } = useChatLayoutContext();
|
|
83
|
+
if (!sidebarOpen)
|
|
84
|
+
return null;
|
|
85
|
+
return (_jsx("div", { ref: ref, className: cn("border-r border-border bg-card w-64 overflow-y-auto", className), ...props, children: children }));
|
|
86
|
+
});
|
|
87
|
+
ChatLayoutSidebar.displayName = "ChatLayout.Sidebar";
|
|
88
|
+
const ChatLayoutAside = React.forwardRef(({ breakpoint = "lg", className, children, ...props }, ref) => {
|
|
89
|
+
const { panelSize } = useChatLayoutContext();
|
|
90
|
+
// Hidden state - don't render
|
|
91
|
+
if (panelSize === "hidden")
|
|
92
|
+
return null;
|
|
93
|
+
return (_jsx("div", { ref: ref, className: cn(
|
|
94
|
+
// Hidden by default, visible at breakpoint
|
|
95
|
+
"hidden border-l border-border bg-card overflow-y-auto transition-all duration-300",
|
|
96
|
+
// Breakpoint visibility
|
|
97
|
+
breakpoint === "md" && "md:block", breakpoint === "lg" && "lg:block", breakpoint === "xl" && "xl:block", breakpoint === "2xl" && "2xl:block",
|
|
98
|
+
// Size variants
|
|
99
|
+
panelSize === "small" && "w-80", panelSize === "large" && "w-lg", className), ...props, children: children }));
|
|
100
|
+
});
|
|
101
|
+
ChatLayoutAside.displayName = "ChatLayout.Aside";
|
|
102
|
+
/* -------------------------------------------------------------------------------------------------
|
|
103
|
+
* Exports
|
|
104
|
+
* -----------------------------------------------------------------------------------------------*/
|
|
105
|
+
export { ChatLayoutRoot as Root, ChatLayoutHeader as Header, ChatLayoutMain as Main, ChatLayoutBody as Body, ChatLayoutMessages as Messages, ChatLayoutFooter as Footer, ChatLayoutSidebar as Sidebar, ChatLayoutAside as Aside, useChatLayoutContext, };
|