@townco/ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +175 -0
- package/dist/core/hooks/index.d.ts +6 -0
- package/dist/core/hooks/index.d.ts.map +1 -0
- package/dist/core/hooks/index.js +6 -0
- package/dist/core/hooks/index.js.map +1 -0
- package/dist/core/hooks/use-chat-input.d.ts +23 -0
- package/dist/core/hooks/use-chat-input.d.ts.map +1 -0
- package/dist/core/hooks/use-chat-input.js +63 -0
- package/dist/core/hooks/use-chat-input.js.map +1 -0
- package/dist/core/hooks/use-chat-messages.d.ts +17 -0
- package/dist/core/hooks/use-chat-messages.d.ts.map +1 -0
- package/dist/core/hooks/use-chat-messages.js +121 -0
- package/dist/core/hooks/use-chat-messages.js.map +1 -0
- package/dist/core/hooks/use-chat-session.d.ts +11 -0
- package/dist/core/hooks/use-chat-session.d.ts.map +1 -0
- package/dist/core/hooks/use-chat-session.js +87 -0
- 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 +80 -0
- package/dist/core/index.d.ts +9 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +9 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/schemas/chat.d.ts +78 -0
- package/dist/core/schemas/chat.d.ts.map +1 -0
- package/dist/core/schemas/chat.js +49 -0
- package/dist/core/schemas/chat.js.map +1 -0
- package/dist/core/schemas/index.d.ts +4 -0
- package/dist/core/schemas/index.d.ts.map +1 -0
- package/dist/core/schemas/index.js +4 -0
- package/dist/core/schemas/index.js.map +1 -0
- package/dist/core/store/chat-store.d.ts +30 -0
- package/dist/core/store/chat-store.d.ts.map +1 -0
- package/dist/core/store/chat-store.js +56 -0
- package/dist/core/store/chat-store.js.map +1 -0
- package/dist/gui/components/Button.d.ts +11 -0
- package/dist/gui/components/Button.d.ts.map +1 -0
- package/dist/gui/components/Button.js +33 -0
- package/dist/gui/components/Button.js.map +1 -0
- package/dist/gui/components/Card.d.ts +8 -0
- package/dist/gui/components/Card.d.ts.map +1 -0
- package/dist/gui/components/Card.js +16 -0
- package/dist/gui/components/Card.js.map +1 -0
- package/dist/gui/components/ChatHeader.d.ts +38 -0
- package/dist/gui/components/ChatHeader.js +84 -0
- package/dist/gui/components/ChatInput.d.ts +42 -0
- package/dist/gui/components/ChatInput.d.ts.map +1 -0
- package/dist/gui/components/ChatInput.js +137 -0
- package/dist/gui/components/ChatInput.js.map +1 -0
- package/dist/gui/components/ChatInterface.d.ts +9 -0
- package/dist/gui/components/ChatInterface.d.ts.map +1 -0
- package/dist/gui/components/ChatInterface.js +132 -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 +9 -0
- package/dist/gui/components/ChatPreview.d.ts.map +1 -0
- package/dist/gui/components/ChatPreview.js +164 -0
- package/dist/gui/components/ChatPreview.js.map +1 -0
- package/dist/gui/components/ChatSecondaryPanel.d.ts +20 -0
- package/dist/gui/components/ChatSecondaryPanel.d.ts.map +1 -0
- package/dist/gui/components/ChatSecondaryPanel.js +44 -0
- 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 +6 -0
- package/dist/gui/components/ChatStatus.d.ts.map +1 -0
- package/dist/gui/components/ChatStatus.js +38 -0
- package/dist/gui/components/ChatStatus.js.map +1 -0
- package/dist/gui/components/ChatView.d.ts +6 -0
- package/dist/gui/components/ChatView.d.ts.map +1 -0
- package/dist/gui/components/ChatView.js +13 -0
- package/dist/gui/components/ChatView.js.map +1 -0
- package/dist/gui/components/ConfigPanel.d.ts +16 -0
- package/dist/gui/components/ConfigPanel.d.ts.map +1 -0
- package/dist/gui/components/ConfigPanel.js +48 -0
- package/dist/gui/components/ConfigPanel.js.map +1 -0
- package/dist/gui/components/Conversation.d.ts +20 -0
- package/dist/gui/components/Conversation.d.ts.map +1 -0
- package/dist/gui/components/Conversation.js +87 -0
- package/dist/gui/components/Conversation.js.map +1 -0
- package/dist/gui/components/Dialog.d.ts +19 -0
- package/dist/gui/components/Dialog.d.ts.map +1 -0
- package/dist/gui/components/Dialog.js +22 -0
- 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 +10 -0
- package/dist/gui/components/HeightTransition.d.ts.map +1 -0
- package/dist/gui/components/HeightTransition.js +80 -0
- package/dist/gui/components/HeightTransition.js.map +1 -0
- package/dist/gui/components/Input.d.ts +9 -0
- package/dist/gui/components/Input.d.ts.map +1 -0
- package/dist/gui/components/Input.js +21 -0
- package/dist/gui/components/Input.js.map +1 -0
- package/dist/gui/components/InputBox.d.ts +14 -0
- package/dist/gui/components/InputBox.d.ts.map +1 -0
- package/dist/gui/components/InputBox.js +18 -0
- package/dist/gui/components/InputBox.js.map +1 -0
- package/dist/gui/components/Label.d.ts +4 -0
- package/dist/gui/components/Label.d.ts.map +1 -0
- package/dist/gui/components/Label.js +7 -0
- package/dist/gui/components/Label.js.map +1 -0
- package/dist/gui/components/MarkdownRenderer.d.ts +6 -0
- package/dist/gui/components/MarkdownRenderer.d.ts.map +1 -0
- package/dist/gui/components/MarkdownRenderer.js +86 -0
- package/dist/gui/components/MarkdownRenderer.js.map +1 -0
- package/dist/gui/components/Message.d.ts +26 -0
- package/dist/gui/components/Message.d.ts.map +1 -0
- package/dist/gui/components/Message.js +33 -0
- package/dist/gui/components/Message.js.map +1 -0
- package/dist/gui/components/MessageContent.d.ts +26 -0
- package/dist/gui/components/MessageContent.d.ts.map +1 -0
- package/dist/gui/components/MessageContent.js +104 -0
- package/dist/gui/components/MessageContent.js.map +1 -0
- package/dist/gui/components/MessageList.d.ts +6 -0
- package/dist/gui/components/MessageList.d.ts.map +1 -0
- package/dist/gui/components/MessageList.js +1 -0
- package/dist/gui/components/MessageList.js.map +1 -0
- package/dist/gui/components/PlaygroundLayout.d.ts +10 -0
- package/dist/gui/components/PlaygroundLayout.d.ts.map +1 -0
- package/dist/gui/components/PlaygroundLayout.js +18 -0
- package/dist/gui/components/PlaygroundLayout.js.map +1 -0
- package/dist/gui/components/Reasoning.d.ts +31 -0
- package/dist/gui/components/Reasoning.d.ts.map +1 -0
- package/dist/gui/components/Reasoning.js +70 -0
- package/dist/gui/components/Reasoning.js.map +1 -0
- package/dist/gui/components/Response.d.ts +16 -0
- package/dist/gui/components/Response.d.ts.map +1 -0
- package/dist/gui/components/Response.js +95 -0
- package/dist/gui/components/Response.js.map +1 -0
- package/dist/gui/components/Select.d.ts +13 -0
- package/dist/gui/components/Select.d.ts.map +1 -0
- package/dist/gui/components/Select.js +26 -0
- 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 +8 -0
- package/dist/gui/components/StatusBar.d.ts.map +1 -0
- package/dist/gui/components/StatusBar.js +11 -0
- package/dist/gui/components/StatusBar.js.map +1 -0
- package/dist/gui/components/Tabs.d.ts +7 -0
- package/dist/gui/components/Tabs.d.ts.map +1 -0
- package/dist/gui/components/Tabs.js +12 -0
- package/dist/gui/components/Tabs.js.map +1 -0
- package/dist/gui/components/Task.d.ts +35 -0
- package/dist/gui/components/Task.d.ts.map +1 -0
- package/dist/gui/components/Task.js +37 -0
- package/dist/gui/components/Task.js.map +1 -0
- package/dist/gui/components/Textarea.d.ts +11 -0
- package/dist/gui/components/Textarea.d.ts.map +1 -0
- package/dist/gui/components/Textarea.js +51 -0
- package/dist/gui/components/Textarea.js.map +1 -0
- package/dist/gui/components/ThinkingBlock.d.ts +12 -0
- package/dist/gui/components/ThinkingBlock.d.ts.map +1 -0
- package/dist/gui/components/ThinkingBlock.js +40 -0
- package/dist/gui/components/ThinkingBlock.js.map +1 -0
- package/dist/gui/components/TodoList.d.ts +20 -0
- package/dist/gui/components/TodoList.d.ts.map +1 -0
- package/dist/gui/components/TodoList.js +11 -0
- package/dist/gui/components/TodoList.js.map +1 -0
- package/dist/gui/components/TodoListItem.d.ts +10 -0
- package/dist/gui/components/TodoListItem.d.ts.map +1 -0
- package/dist/gui/components/TodoListItem.js +7 -0
- package/dist/gui/components/TodoListItem.js.map +1 -0
- package/dist/gui/components/index.d.ts +23 -0
- package/dist/gui/components/index.d.ts.map +1 -0
- package/dist/gui/components/index.js +28 -0
- package/dist/gui/components/index.js.map +1 -0
- package/dist/gui/index.d.ts +2 -0
- package/dist/gui/index.d.ts.map +1 -0
- package/dist/gui/index.js +4 -0
- package/dist/gui/index.js.map +1 -0
- package/dist/gui/lib/utils.d.ts +2 -0
- package/dist/gui/lib/utils.d.ts.map +1 -0
- package/dist/gui/lib/utils.js +5 -0
- package/dist/gui/lib/utils.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/index.test.d.ts +0 -0
- package/dist/index.test.js +1 -0
- package/dist/sdk/client/acp-client.d.ts +84 -0
- package/dist/sdk/client/acp-client.d.ts.map +1 -0
- package/dist/sdk/client/acp-client.js +225 -0
- package/dist/sdk/client/acp-client.js.map +1 -0
- package/dist/sdk/client/index.d.ts +4 -0
- package/dist/sdk/client/index.d.ts.map +1 -0
- package/dist/sdk/client/index.js +4 -0
- package/dist/sdk/client/index.js.map +1 -0
- package/dist/sdk/index.d.ts +9 -0
- package/dist/sdk/index.d.ts.map +1 -0
- package/dist/sdk/index.js +9 -0
- package/dist/sdk/index.js.map +1 -0
- package/dist/sdk/schemas/agent.d.ts +87 -0
- package/dist/sdk/schemas/agent.d.ts.map +1 -0
- package/dist/sdk/schemas/agent.js +50 -0
- package/dist/sdk/schemas/agent.js.map +1 -0
- package/dist/sdk/schemas/index.d.ts +6 -0
- package/dist/sdk/schemas/index.d.ts.map +1 -0
- package/dist/sdk/schemas/index.js +6 -0
- package/dist/sdk/schemas/index.js.map +1 -0
- package/dist/sdk/schemas/message.d.ts +195 -0
- package/dist/sdk/schemas/message.d.ts.map +1 -0
- package/dist/sdk/schemas/message.js +95 -0
- package/dist/sdk/schemas/message.js.map +1 -0
- package/dist/sdk/schemas/session.d.ts +158 -0
- package/dist/sdk/schemas/session.d.ts.map +1 -0
- package/dist/sdk/schemas/session.js +54 -0
- package/dist/sdk/schemas/session.js.map +1 -0
- package/dist/sdk/transports/http.d.ts +63 -0
- package/dist/sdk/transports/http.d.ts.map +1 -0
- package/dist/sdk/transports/http.js +476 -0
- package/dist/sdk/transports/http.js.map +1 -0
- package/dist/sdk/transports/index.d.ts +7 -0
- package/dist/sdk/transports/index.d.ts.map +1 -0
- package/dist/sdk/transports/index.js +7 -0
- package/dist/sdk/transports/index.js.map +1 -0
- package/dist/sdk/transports/stdio.d.ts +28 -0
- package/dist/sdk/transports/stdio.d.ts.map +1 -0
- package/dist/sdk/transports/stdio.js +294 -0
- package/dist/sdk/transports/stdio.js.map +1 -0
- package/dist/sdk/transports/types.d.ts +63 -0
- package/dist/sdk/transports/types.d.ts.map +1 -0
- package/dist/sdk/transports/types.js +1 -0
- package/dist/sdk/transports/types.js.map +1 -0
- package/dist/sdk/transports/websocket.d.ts +20 -0
- package/dist/sdk/transports/websocket.d.ts.map +1 -0
- package/dist/sdk/transports/websocket.js +52 -0
- package/dist/sdk/transports/websocket.js.map +1 -0
- package/dist/tui/components/ChatView.d.ts +5 -0
- package/dist/tui/components/ChatView.d.ts.map +1 -0
- package/dist/tui/components/ChatView.js +24 -0
- package/dist/tui/components/ChatView.js.map +1 -0
- package/dist/tui/components/GameOfLife.d.ts +1 -0
- package/dist/tui/components/GameOfLife.d.ts.map +1 -0
- package/dist/tui/components/GameOfLife.js +50 -0
- package/dist/tui/components/GameOfLife.js.map +1 -0
- package/dist/tui/components/InputBox.d.ts +13 -0
- package/dist/tui/components/InputBox.d.ts.map +1 -0
- package/dist/tui/components/InputBox.js +15 -0
- package/dist/tui/components/InputBox.js.map +1 -0
- package/dist/tui/components/MessageList.d.ts +5 -0
- package/dist/tui/components/MessageList.d.ts.map +1 -0
- package/dist/tui/components/MessageList.js +16 -0
- package/dist/tui/components/MessageList.js.map +1 -0
- package/dist/tui/components/MultiSelect.d.ts +13 -0
- package/dist/tui/components/MultiSelect.js +72 -0
- package/dist/tui/components/ReadlineInput.d.ts +8 -0
- package/dist/tui/components/ReadlineInput.d.ts.map +1 -0
- package/dist/tui/components/ReadlineInput.js +240 -0
- package/dist/tui/components/ReadlineInput.js.map +1 -0
- package/dist/tui/components/SingleSelect.d.ts +13 -0
- package/dist/tui/components/SingleSelect.js +46 -0
- package/dist/tui/components/StatusBar.d.ts +9 -0
- package/dist/tui/components/StatusBar.d.ts.map +1 -0
- package/dist/tui/components/StatusBar.js +82 -0
- package/dist/tui/components/StatusBar.js.map +1 -0
- package/dist/tui/components/index.d.ts +11 -0
- package/dist/tui/components/index.d.ts.map +1 -0
- package/dist/tui/components/index.js +11 -0
- package/dist/tui/components/index.js.map +1 -0
- package/dist/tui/index.d.ts +7 -0
- package/dist/tui/index.d.ts.map +1 -0
- package/dist/tui/index.js +7 -0
- package/dist/tui/index.js.map +1 -0
- package/package.json +86 -0
- package/src/styles/global.css +152 -0
package/README.md
ADDED
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# @town/ui
|
|
2
|
+
|
|
3
|
+
Unified UI package with composable components for chat interfaces.
|
|
4
|
+
|
|
5
|
+
## Architecture
|
|
6
|
+
|
|
7
|
+
Three layers:
|
|
8
|
+
|
|
9
|
+
1. **Core** (`@town/ui/core`) - Headless business logic
|
|
10
|
+
1. **TUI** (`@town/ui/tui`) - Terminal renderers (Ink)
|
|
11
|
+
1. **GUI** (`@town/ui/gui`) - Web renderers (React + Tailwind)
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
bun add @town/ui @town/ui
|
|
17
|
+
|
|
18
|
+
# For TUI
|
|
19
|
+
bun add ink react
|
|
20
|
+
|
|
21
|
+
# For GUI
|
|
22
|
+
bun add react react-dom
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage
|
|
26
|
+
|
|
27
|
+
### Core (Headless Hooks)
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { useChatSession, useChatMessages, useChatInput } from "@town/ui/core";
|
|
31
|
+
|
|
32
|
+
function MyComponent({ client }) {
|
|
33
|
+
const { connectionStatus, sessionId } = useChatSession(client);
|
|
34
|
+
const { messages, isStreaming, sendMessage } = useChatMessages(client);
|
|
35
|
+
const { value, onChange, onSubmit } = useChatInput(client);
|
|
36
|
+
|
|
37
|
+
// Use these hooks to build any UI!
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### TUI (Terminal)
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { render } from "ink";
|
|
45
|
+
import { ChatView } from "@town/ui/tui";
|
|
46
|
+
import { AcpClient } from "@town/ui";
|
|
47
|
+
|
|
48
|
+
const client = new AcpClient({ stdio: { agentPath: "./agent" } });
|
|
49
|
+
render(<ChatView client={client} />);
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### GUI (Web)
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import ReactDOM from "react-dom/client";
|
|
56
|
+
import { ChatView } from "@town/ui/gui";
|
|
57
|
+
import { AcpClient } from "@town/ui";
|
|
58
|
+
|
|
59
|
+
const client = new AcpClient({ http: { baseUrl: "http://localhost:8080" } });
|
|
60
|
+
ReactDOM.createRoot(root).render(<ChatView client={client} />);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Components
|
|
64
|
+
|
|
65
|
+
### Core Hooks
|
|
66
|
+
|
|
67
|
+
All hooks accept an `AcpClient | null` parameter.
|
|
68
|
+
|
|
69
|
+
#### `useChatSession(client)`
|
|
70
|
+
|
|
71
|
+
Manages connection and session lifecycle.
|
|
72
|
+
|
|
73
|
+
**Returns**:
|
|
74
|
+
|
|
75
|
+
- `connectionStatus` - Current connection state
|
|
76
|
+
- `sessionId` - Active session ID
|
|
77
|
+
- `connect()` - Connect to agent
|
|
78
|
+
- `startSession()` - Start new session
|
|
79
|
+
- `disconnect()` - Disconnect from agent
|
|
80
|
+
|
|
81
|
+
#### `useChatMessages(client)`
|
|
82
|
+
|
|
83
|
+
Manages message sending and receiving.
|
|
84
|
+
|
|
85
|
+
**Returns**:
|
|
86
|
+
|
|
87
|
+
- `messages` - Array of display messages
|
|
88
|
+
- `isStreaming` - Whether currently streaming
|
|
89
|
+
- `sendMessage(content)` - Send a message
|
|
90
|
+
|
|
91
|
+
#### `useChatInput(client)`
|
|
92
|
+
|
|
93
|
+
Manages input state and submission.
|
|
94
|
+
|
|
95
|
+
**Returns**:
|
|
96
|
+
|
|
97
|
+
- `value` - Current input value
|
|
98
|
+
- `isSubmitting` - Whether submitting
|
|
99
|
+
- `attachedFiles` - File attachments
|
|
100
|
+
- `onChange(value)` - Update input
|
|
101
|
+
- `onSubmit()` - Submit message
|
|
102
|
+
- `onAttachFile(file)` - Attach file
|
|
103
|
+
- `onRemoveFile(index)` - Remove file
|
|
104
|
+
|
|
105
|
+
### TUI Components
|
|
106
|
+
|
|
107
|
+
Built with Ink for terminal UIs.
|
|
108
|
+
|
|
109
|
+
#### `<ChatView client={client} />`
|
|
110
|
+
|
|
111
|
+
Complete chat interface.
|
|
112
|
+
|
|
113
|
+
#### `<StatusBar connectionStatus sessionId isStreaming />`
|
|
114
|
+
|
|
115
|
+
Status indicator bar.
|
|
116
|
+
|
|
117
|
+
#### `<MessageList messages />`
|
|
118
|
+
|
|
119
|
+
Scrollable message list.
|
|
120
|
+
|
|
121
|
+
#### `<InputBox value isSubmitting attachedFiles onChange onSubmit onRemoveFile />`
|
|
122
|
+
|
|
123
|
+
Input field with file attachments.
|
|
124
|
+
|
|
125
|
+
### GUI Components
|
|
126
|
+
|
|
127
|
+
Built with React + Tailwind for web UIs.
|
|
128
|
+
|
|
129
|
+
Same props as TUI components, but with web-friendly styling!
|
|
130
|
+
|
|
131
|
+
## Key Benefits
|
|
132
|
+
|
|
133
|
+
1. **Shared Logic**: TUI and GUI use identical hooks
|
|
134
|
+
1. **Composable**: Build custom UIs from primitives
|
|
135
|
+
1. **Type-Safe**: Full TypeScript support
|
|
136
|
+
1. **State Management**: Zustand for global state
|
|
137
|
+
1. **Validation**: Zod schemas for all data
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# Install dependencies
|
|
143
|
+
bun install
|
|
144
|
+
|
|
145
|
+
# Build
|
|
146
|
+
bun run build
|
|
147
|
+
|
|
148
|
+
# Test
|
|
149
|
+
bun test
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Example: Custom Component
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { useChatMessages, useChatInput } from "@town/ui/core";
|
|
156
|
+
|
|
157
|
+
function CustomChat({ client }) {
|
|
158
|
+
const { messages, sendMessage } = useChatMessages(client);
|
|
159
|
+
const { value, onChange, onSubmit } = useChatInput(client);
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
<div>
|
|
163
|
+
<div>
|
|
164
|
+
{messages.map(msg => (
|
|
165
|
+
<div key={msg.id}>{msg.content}</div>
|
|
166
|
+
))}
|
|
167
|
+
</div>
|
|
168
|
+
<input value={value} onChange={e => onChange(e.target.value)} />
|
|
169
|
+
<button onClick={onSubmit}>Send</button>
|
|
170
|
+
</div>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The headless core makes it easy to build any UI!
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/core/hooks/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { AcpClient } from "../../sdk/client/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Hook for managing chat input
|
|
4
|
+
*/
|
|
5
|
+
export declare function useChatInput(client: AcpClient | null): {
|
|
6
|
+
value: string;
|
|
7
|
+
isSubmitting: boolean;
|
|
8
|
+
attachedFiles: {
|
|
9
|
+
name: string;
|
|
10
|
+
path: string;
|
|
11
|
+
size: number;
|
|
12
|
+
mimeType: string;
|
|
13
|
+
}[];
|
|
14
|
+
onChange: (value: string) => void;
|
|
15
|
+
onSubmit: () => Promise<void>;
|
|
16
|
+
onAttachFile: (file: {
|
|
17
|
+
name: string;
|
|
18
|
+
path: string;
|
|
19
|
+
size: number;
|
|
20
|
+
mimeType: string;
|
|
21
|
+
}) => void;
|
|
22
|
+
onRemoveFile: (index: number) => void;
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-chat-input.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/use-chat-input.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;;;;;;;;;sBAezC,MAAM;;yBAkCP;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;0BAU7D,MAAM;EAejB"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { useChatStore } from "../store/chat-store.js";
|
|
3
|
+
import { useChatMessages } from "./use-chat-messages.js";
|
|
4
|
+
/**
|
|
5
|
+
* Hook for managing chat input
|
|
6
|
+
*/
|
|
7
|
+
export function useChatInput(client) {
|
|
8
|
+
const input = useChatStore((state) => state.input);
|
|
9
|
+
const setInputValue = useChatStore((state) => state.setInputValue);
|
|
10
|
+
const setInputSubmitting = useChatStore((state) => state.setInputSubmitting);
|
|
11
|
+
const addFileAttachment = useChatStore((state) => state.addFileAttachment);
|
|
12
|
+
const removeFileAttachment = useChatStore((state) => state.removeFileAttachment);
|
|
13
|
+
const { sendMessage } = useChatMessages(client);
|
|
14
|
+
/**
|
|
15
|
+
* Handle input value change
|
|
16
|
+
*/
|
|
17
|
+
const handleInputChange = useCallback((value) => {
|
|
18
|
+
setInputValue(value);
|
|
19
|
+
}, [setInputValue]);
|
|
20
|
+
/**
|
|
21
|
+
* Handle input submission
|
|
22
|
+
*/
|
|
23
|
+
const handleSubmit = useCallback(async () => {
|
|
24
|
+
if (!input.value.trim() || input.isSubmitting) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const message = input.value;
|
|
28
|
+
// Clear input immediately for better UX
|
|
29
|
+
setInputValue("");
|
|
30
|
+
setInputSubmitting(true);
|
|
31
|
+
try {
|
|
32
|
+
await sendMessage(message);
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
// Error is handled in useChatMessages
|
|
36
|
+
console.error("Failed to send message:", error);
|
|
37
|
+
}
|
|
38
|
+
finally {
|
|
39
|
+
setInputSubmitting(false);
|
|
40
|
+
}
|
|
41
|
+
}, [input, setInputValue, setInputSubmitting, sendMessage]);
|
|
42
|
+
/**
|
|
43
|
+
* Handle file attachment
|
|
44
|
+
*/
|
|
45
|
+
const handleAttachFile = useCallback((file) => {
|
|
46
|
+
addFileAttachment(file);
|
|
47
|
+
}, [addFileAttachment]);
|
|
48
|
+
/**
|
|
49
|
+
* Handle file removal
|
|
50
|
+
*/
|
|
51
|
+
const handleRemoveFile = useCallback((index) => {
|
|
52
|
+
removeFileAttachment(index);
|
|
53
|
+
}, [removeFileAttachment]);
|
|
54
|
+
return {
|
|
55
|
+
value: input.value,
|
|
56
|
+
isSubmitting: input.isSubmitting,
|
|
57
|
+
attachedFiles: input.attachedFiles,
|
|
58
|
+
onChange: handleInputChange,
|
|
59
|
+
onSubmit: handleSubmit,
|
|
60
|
+
onAttachFile: handleAttachFile,
|
|
61
|
+
onRemoveFile: handleRemoveFile,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-chat-input.js","sourceRoot":"","sources":["../../../src/core/hooks/use-chat-input.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEpC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,MAAwB;IACnD,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACnD,MAAM,aAAa,GAAG,YAAY,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACnE,MAAM,kBAAkB,GAAG,YAAY,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAC7E,MAAM,iBAAiB,GAAG,YAAY,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;IAC3E,MAAM,oBAAoB,GAAG,YAAY,CACvC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,oBAAoB,CACtC,CAAC;IAEF,MAAM,EAAE,WAAW,EAAE,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAEhD;;OAEG;IACH,MAAM,iBAAiB,GAAG,WAAW,CACnC,CAAC,KAAa,EAAE,EAAE;QAChB,aAAa,CAAC,KAAK,CAAC,CAAC;IACvB,CAAC,EACD,CAAC,aAAa,CAAC,CAChB,CAAC;IAEF;;OAEG;IACH,MAAM,YAAY,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC1C,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;YAC9C,OAAO;QACT,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC;QAE5B,wCAAwC;QACxC,aAAa,CAAC,EAAE,CAAC,CAAC;QAClB,kBAAkB,CAAC,IAAI,CAAC,CAAC;QAEzB,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,sCAAsC;YACtC,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAClD,CAAC;gBAAS,CAAC;YACT,kBAAkB,CAAC,KAAK,CAAC,CAAC;QAC5B,CAAC;IACH,CAAC,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,kBAAkB,EAAE,WAAW,CAAC,CAAC,CAAC;IAE5D;;OAEG;IACH,MAAM,gBAAgB,GAAG,WAAW,CAClC,CAAC,IAAoE,EAAE,EAAE;QACvE,iBAAiB,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC,EACD,CAAC,iBAAiB,CAAC,CACpB,CAAC;IAEF;;OAEG;IACH,MAAM,gBAAgB,GAAG,WAAW,CAClC,CAAC,KAAa,EAAE,EAAE;QAChB,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC,EACD,CAAC,oBAAoB,CAAC,CACvB,CAAC;IAEF,OAAO;QACL,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,aAAa,EAAE,KAAK,CAAC,aAAa;QAClC,QAAQ,EAAE,iBAAiB;QAC3B,QAAQ,EAAE,YAAY;QACtB,YAAY,EAAE,gBAAgB;QAC9B,YAAY,EAAE,gBAAgB;KAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AcpClient } from "../../sdk/client/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Hook for managing chat messages
|
|
4
|
+
*/
|
|
5
|
+
export declare function useChatMessages(client: AcpClient | null): {
|
|
6
|
+
messages: {
|
|
7
|
+
id: string;
|
|
8
|
+
role: "user" | "assistant" | "system";
|
|
9
|
+
content: string;
|
|
10
|
+
timestamp: string;
|
|
11
|
+
isStreaming: boolean;
|
|
12
|
+
streamingStartTime?: number | undefined;
|
|
13
|
+
metadata?: Record<string, unknown> | undefined;
|
|
14
|
+
}[];
|
|
15
|
+
isStreaming: boolean;
|
|
16
|
+
sendMessage: (content: string) => Promise<void>;
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-chat-messages.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/use-chat-messages.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAI3D;;GAEG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;;;;;;;;;;;2BAgBpC,MAAM;EAsHzB"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { useCallback } from "react";
|
|
2
|
+
import { useChatStore } from "../store/chat-store.js";
|
|
3
|
+
/**
|
|
4
|
+
* Hook for managing chat messages
|
|
5
|
+
*/
|
|
6
|
+
export function useChatMessages(client) {
|
|
7
|
+
const messages = useChatStore((state) => state.messages);
|
|
8
|
+
const isStreaming = useChatStore((state) => state.isStreaming);
|
|
9
|
+
const sessionId = useChatStore((state) => state.sessionId);
|
|
10
|
+
const setIsStreaming = useChatStore((state) => state.setIsStreaming);
|
|
11
|
+
const setStreamingStartTime = useChatStore((state) => state.setStreamingStartTime);
|
|
12
|
+
const addMessage = useChatStore((state) => state.addMessage);
|
|
13
|
+
const updateMessage = useChatStore((state) => state.updateMessage);
|
|
14
|
+
const setError = useChatStore((state) => state.setError);
|
|
15
|
+
/**
|
|
16
|
+
* Send a message to the agent
|
|
17
|
+
*/
|
|
18
|
+
const sendMessage = useCallback(async (content) => {
|
|
19
|
+
if (!client) {
|
|
20
|
+
console.error("❌ No client available");
|
|
21
|
+
setError("No client available");
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (!sessionId) {
|
|
25
|
+
console.error("❌ No active session");
|
|
26
|
+
setError("No active session");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
// Start streaming and track time immediately
|
|
31
|
+
const startTime = Date.now();
|
|
32
|
+
setIsStreaming(true);
|
|
33
|
+
setStreamingStartTime(startTime);
|
|
34
|
+
// Add user message to UI
|
|
35
|
+
const userMessage = {
|
|
36
|
+
id: `msg_${Date.now()}_user`,
|
|
37
|
+
role: "user",
|
|
38
|
+
content,
|
|
39
|
+
timestamp: new Date().toISOString(),
|
|
40
|
+
isStreaming: false,
|
|
41
|
+
};
|
|
42
|
+
addMessage(userMessage);
|
|
43
|
+
// Create placeholder for assistant message BEFORE sending
|
|
44
|
+
const assistantMessageId = `msg_${Date.now()}_assistant`;
|
|
45
|
+
const assistantMessage = {
|
|
46
|
+
id: assistantMessageId,
|
|
47
|
+
role: "assistant",
|
|
48
|
+
content: "",
|
|
49
|
+
timestamp: new Date().toISOString(),
|
|
50
|
+
isStreaming: true,
|
|
51
|
+
streamingStartTime: startTime, // Use the same start time from when user sent message
|
|
52
|
+
};
|
|
53
|
+
addMessage(assistantMessage);
|
|
54
|
+
// Build full conversation history (excluding system messages)
|
|
55
|
+
const conversationHistory = messages
|
|
56
|
+
.filter((msg) => msg.role !== "system")
|
|
57
|
+
.map((msg) => `${msg.role === "user" ? "Human" : "Assistant"}: ${msg.content}`)
|
|
58
|
+
.join("\n\n");
|
|
59
|
+
// Combine history with new message
|
|
60
|
+
const fullPrompt = conversationHistory
|
|
61
|
+
? `${conversationHistory}\n\nHuman: ${content}`
|
|
62
|
+
: content;
|
|
63
|
+
// Start receiving chunks (async iterator)
|
|
64
|
+
const messageStream = client.receiveMessages();
|
|
65
|
+
// Send full conversation without awaiting (fire and forget)
|
|
66
|
+
// This allows chunks to start arriving while we're listening
|
|
67
|
+
client.sendMessage(fullPrompt, sessionId).catch((error) => {
|
|
68
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
69
|
+
setError(message);
|
|
70
|
+
setIsStreaming(false);
|
|
71
|
+
setStreamingStartTime(null);
|
|
72
|
+
});
|
|
73
|
+
// Listen for streaming chunks
|
|
74
|
+
let accumulatedContent = "";
|
|
75
|
+
for await (const chunk of messageStream) {
|
|
76
|
+
if (chunk.isComplete) {
|
|
77
|
+
// Update final message
|
|
78
|
+
updateMessage(assistantMessageId, {
|
|
79
|
+
content: accumulatedContent,
|
|
80
|
+
isStreaming: false,
|
|
81
|
+
streamingStartTime: undefined, // Clear streaming start time
|
|
82
|
+
});
|
|
83
|
+
setIsStreaming(false);
|
|
84
|
+
setStreamingStartTime(null); // Clear global streaming start time
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
// Update streaming content
|
|
89
|
+
if (chunk.contentDelta.type === "text") {
|
|
90
|
+
accumulatedContent += chunk.contentDelta.text;
|
|
91
|
+
updateMessage(assistantMessageId, {
|
|
92
|
+
content: accumulatedContent,
|
|
93
|
+
});
|
|
94
|
+
// Small delay to allow Ink to render between chunks (~60fps)
|
|
95
|
+
await new Promise((resolve) => setTimeout(resolve, 16));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
102
|
+
setError(message);
|
|
103
|
+
setIsStreaming(false);
|
|
104
|
+
setStreamingStartTime(null); // Clear streaming start time on error
|
|
105
|
+
}
|
|
106
|
+
}, [
|
|
107
|
+
client,
|
|
108
|
+
sessionId,
|
|
109
|
+
messages,
|
|
110
|
+
addMessage,
|
|
111
|
+
updateMessage,
|
|
112
|
+
setIsStreaming,
|
|
113
|
+
setStreamingStartTime,
|
|
114
|
+
setError,
|
|
115
|
+
]);
|
|
116
|
+
return {
|
|
117
|
+
messages,
|
|
118
|
+
isStreaming,
|
|
119
|
+
sendMessage,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-chat-messages.js","sourceRoot":"","sources":["../../../src/core/hooks/use-chat-messages.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AcpClient } from "../../sdk/client/index.js";
|
|
2
|
+
/**
|
|
3
|
+
* Hook for managing chat session lifecycle
|
|
4
|
+
*/
|
|
5
|
+
export declare function useChatSession(client: AcpClient | null): {
|
|
6
|
+
connectionStatus: "error" | "connecting" | "connected" | "disconnected";
|
|
7
|
+
sessionId: string | null;
|
|
8
|
+
connect: () => Promise<void>;
|
|
9
|
+
startSession: () => Promise<void>;
|
|
10
|
+
disconnect: () => Promise<void>;
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-chat-session.d.ts","sourceRoot":"","sources":["../../../src/core/hooks/use-chat-session.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAG3D;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI;;;;;;EAuFtD"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { useCallback, useEffect } from "react";
|
|
2
|
+
import { useChatStore } from "../store/chat-store.js";
|
|
3
|
+
/**
|
|
4
|
+
* Hook for managing chat session lifecycle
|
|
5
|
+
*/
|
|
6
|
+
export function useChatSession(client) {
|
|
7
|
+
const connectionStatus = useChatStore((state) => state.connectionStatus);
|
|
8
|
+
const sessionId = useChatStore((state) => state.sessionId);
|
|
9
|
+
const setConnectionStatus = useChatStore((state) => state.setConnectionStatus);
|
|
10
|
+
const setSessionId = useChatStore((state) => state.setSessionId);
|
|
11
|
+
const setError = useChatStore((state) => state.setError);
|
|
12
|
+
const clearMessages = useChatStore((state) => state.clearMessages);
|
|
13
|
+
/**
|
|
14
|
+
* Connect to the agent
|
|
15
|
+
*/
|
|
16
|
+
const connect = useCallback(async () => {
|
|
17
|
+
if (!client) {
|
|
18
|
+
setError("No client available");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
try {
|
|
22
|
+
setConnectionStatus("connecting");
|
|
23
|
+
setError(null);
|
|
24
|
+
await client.connect();
|
|
25
|
+
setConnectionStatus("connected");
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
console.log(error);
|
|
29
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
30
|
+
setError(message);
|
|
31
|
+
setConnectionStatus("error");
|
|
32
|
+
}
|
|
33
|
+
}, [client, setConnectionStatus, setError]);
|
|
34
|
+
/**
|
|
35
|
+
* Start a new session
|
|
36
|
+
*/
|
|
37
|
+
const startSession = useCallback(async () => {
|
|
38
|
+
if (!client) {
|
|
39
|
+
setError("No client available");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
try {
|
|
43
|
+
const id = await client.startSession();
|
|
44
|
+
setSessionId(id);
|
|
45
|
+
clearMessages();
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
49
|
+
setError(message);
|
|
50
|
+
}
|
|
51
|
+
}, [client, setSessionId, setError, clearMessages]);
|
|
52
|
+
/**
|
|
53
|
+
* Disconnect from the agent
|
|
54
|
+
*/
|
|
55
|
+
const disconnect = useCallback(async () => {
|
|
56
|
+
if (!client)
|
|
57
|
+
return;
|
|
58
|
+
try {
|
|
59
|
+
await client.disconnect();
|
|
60
|
+
setConnectionStatus("disconnected");
|
|
61
|
+
setSessionId(null);
|
|
62
|
+
}
|
|
63
|
+
catch (error) {
|
|
64
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
65
|
+
setError(message);
|
|
66
|
+
}
|
|
67
|
+
}, [client, setConnectionStatus, setSessionId, setError]);
|
|
68
|
+
// Auto-connect on mount if client is available
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
if (client && connectionStatus === "disconnected") {
|
|
71
|
+
connect();
|
|
72
|
+
}
|
|
73
|
+
}, [client, connectionStatus, connect]);
|
|
74
|
+
// Auto-start session after connecting
|
|
75
|
+
useEffect(() => {
|
|
76
|
+
if (connectionStatus === "connected" && !sessionId) {
|
|
77
|
+
startSession();
|
|
78
|
+
}
|
|
79
|
+
}, [connectionStatus, sessionId, startSession]);
|
|
80
|
+
return {
|
|
81
|
+
connectionStatus,
|
|
82
|
+
sessionId,
|
|
83
|
+
connect,
|
|
84
|
+
startSession,
|
|
85
|
+
disconnect,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-chat-session.js","sourceRoot":"","sources":["../../../src/core/hooks/use-chat-session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom hook for responsive breakpoints with SSR-safe implementation
|
|
3
|
+
*
|
|
4
|
+
* @param query - Media query string (e.g., "(min-width: 768px)")
|
|
5
|
+
* @returns boolean indicating if the media query matches
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* const isMobile = useMediaQuery("(max-width: 640px)");
|
|
10
|
+
* const isDesktop = useMediaQuery("(min-width: 1024px)");
|
|
11
|
+
*
|
|
12
|
+
* return (
|
|
13
|
+
* <div>
|
|
14
|
+
* {isMobile && <MobileMenu />}
|
|
15
|
+
* {isDesktop && <DesktopSidebar />}
|
|
16
|
+
* </div>
|
|
17
|
+
* );
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare function useMediaQuery(query: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Common breakpoint presets for convenience
|
|
23
|
+
*/
|
|
24
|
+
export declare const breakpoints: {
|
|
25
|
+
readonly sm: "(min-width: 640px)";
|
|
26
|
+
readonly md: "(min-width: 768px)";
|
|
27
|
+
readonly lg: "(min-width: 1024px)";
|
|
28
|
+
readonly xl: "(min-width: 1280px)";
|
|
29
|
+
readonly "2xl": "(min-width: 1536px)";
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Convenience hooks for common breakpoints
|
|
33
|
+
*/
|
|
34
|
+
export declare function useIsSmallScreen(): boolean;
|
|
35
|
+
export declare function useIsMediumScreen(): boolean;
|
|
36
|
+
export declare function useIsLargeScreen(): boolean;
|
|
37
|
+
export declare function useIsDesktop(): boolean;
|
|
38
|
+
export declare function useIsMobile(): boolean;
|
|
39
|
+
export declare function useIsTablet(): boolean;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Custom hook for responsive breakpoints with SSR-safe implementation
|
|
4
|
+
*
|
|
5
|
+
* @param query - Media query string (e.g., "(min-width: 768px)")
|
|
6
|
+
* @returns boolean indicating if the media query matches
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* const isMobile = useMediaQuery("(max-width: 640px)");
|
|
11
|
+
* const isDesktop = useMediaQuery("(min-width: 1024px)");
|
|
12
|
+
*
|
|
13
|
+
* return (
|
|
14
|
+
* <div>
|
|
15
|
+
* {isMobile && <MobileMenu />}
|
|
16
|
+
* {isDesktop && <DesktopSidebar />}
|
|
17
|
+
* </div>
|
|
18
|
+
* );
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function useMediaQuery(query) {
|
|
22
|
+
const [matches, setMatches] = useState(() => {
|
|
23
|
+
// SSR-safe: return false on server, check on client
|
|
24
|
+
if (typeof window === "undefined") {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
return window.matchMedia(query).matches;
|
|
28
|
+
});
|
|
29
|
+
useEffect(() => {
|
|
30
|
+
// SSR guard
|
|
31
|
+
if (typeof window === "undefined") {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const mediaQueryList = window.matchMedia(query);
|
|
35
|
+
// Update state if query evaluation changes
|
|
36
|
+
const handleChange = (event) => {
|
|
37
|
+
setMatches(event.matches);
|
|
38
|
+
};
|
|
39
|
+
// Set initial value
|
|
40
|
+
setMatches(mediaQueryList.matches);
|
|
41
|
+
// Listen for changes
|
|
42
|
+
mediaQueryList.addEventListener("change", handleChange);
|
|
43
|
+
// Cleanup
|
|
44
|
+
return () => {
|
|
45
|
+
mediaQueryList.removeEventListener("change", handleChange);
|
|
46
|
+
};
|
|
47
|
+
}, [query]);
|
|
48
|
+
return matches;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Common breakpoint presets for convenience
|
|
52
|
+
*/
|
|
53
|
+
export const breakpoints = {
|
|
54
|
+
sm: "(min-width: 640px)",
|
|
55
|
+
md: "(min-width: 768px)",
|
|
56
|
+
lg: "(min-width: 1024px)",
|
|
57
|
+
xl: "(min-width: 1280px)",
|
|
58
|
+
"2xl": "(min-width: 1536px)",
|
|
59
|
+
};
|
|
60
|
+
/**
|
|
61
|
+
* Convenience hooks for common breakpoints
|
|
62
|
+
*/
|
|
63
|
+
export function useIsSmallScreen() {
|
|
64
|
+
return useMediaQuery("(max-width: 639px)");
|
|
65
|
+
}
|
|
66
|
+
export function useIsMediumScreen() {
|
|
67
|
+
return useMediaQuery(breakpoints.md);
|
|
68
|
+
}
|
|
69
|
+
export function useIsLargeScreen() {
|
|
70
|
+
return useMediaQuery(breakpoints.lg);
|
|
71
|
+
}
|
|
72
|
+
export function useIsDesktop() {
|
|
73
|
+
return useMediaQuery(breakpoints.lg);
|
|
74
|
+
}
|
|
75
|
+
export function useIsMobile() {
|
|
76
|
+
return useMediaQuery("(max-width: 767px)");
|
|
77
|
+
}
|
|
78
|
+
export function useIsTablet() {
|
|
79
|
+
return useMediaQuery("(min-width: 768px) and (max-width: 1023px)");
|
|
80
|
+
}
|