@townco/ui 0.1.17 → 0.1.19
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/use-chat-input.d.ts +17 -17
- package/dist/core/hooks/use-chat-input.js +55 -64
- package/dist/core/hooks/use-chat-messages.js +114 -121
- package/dist/core/hooks/use-chat-session.d.ts +1 -1
- package/dist/core/hooks/use-chat-session.js +80 -78
- package/dist/gui/components/Button.d.ts +7 -23
- package/dist/gui/components/Button.js +27 -40
- package/dist/gui/components/Card.d.ts +7 -26
- package/dist/gui/components/Card.js +8 -54
- package/dist/gui/components/ChatEmptyState.d.ts +18 -0
- package/dist/gui/components/ChatEmptyState.js +22 -0
- package/dist/gui/components/ChatInput.js +29 -1
- package/dist/gui/components/ChatLayout.js +2 -2
- package/dist/gui/components/ChatSecondaryPanel.d.ts +25 -14
- package/dist/gui/components/ChatSecondaryPanel.js +60 -115
- package/dist/gui/components/ChatStatus.d.ts +2 -4
- package/dist/gui/components/ChatStatus.js +34 -45
- package/dist/gui/components/Conversation.d.ts +14 -17
- package/dist/gui/components/Conversation.js +83 -143
- package/dist/gui/components/Dialog.d.ts +11 -57
- package/dist/gui/components/HeightTransition.d.ts +7 -12
- package/dist/gui/components/HeightTransition.js +77 -88
- package/dist/gui/components/Input.d.ts +6 -13
- package/dist/gui/components/Input.js +16 -27
- package/dist/gui/components/Label.d.ts +1 -7
- package/dist/gui/components/MarkdownRenderer.d.ts +4 -6
- package/dist/gui/components/MarkdownRenderer.js +81 -178
- package/dist/gui/components/Message.d.ts +1 -1
- package/dist/gui/components/MessageContent.d.ts +22 -29
- package/dist/gui/components/PanelTabsHeader.d.ts +17 -0
- package/dist/gui/components/PanelTabsHeader.js +31 -0
- package/dist/gui/components/Reasoning.d.ts +24 -30
- package/dist/gui/components/Reasoning.js +60 -187
- package/dist/gui/components/Response.d.ts +9 -11
- package/dist/gui/components/Response.js +90 -229
- package/dist/gui/components/Select.d.ts +10 -69
- package/dist/gui/components/Tabs.d.ts +4 -24
- package/dist/gui/components/Task.d.ts +24 -28
- package/dist/gui/components/Task.js +31 -164
- package/dist/gui/components/Textarea.d.ts +7 -15
- package/dist/gui/components/Textarea.js +46 -63
- package/dist/gui/components/ThinkingBlock.d.ts +10 -20
- package/dist/gui/components/ThinkingBlock.js +35 -134
- package/dist/gui/components/TodoList.d.ts +10 -12
- package/dist/gui/components/TodoList.js +7 -22
- package/dist/gui/components/TodoListItem.d.ts +6 -9
- package/dist/gui/components/TodoListItem.js +4 -18
- package/dist/gui/components/index.d.ts +2 -0
- package/dist/gui/components/index.js +2 -0
- package/dist/gui/lib/utils.js +1 -1
- package/dist/index.test.js +1 -0
- package/dist/sdk/client/acp-client.d.ts +76 -88
- package/dist/sdk/client/acp-client.js +217 -215
- package/dist/sdk/schemas/agent.d.ts +64 -111
- package/dist/sdk/schemas/agent.js +24 -24
- package/dist/sdk/schemas/message.d.ts +147 -245
- package/dist/sdk/schemas/message.js +40 -40
- package/dist/sdk/schemas/session.d.ts +6 -6
- package/dist/sdk/transports/http.d.ts +55 -55
- package/dist/sdk/transports/http.js +3 -3
- package/dist/sdk/transports/stdio.d.ts +20 -20
- package/dist/sdk/transports/types.d.ts +42 -42
- package/dist/sdk/transports/websocket.d.ts +12 -12
- package/dist/sdk/transports/websocket.js +46 -52
- package/dist/tui/components/ChatView.d.ts +2 -4
- package/dist/tui/components/GameOfLife.js +35 -64
- package/dist/tui/components/InputBox.d.ts +11 -18
- package/dist/tui/components/InputBox.js +10 -70
- package/dist/tui/components/ReadlineInput.d.ts +6 -12
- package/dist/tui/components/ReadlineInput.js +237 -252
- package/dist/tui/components/SingleSelect.d.ts +9 -15
- package/dist/tui/components/SingleSelect.js +43 -84
- package/dist/tui/components/StatusBar.d.ts +6 -11
- package/dist/tui/components/StatusBar.js +67 -102
- package/package.json +2 -2
- package/src/styles/global.css +64 -0
- package/dist/core/hooks/index.d.ts.map +0 -1
- package/dist/core/hooks/index.js.map +0 -1
- package/dist/core/hooks/use-chat-input.d.ts.map +0 -1
- package/dist/core/hooks/use-chat-input.js.map +0 -1
- package/dist/core/hooks/use-chat-messages.d.ts.map +0 -1
- package/dist/core/hooks/use-chat-messages.js.map +0 -1
- package/dist/core/hooks/use-chat-session.d.ts.map +0 -1
- package/dist/core/hooks/use-chat-session.js.map +0 -1
- package/dist/core/index.d.ts.map +0 -1
- package/dist/core/index.js.map +0 -1
- package/dist/core/schemas/chat.d.ts.map +0 -1
- package/dist/core/schemas/chat.js.map +0 -1
- package/dist/core/schemas/index.d.ts.map +0 -1
- package/dist/core/schemas/index.js.map +0 -1
- package/dist/core/store/chat-store.d.ts.map +0 -1
- package/dist/core/store/chat-store.js.map +0 -1
- package/dist/gui/components/Button.d.ts.map +0 -1
- package/dist/gui/components/Button.js.map +0 -1
- package/dist/gui/components/Card.d.ts.map +0 -1
- package/dist/gui/components/Card.js.map +0 -1
- package/dist/gui/components/ChatInput.d.ts.map +0 -1
- package/dist/gui/components/ChatInput.js.map +0 -1
- package/dist/gui/components/ChatInterface.d.ts +0 -12
- package/dist/gui/components/ChatInterface.d.ts.map +0 -1
- package/dist/gui/components/ChatInterface.js +0 -204
- package/dist/gui/components/ChatInterface.js.map +0 -1
- package/dist/gui/components/ChatPreview.d.ts +0 -12
- package/dist/gui/components/ChatPreview.d.ts.map +0 -1
- package/dist/gui/components/ChatPreview.js +0 -214
- package/dist/gui/components/ChatPreview.js.map +0 -1
- package/dist/gui/components/ChatSecondaryPanel.d.ts.map +0 -1
- package/dist/gui/components/ChatSecondaryPanel.js.map +0 -1
- package/dist/gui/components/ChatStatus.d.ts.map +0 -1
- package/dist/gui/components/ChatStatus.js.map +0 -1
- package/dist/gui/components/ChatView.d.ts +0 -8
- package/dist/gui/components/ChatView.d.ts.map +0 -1
- package/dist/gui/components/ChatView.js +0 -42
- package/dist/gui/components/ChatView.js.map +0 -1
- package/dist/gui/components/ConfigPanel.d.ts +0 -20
- package/dist/gui/components/ConfigPanel.d.ts.map +0 -1
- package/dist/gui/components/ConfigPanel.js +0 -225
- package/dist/gui/components/ConfigPanel.js.map +0 -1
- package/dist/gui/components/Conversation.d.ts.map +0 -1
- package/dist/gui/components/Conversation.js.map +0 -1
- package/dist/gui/components/Dialog.d.ts.map +0 -1
- package/dist/gui/components/Dialog.js.map +0 -1
- package/dist/gui/components/HeightTransition.d.ts.map +0 -1
- package/dist/gui/components/HeightTransition.js.map +0 -1
- package/dist/gui/components/Input.d.ts.map +0 -1
- package/dist/gui/components/Input.js.map +0 -1
- package/dist/gui/components/InputBox.d.ts +0 -21
- package/dist/gui/components/InputBox.d.ts.map +0 -1
- package/dist/gui/components/InputBox.js +0 -90
- package/dist/gui/components/InputBox.js.map +0 -1
- package/dist/gui/components/Label.d.ts.map +0 -1
- package/dist/gui/components/Label.js.map +0 -1
- package/dist/gui/components/MarkdownRenderer.d.ts.map +0 -1
- package/dist/gui/components/MarkdownRenderer.js.map +0 -1
- package/dist/gui/components/Message.d.ts.map +0 -1
- package/dist/gui/components/Message.js.map +0 -1
- package/dist/gui/components/MessageContent.d.ts.map +0 -1
- package/dist/gui/components/MessageContent.js.map +0 -1
- package/dist/gui/components/MessageList.d.ts.map +0 -1
- package/dist/gui/components/MessageList.js.map +0 -1
- package/dist/gui/components/PlaygroundLayout.d.ts +0 -14
- package/dist/gui/components/PlaygroundLayout.d.ts.map +0 -1
- package/dist/gui/components/PlaygroundLayout.js +0 -49
- package/dist/gui/components/PlaygroundLayout.js.map +0 -1
- package/dist/gui/components/Reasoning.d.ts.map +0 -1
- package/dist/gui/components/Reasoning.js.map +0 -1
- package/dist/gui/components/Response.d.ts.map +0 -1
- package/dist/gui/components/Response.js.map +0 -1
- package/dist/gui/components/Select.d.ts.map +0 -1
- package/dist/gui/components/Select.js.map +0 -1
- package/dist/gui/components/StatusBar.d.ts +0 -12
- package/dist/gui/components/StatusBar.d.ts.map +0 -1
- package/dist/gui/components/StatusBar.js +0 -58
- package/dist/gui/components/StatusBar.js.map +0 -1
- package/dist/gui/components/Tabs.d.ts.map +0 -1
- package/dist/gui/components/Tabs.js.map +0 -1
- package/dist/gui/components/Task.d.ts.map +0 -1
- package/dist/gui/components/Task.js.map +0 -1
- package/dist/gui/components/Textarea.d.ts.map +0 -1
- package/dist/gui/components/Textarea.js.map +0 -1
- package/dist/gui/components/ThinkingBlock.d.ts.map +0 -1
- package/dist/gui/components/ThinkingBlock.js.map +0 -1
- package/dist/gui/components/TodoList.d.ts.map +0 -1
- package/dist/gui/components/TodoList.js.map +0 -1
- package/dist/gui/components/TodoListItem.d.ts.map +0 -1
- package/dist/gui/components/TodoListItem.js.map +0 -1
- package/dist/gui/components/index.d.ts.map +0 -1
- package/dist/gui/components/index.js.map +0 -1
- package/dist/gui/index.d.ts.map +0 -1
- package/dist/gui/index.js.map +0 -1
- package/dist/gui/lib/utils.d.ts.map +0 -1
- package/dist/gui/lib/utils.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/sdk/client/acp-client.d.ts.map +0 -1
- package/dist/sdk/client/acp-client.js.map +0 -1
- package/dist/sdk/client/index.d.ts.map +0 -1
- package/dist/sdk/client/index.js.map +0 -1
- package/dist/sdk/index.d.ts.map +0 -1
- package/dist/sdk/index.js.map +0 -1
- package/dist/sdk/schemas/agent.d.ts.map +0 -1
- package/dist/sdk/schemas/agent.js.map +0 -1
- package/dist/sdk/schemas/index.d.ts.map +0 -1
- package/dist/sdk/schemas/index.js.map +0 -1
- package/dist/sdk/schemas/message.d.ts.map +0 -1
- package/dist/sdk/schemas/message.js.map +0 -1
- package/dist/sdk/schemas/session.d.ts.map +0 -1
- package/dist/sdk/schemas/session.js.map +0 -1
- package/dist/sdk/transports/http.d.ts.map +0 -1
- package/dist/sdk/transports/http.js.map +0 -1
- package/dist/sdk/transports/index.d.ts.map +0 -1
- package/dist/sdk/transports/index.js.map +0 -1
- package/dist/sdk/transports/stdio.d.ts.map +0 -1
- package/dist/sdk/transports/stdio.js.map +0 -1
- package/dist/sdk/transports/types.d.ts.map +0 -1
- package/dist/sdk/transports/types.js.map +0 -1
- package/dist/sdk/transports/websocket.d.ts.map +0 -1
- package/dist/sdk/transports/websocket.js.map +0 -1
- package/dist/tui/components/ChatView.d.ts.map +0 -1
- package/dist/tui/components/ChatView.js.map +0 -1
- package/dist/tui/components/GameOfLife.d.ts.map +0 -1
- package/dist/tui/components/GameOfLife.js.map +0 -1
- package/dist/tui/components/InputBox.d.ts.map +0 -1
- package/dist/tui/components/InputBox.js.map +0 -1
- package/dist/tui/components/MessageList.d.ts.map +0 -1
- package/dist/tui/components/MessageList.js.map +0 -1
- package/dist/tui/components/ReadlineInput.d.ts.map +0 -1
- package/dist/tui/components/ReadlineInput.js.map +0 -1
- package/dist/tui/components/StatusBar.d.ts.map +0 -1
- package/dist/tui/components/StatusBar.js.map +0 -1
- package/dist/tui/components/index.d.ts.map +0 -1
- package/dist/tui/components/index.js.map +0 -1
- package/dist/tui/index.d.ts.map +0 -1
- package/dist/tui/index.js.map +0 -1
|
@@ -1,46 +1,33 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
2
|
import { Slot } from "@radix-ui/react-slot";
|
|
2
3
|
import { cva } from "class-variance-authority";
|
|
3
4
|
import * as React from "react";
|
|
4
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
5
|
import { cn } from "../lib/utils.js";
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
},
|
|
33
|
-
},
|
|
34
|
-
);
|
|
35
|
-
const Button = React.forwardRef(
|
|
36
|
-
({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
37
|
-
const Comp = asChild ? Slot : "button";
|
|
38
|
-
return _jsx(Comp, {
|
|
39
|
-
className: cn(buttonVariants({ variant, size, className })),
|
|
40
|
-
ref: ref,
|
|
41
|
-
...props,
|
|
42
|
-
});
|
|
43
|
-
},
|
|
44
|
-
);
|
|
6
|
+
const buttonVariants = cva("inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 cursor-pointer", {
|
|
7
|
+
variants: {
|
|
8
|
+
variant: {
|
|
9
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
10
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
11
|
+
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
|
12
|
+
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
|
13
|
+
ghost: "hover:bg-accent hover:text-accent-foreground",
|
|
14
|
+
link: "text-primary underline-offset-4 hover:underline",
|
|
15
|
+
},
|
|
16
|
+
size: {
|
|
17
|
+
default: "h-10 px-4 py-2",
|
|
18
|
+
sm: "h-9 rounded-md px-3",
|
|
19
|
+
lg: "h-11 rounded-md px-8",
|
|
20
|
+
icon: "h-10 w-10",
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
defaultVariants: {
|
|
24
|
+
variant: "default",
|
|
25
|
+
size: "default",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
const Button = React.forwardRef(({ className, variant, size, asChild = false, ...props }, ref) => {
|
|
29
|
+
const Comp = asChild ? Slot : "button";
|
|
30
|
+
return (_jsx(Comp, { className: cn(buttonVariants({ variant, size, className })), ref: ref, ...props }));
|
|
31
|
+
});
|
|
45
32
|
Button.displayName = "Button";
|
|
46
33
|
export { Button, buttonVariants };
|
|
@@ -1,27 +1,8 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
declare const Card: React.ForwardRefExoticComponent<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
declare const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
|
|
10
|
-
>;
|
|
11
|
-
declare const CardDescription: React.ForwardRefExoticComponent<
|
|
12
|
-
React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
|
|
13
|
-
>;
|
|
14
|
-
declare const CardContent: React.ForwardRefExoticComponent<
|
|
15
|
-
React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
|
|
16
|
-
>;
|
|
17
|
-
declare const CardFooter: React.ForwardRefExoticComponent<
|
|
18
|
-
React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>
|
|
19
|
-
>;
|
|
20
|
-
export {
|
|
21
|
-
Card,
|
|
22
|
-
CardHeader,
|
|
23
|
-
CardFooter,
|
|
24
|
-
CardTitle,
|
|
25
|
-
CardDescription,
|
|
26
|
-
CardContent,
|
|
27
|
-
};
|
|
2
|
+
declare const Card: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
3
|
+
declare const CardHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
4
|
+
declare const CardTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
5
|
+
declare const CardDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
6
|
+
declare const CardContent: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
7
|
+
declare const CardFooter: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
|
|
8
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent, };
|
|
@@ -1,62 +1,16 @@
|
|
|
1
|
-
import * as React from "react";
|
|
2
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import * as React from "react";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
|
-
|
|
5
|
-
const Card = React.forwardRef(({ className, ...props }, ref) =>
|
|
6
|
-
_jsx("div", {
|
|
7
|
-
ref: ref,
|
|
8
|
-
className: cn(
|
|
9
|
-
"rounded-lg border bg-card text-card-foreground shadow-sm",
|
|
10
|
-
className,
|
|
11
|
-
),
|
|
12
|
-
...props,
|
|
13
|
-
}),
|
|
14
|
-
);
|
|
4
|
+
const Card = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("rounded-lg border bg-card text-card-foreground shadow-sm", className), ...props })));
|
|
15
5
|
Card.displayName = "Card";
|
|
16
|
-
const CardHeader = React.forwardRef(({ className, ...props }, ref) =>
|
|
17
|
-
_jsx("div", {
|
|
18
|
-
ref: ref,
|
|
19
|
-
className: cn("flex flex-col space-y-1.5 p-6", className),
|
|
20
|
-
...props,
|
|
21
|
-
}),
|
|
22
|
-
);
|
|
6
|
+
const CardHeader = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("flex flex-col space-y-1.5 p-6", className), ...props })));
|
|
23
7
|
CardHeader.displayName = "CardHeader";
|
|
24
|
-
const CardTitle = React.forwardRef(({ className, ...props }, ref) =>
|
|
25
|
-
_jsx("div", {
|
|
26
|
-
ref: ref,
|
|
27
|
-
className: cn(
|
|
28
|
-
"text-2xl font-semibold leading-none tracking-tight",
|
|
29
|
-
className,
|
|
30
|
-
),
|
|
31
|
-
...props,
|
|
32
|
-
}),
|
|
33
|
-
);
|
|
8
|
+
const CardTitle = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })));
|
|
34
9
|
CardTitle.displayName = "CardTitle";
|
|
35
|
-
const CardDescription = React.forwardRef(({ className, ...props }, ref) =>
|
|
36
|
-
_jsx("div", {
|
|
37
|
-
ref: ref,
|
|
38
|
-
className: cn("text-sm text-muted-foreground", className),
|
|
39
|
-
...props,
|
|
40
|
-
}),
|
|
41
|
-
);
|
|
10
|
+
const CardDescription = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("text-sm text-muted-foreground", className), ...props })));
|
|
42
11
|
CardDescription.displayName = "CardDescription";
|
|
43
|
-
const CardContent = React.forwardRef(({ className, ...props }, ref) =>
|
|
44
|
-
_jsx("div", { ref: ref, className: cn("p-6 pt-0", className), ...props }),
|
|
45
|
-
);
|
|
12
|
+
const CardContent = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("p-6 pt-0", className), ...props })));
|
|
46
13
|
CardContent.displayName = "CardContent";
|
|
47
|
-
const CardFooter = React.forwardRef(({ className, ...props }, ref) =>
|
|
48
|
-
_jsx("div", {
|
|
49
|
-
ref: ref,
|
|
50
|
-
className: cn("flex items-center p-6 pt-0", className),
|
|
51
|
-
...props,
|
|
52
|
-
}),
|
|
53
|
-
);
|
|
14
|
+
const CardFooter = React.forwardRef(({ className, ...props }, ref) => (_jsx("div", { ref: ref, className: cn("flex items-center p-6 pt-0", className), ...props })));
|
|
54
15
|
CardFooter.displayName = "CardFooter";
|
|
55
|
-
export {
|
|
56
|
-
Card,
|
|
57
|
-
CardHeader,
|
|
58
|
-
CardFooter,
|
|
59
|
-
CardTitle,
|
|
60
|
-
CardDescription,
|
|
61
|
-
CardContent,
|
|
62
|
-
};
|
|
16
|
+
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent, };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
export interface ChatEmptyStateProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
3
|
+
/** Agent name/title */
|
|
4
|
+
title: string;
|
|
5
|
+
/** Agent description */
|
|
6
|
+
description: string;
|
|
7
|
+
/** Optional guide link URL */
|
|
8
|
+
guideUrl?: string;
|
|
9
|
+
/** Optional guide link text */
|
|
10
|
+
guideText?: string;
|
|
11
|
+
/** Suggested prompts */
|
|
12
|
+
suggestedPrompts?: string[];
|
|
13
|
+
/** Callback when a prompt is clicked */
|
|
14
|
+
onPromptClick?: (prompt: string) => void;
|
|
15
|
+
/** Callback when guide is clicked */
|
|
16
|
+
onGuideClick?: () => void;
|
|
17
|
+
}
|
|
18
|
+
export declare const ChatEmptyState: React.ForwardRefExoticComponent<ChatEmptyStateProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronRight } from "lucide-react";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../lib/utils.js";
|
|
5
|
+
export const ChatEmptyState = React.forwardRef(({ title, description, guideUrl, guideText = "Guide", suggestedPrompts = [], onPromptClick, onGuideClick, className, ...props }, ref) => {
|
|
6
|
+
const handlePromptClick = (prompt) => {
|
|
7
|
+
onPromptClick?.(prompt);
|
|
8
|
+
};
|
|
9
|
+
const handleGuideClick = () => {
|
|
10
|
+
if (guideUrl) {
|
|
11
|
+
window.open(guideUrl, "_blank", "noopener,noreferrer");
|
|
12
|
+
}
|
|
13
|
+
onGuideClick?.();
|
|
14
|
+
};
|
|
15
|
+
// Group prompts into rows of 2
|
|
16
|
+
const promptRows = [];
|
|
17
|
+
for (let i = 0; i < suggestedPrompts.length; i += 2) {
|
|
18
|
+
promptRows.push(suggestedPrompts.slice(i, i + 2));
|
|
19
|
+
}
|
|
20
|
+
return (_jsxs("div", { ref: ref, className: cn("flex flex-col items-start gap-6", className), ...props, children: [_jsx("h3", { className: "text-heading-3 text-text-primary hidden lg:block", children: title }), _jsx("p", { className: "text-subheading text-text-secondary max-w-prose", children: description }), (guideUrl || onGuideClick) && (_jsxs("button", { type: "button", onClick: handleGuideClick, className: "flex items-center gap-2 px-3 py-1.5 rounded-lg hover:bg-accent transition-colors", children: [_jsx("span", { className: "text-sm font-medium leading-normal text-text-primary", children: guideText }), _jsx(ChevronRight, { className: "size-4 text-text-primary" })] })), suggestedPrompts.length > 0 && (_jsxs("div", { className: "flex flex-col gap-3 w-full max-w-prompt-container", children: [_jsx("p", { className: "text-label text-text-tertiary", children: "Suggested Prompts" }), _jsx("div", { className: "flex flex-col gap-2.5", children: promptRows.map((row) => (_jsx("div", { className: "flex gap-2.5 items-center", children: row.map((prompt) => (_jsx("button", { type: "button", onClick: () => handlePromptClick(prompt), className: "flex-1 flex items-start gap-2 p-3 bg-secondary hover:bg-secondary/80 rounded-2xl transition-colors min-w-0", children: _jsx("span", { className: "text-base font-normal leading-normal text-text-tertiary truncate", children: prompt }) }, prompt))) }, row.join("-")))) })] }))] }));
|
|
21
|
+
});
|
|
22
|
+
ChatEmptyState.displayName = "ChatEmptyState";
|
|
@@ -48,6 +48,34 @@ const ChatInputRoot = React.forwardRef(({ client, value: valueProp, onChange: on
|
|
|
48
48
|
}, 0);
|
|
49
49
|
}
|
|
50
50
|
};
|
|
51
|
+
// Handle clicks on the composer to focus the input field
|
|
52
|
+
const handleFormClick = (e) => {
|
|
53
|
+
// Don't focus if clicking on interactive elements (buttons, inputs, etc.)
|
|
54
|
+
const target = e.target;
|
|
55
|
+
const isInteractive = target.tagName === "BUTTON" ||
|
|
56
|
+
target.tagName === "INPUT" ||
|
|
57
|
+
target.tagName === "TEXTAREA" ||
|
|
58
|
+
target.closest("button");
|
|
59
|
+
if (!isInteractive && textareaRef.current) {
|
|
60
|
+
textareaRef.current.focus();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
// Handle keyboard events for accessibility
|
|
64
|
+
const handleFormKeyDown = (e) => {
|
|
65
|
+
// Focus input when Space is pressed on the form (but not on interactive elements)
|
|
66
|
+
// Enter is handled by form submission, so we don't intercept it
|
|
67
|
+
const target = e.target;
|
|
68
|
+
const isInteractive = target.tagName === "BUTTON" ||
|
|
69
|
+
target.tagName === "INPUT" ||
|
|
70
|
+
target.tagName === "TEXTAREA" ||
|
|
71
|
+
target.closest("button");
|
|
72
|
+
if (!isInteractive && e.key === " ") {
|
|
73
|
+
e.preventDefault();
|
|
74
|
+
if (textareaRef.current) {
|
|
75
|
+
textareaRef.current.focus();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
51
79
|
// Expose textarea ref to children via context
|
|
52
80
|
React.useEffect(() => {
|
|
53
81
|
const textarea = document.querySelector('textarea[name="chat-input"]');
|
|
@@ -79,7 +107,7 @@ const ChatInputRoot = React.forwardRef(({ client, value: valueProp, onChange: on
|
|
|
79
107
|
setMenuItemCount,
|
|
80
108
|
triggerMenuSelect,
|
|
81
109
|
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 }) }));
|
|
110
|
+
}, children: _jsx("form", { ref: ref, onSubmit: handleSubmit, onClick: handleFormClick, onKeyDown: handleFormKeyDown, className: cn("relative w-full divide-y rounded-xl border bg-background shadow-md", className), ...props, children: children }) }));
|
|
83
111
|
});
|
|
84
112
|
ChatInputRoot.displayName = "ChatInput.Root";
|
|
85
113
|
const ChatInputField = React.forwardRef(({ asChild = false, className, onKeyDown, children, ...props }, ref) => {
|
|
@@ -72,11 +72,11 @@ const ChatLayoutMessages = React.forwardRef(({ className, children, onScrollChan
|
|
|
72
72
|
React.useEffect(() => {
|
|
73
73
|
checkScrollPosition();
|
|
74
74
|
}, [checkScrollPosition]);
|
|
75
|
-
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: "
|
|
75
|
+
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: _jsx("div", { className: "mx-auto max-w-chat min-h-full flex flex-col", 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: "size-4" }) }))] }));
|
|
76
76
|
});
|
|
77
77
|
ChatLayoutMessages.displayName = "ChatLayout.Messages";
|
|
78
78
|
const ChatLayoutFooter = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
79
|
-
return (_jsx("div", { ref: ref, className: cn("bg-linear-to-t from-background to-transparent px-4 pb-4", className), ...props, children: children }));
|
|
79
|
+
return (_jsx("div", { ref: ref, className: cn("bg-linear-to-t from-background to-transparent px-4 pb-4", className), ...props, children: _jsx("div", { className: "mx-auto max-w-chat", children: children }) }));
|
|
80
80
|
});
|
|
81
81
|
ChatLayoutFooter.displayName = "ChatLayout.Footer";
|
|
82
82
|
const ChatLayoutSidebar = React.forwardRef(({ className, children, ...props }, ref) => {
|
|
@@ -6,18 +6,29 @@ import type { TodoItem } from "./TodoListItem.js";
|
|
|
6
6
|
* 1. Hook-based: Pass `client` prop (future support when todos are in store)
|
|
7
7
|
* 2. Prop-based: Pass `todos` prop directly
|
|
8
8
|
*/
|
|
9
|
-
export interface ChatSecondaryPanelProps
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
9
|
+
export interface ChatSecondaryPanelProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
10
|
+
/**
|
|
11
|
+
* ACP Client for hook-based todo fetching (future support)
|
|
12
|
+
*/
|
|
13
|
+
client?: AcpClient | null;
|
|
14
|
+
/**
|
|
15
|
+
* Todos to display (prop-based pattern)
|
|
16
|
+
* Either client or todos should be provided
|
|
17
|
+
*/
|
|
18
|
+
todos?: TodoItem[];
|
|
19
|
+
/**
|
|
20
|
+
* Styling variant
|
|
21
|
+
* - 'animated': Clip-path animated tabs (original style)
|
|
22
|
+
* - 'pills': Simple pill-style tabs with background (Figma design)
|
|
23
|
+
*/
|
|
24
|
+
variant?: "animated" | "pills";
|
|
25
|
+
/**
|
|
26
|
+
* Whether to show icons in tabs (for pills variant)
|
|
27
|
+
*/
|
|
28
|
+
showIcons?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Which tabs to show
|
|
31
|
+
*/
|
|
32
|
+
visibleTabs?: ("todo" | "files" | "database")[];
|
|
20
33
|
}
|
|
21
|
-
export declare const ChatSecondaryPanel: React.ForwardRefExoticComponent<
|
|
22
|
-
ChatSecondaryPanelProps & React.RefAttributes<HTMLDivElement>
|
|
23
|
-
>;
|
|
34
|
+
export declare const ChatSecondaryPanel: React.ForwardRefExoticComponent<ChatSecondaryPanelProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -1,121 +1,66 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { CheckSquare, Database, FileText } from "lucide-react";
|
|
1
3
|
import * as React from "react";
|
|
2
4
|
import { useEffect, useRef, useState } from "react";
|
|
3
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
4
5
|
import { cn } from "../lib/utils.js";
|
|
6
|
+
import { FilesTabContent, TodoTabContent } from "./ChatPanelTabContent.js";
|
|
5
7
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "./Tabs.js";
|
|
6
8
|
import { TodoList } from "./TodoList.js";
|
|
7
|
-
export const ChatSecondaryPanel = React.forwardRef(
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
},
|
|
65
|
-
tab.id,
|
|
66
|
-
),
|
|
67
|
-
),
|
|
68
|
-
}),
|
|
69
|
-
_jsx("div", {
|
|
70
|
-
ref: containerRef,
|
|
71
|
-
className:
|
|
72
|
-
"absolute top-0 left-0 w-full overflow-hidden z-10 pointer-events-none",
|
|
73
|
-
style: {
|
|
74
|
-
clipPath: "inset(0 100% 0 0% round 999px)",
|
|
75
|
-
transition: "clip-path 0.25s ease-out",
|
|
76
|
-
},
|
|
77
|
-
children: _jsx(TabsList, {
|
|
78
|
-
className:
|
|
79
|
-
"bg-secondary p-0 h-auto rounded-none w-full border-none",
|
|
80
|
-
children: tabs.map((tab) =>
|
|
81
|
-
_jsx(
|
|
82
|
-
TabsTrigger,
|
|
83
|
-
{
|
|
84
|
-
value: tab.id,
|
|
85
|
-
ref: activeTab === tab.id ? activeTabElementRef : null,
|
|
86
|
-
className:
|
|
87
|
-
"px-3 py-1 text-sm font-[var(--font-family)] font-medium rounded-none text-primary bg-transparent data-[state=active]:shadow-none shadow-none",
|
|
88
|
-
tabIndex: -1,
|
|
89
|
-
children: tab.label,
|
|
90
|
-
},
|
|
91
|
-
tab.id,
|
|
92
|
-
),
|
|
93
|
-
),
|
|
94
|
-
}),
|
|
95
|
-
}),
|
|
96
|
-
],
|
|
97
|
-
}),
|
|
98
|
-
_jsx(TabsContent, {
|
|
99
|
-
value: "todo",
|
|
100
|
-
children: _jsx(TodoList, { todos: todosToDisplay }),
|
|
101
|
-
}),
|
|
102
|
-
_jsx(TabsContent, {
|
|
103
|
-
value: "files",
|
|
104
|
-
children: _jsx("div", {
|
|
105
|
-
className: "text-sm text-foreground opacity-60 italic",
|
|
106
|
-
children: "Files tab coming soon...",
|
|
107
|
-
}),
|
|
108
|
-
}),
|
|
109
|
-
_jsx(TabsContent, {
|
|
110
|
-
value: "database",
|
|
111
|
-
children: _jsx("div", {
|
|
112
|
-
className: "text-sm text-foreground opacity-60 italic",
|
|
113
|
-
children: "Database tab coming soon...",
|
|
114
|
-
}),
|
|
115
|
-
}),
|
|
116
|
-
],
|
|
117
|
-
}),
|
|
118
|
-
});
|
|
119
|
-
},
|
|
120
|
-
);
|
|
9
|
+
export const ChatSecondaryPanel = React.forwardRef(({ client, todos, variant = "animated", showIcons = false, visibleTabs = ["todo", "files", "database"], className, ...props }, ref) => {
|
|
10
|
+
// For now, just use prop-based todos
|
|
11
|
+
// Future: Add hook to get todos from store when available
|
|
12
|
+
const todosToDisplay = todos || [];
|
|
13
|
+
const [activeTab, setActiveTab] = useState(visibleTabs[0] || "todo");
|
|
14
|
+
const containerRef = useRef(null);
|
|
15
|
+
const activeTabElementRef = useRef(null);
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
const updateClipPath = () => {
|
|
18
|
+
const container = containerRef.current;
|
|
19
|
+
if (activeTab && container) {
|
|
20
|
+
const activeTabElement = activeTabElementRef.current;
|
|
21
|
+
if (activeTabElement) {
|
|
22
|
+
const containerRect = container.getBoundingClientRect();
|
|
23
|
+
const tabRect = activeTabElement.getBoundingClientRect();
|
|
24
|
+
const offsetLeft = tabRect.left - containerRect.left;
|
|
25
|
+
const offsetWidth = tabRect.width;
|
|
26
|
+
const clipLeftPercent = (offsetLeft / containerRect.width) * 100;
|
|
27
|
+
const clipRightPercent = 100 - ((offsetLeft + offsetWidth) / containerRect.width) * 100;
|
|
28
|
+
container.style.clipPath = `inset(0 ${clipRightPercent.toFixed(2)}% 0 ${clipLeftPercent.toFixed(2)}% round 999px)`;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
// Small delay to ensure DOM is ready
|
|
33
|
+
const timeoutId = setTimeout(updateClipPath, 0);
|
|
34
|
+
return () => clearTimeout(timeoutId);
|
|
35
|
+
}, [activeTab]);
|
|
36
|
+
const allTabs = [
|
|
37
|
+
{
|
|
38
|
+
id: "todo",
|
|
39
|
+
label: variant === "pills" ? "To-do" : "To-Do List",
|
|
40
|
+
icon: CheckSquare,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: "files",
|
|
44
|
+
label: "Files",
|
|
45
|
+
icon: FileText,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
id: "database",
|
|
49
|
+
label: "Database",
|
|
50
|
+
icon: Database,
|
|
51
|
+
},
|
|
52
|
+
];
|
|
53
|
+
const tabs = allTabs.filter((tab) => visibleTabs.includes(tab.id));
|
|
54
|
+
return (_jsx("div", { ref: ref, className: cn("select-none", className), ...props, children: _jsxs(Tabs, { value: activeTab, onValueChange: setActiveTab, className: "w-full", children: [variant === "pills" ? (
|
|
55
|
+
// Pills variant - Simple background highlight (Figma design)
|
|
56
|
+
_jsx(TabsList, { className: cn("w-full justify-start bg-transparent p-0 h-auto", "gap-1"), children: tabs.map((tab) => {
|
|
57
|
+
const Icon = tab.icon;
|
|
58
|
+
return (_jsxs(TabsTrigger, { value: tab.id, className: cn("gap-2 px-3 py-1.5 rounded-lg text-sm font-medium", "data-[state=active]:bg-zinc-100 data-[state=active]:text-foreground", "data-[state=inactive]:text-muted-foreground"), children: [showIcons && Icon && _jsx(Icon, { className: "size-4" }), tab.label] }, tab.id));
|
|
59
|
+
}) })) : (
|
|
60
|
+
// Animated variant - Clip-path animation (original style)
|
|
61
|
+
_jsxs("div", { className: "relative mb-4 border-border", children: [_jsx(TabsList, { className: "bg-transparent p-0 h-auto rounded-none w-full border-none", children: tabs.map((tab) => (_jsx(TabsTrigger, { value: tab.id, className: "px-3 py-1 text-sm font-[var(--font-family)] font-medium rounded-none text-foreground opacity-60 data-[state=active]:opacity-100 data-[state=active]:bg-transparent data-[state=active]:shadow-none", children: tab.label }, tab.id))) }), _jsx("div", { ref: containerRef, className: "absolute top-0 left-0 w-full overflow-hidden z-10 pointer-events-none", style: {
|
|
62
|
+
clipPath: "inset(0 100% 0 0% round 999px)",
|
|
63
|
+
transition: "clip-path 0.25s ease-out",
|
|
64
|
+
}, children: _jsx(TabsList, { className: "bg-secondary p-0 h-auto rounded-none w-full border-none", children: tabs.map((tab) => (_jsx(TabsTrigger, { value: tab.id, ref: activeTab === tab.id ? activeTabElementRef : null, className: "px-3 py-1 text-sm font-[var(--font-family)] font-medium rounded-none text-primary bg-transparent data-[state=active]:shadow-none shadow-none", tabIndex: -1, children: tab.label }, tab.id))) }) })] })), _jsx(TabsContent, { value: "todo", className: variant === "pills" ? "mt-0" : "", children: variant === "pills" ? (_jsx(TodoTabContent, { todos: todosToDisplay })) : (_jsx(TodoList, { todos: todosToDisplay })) }), _jsx(TabsContent, { value: "files", className: variant === "pills" ? "mt-0" : "", children: _jsx(FilesTabContent, {}) }), _jsx(TabsContent, { value: "database", className: variant === "pills" ? "mt-0" : "", children: _jsx("div", { className: "text-sm text-foreground opacity-60 italic", children: "Database tab coming soon..." }) })] }) }));
|
|
65
|
+
});
|
|
121
66
|
ChatSecondaryPanel.displayName = "ChatSecondaryPanel";
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { type ReactNode } from "react";
|
|
3
3
|
export interface ChatStatusProps extends React.HTMLAttributes<HTMLSpanElement> {
|
|
4
|
-
|
|
4
|
+
children: ReactNode;
|
|
5
5
|
}
|
|
6
|
-
export declare const ChatStatus: React.ForwardRefExoticComponent<
|
|
7
|
-
ChatStatusProps & React.RefAttributes<HTMLSpanElement>
|
|
8
|
-
>;
|
|
6
|
+
export declare const ChatStatus: React.ForwardRefExoticComponent<ChatStatusProps & React.RefAttributes<HTMLSpanElement>>;
|
|
@@ -1,49 +1,38 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
2
|
import * as React from "react";
|
|
2
3
|
import { useEffect, useRef, useState } from "react";
|
|
3
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
4
4
|
import { cn } from "../lib/utils.js";
|
|
5
|
-
export const ChatStatus = React.forwardRef(
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
ref: ref,
|
|
39
|
-
className: cn(
|
|
40
|
-
"text-sm text-foreground opacity-60 transition-opacity duration-300",
|
|
41
|
-
isTransitioning ? "opacity-0" : "opacity-60",
|
|
42
|
-
className,
|
|
43
|
-
),
|
|
44
|
-
...props,
|
|
45
|
-
children: displayContent,
|
|
46
|
-
});
|
|
47
|
-
},
|
|
48
|
-
);
|
|
5
|
+
export const ChatStatus = React.forwardRef(({ children, className, ...props }, ref) => {
|
|
6
|
+
const [displayContent, setDisplayContent] = useState(children);
|
|
7
|
+
const [isTransitioning, setIsTransitioning] = useState(false);
|
|
8
|
+
const previousContentRef = useRef(children);
|
|
9
|
+
const isInitialMountRef = useRef(true);
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
// Skip transition on initial mount
|
|
12
|
+
if (isInitialMountRef.current) {
|
|
13
|
+
isInitialMountRef.current = false;
|
|
14
|
+
previousContentRef.current = children;
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
// Only transition if content actually changed
|
|
18
|
+
if (previousContentRef.current === children) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
// Start transition out
|
|
22
|
+
setIsTransitioning(true);
|
|
23
|
+
// After fade out, update content and fade in
|
|
24
|
+
const timeoutId = setTimeout(() => {
|
|
25
|
+
setDisplayContent(children);
|
|
26
|
+
previousContentRef.current = children;
|
|
27
|
+
// Trigger fade in
|
|
28
|
+
requestAnimationFrame(() => {
|
|
29
|
+
setIsTransitioning(false);
|
|
30
|
+
});
|
|
31
|
+
}, 150); // Half of transition duration (300ms total)
|
|
32
|
+
return () => {
|
|
33
|
+
clearTimeout(timeoutId);
|
|
34
|
+
};
|
|
35
|
+
}, [children]);
|
|
36
|
+
return (_jsx("span", { ref: ref, className: cn("text-sm text-foreground opacity-60 transition-opacity duration-300", isTransitioning ? "opacity-0" : "opacity-60", className), ...props, children: displayContent }));
|
|
37
|
+
});
|
|
49
38
|
ChatStatus.displayName = "ChatStatus";
|