@hsafa/ui-sdk 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/DOCUMENTATION.md +174 -0
- package/README.md +347 -0
- package/dist/index.cjs +30 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +188 -0
- package/dist/index.d.ts +188 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/docs/api/README.md +351 -0
- package/docs/api/functions/HsafaChat.md +21 -0
- package/docs/api/functions/HsafaProvider.md +32 -0
- package/docs/api/functions/useAutoScroll.md +21 -0
- package/docs/api/functions/useHsafa.md +39 -0
- package/docs/api/functions/useHsafaAction.md +28 -0
- package/docs/api/functions/useHsafaComponent.md +28 -0
- package/docs/api/functions/useToggle.md +27 -0
- package/docs/api/globals.md +24 -0
- package/docs/api/interfaces/ButtonProps.md +59 -0
- package/docs/api/interfaces/UseToggleReturn.md +81 -0
- package/docs/api/variables/Button.md +29 -0
- package/examples/ecommerce-agent.tsx +229 -0
- package/examples/getting-started.tsx +96 -0
- package/package.json +109 -0
package/DOCUMENTATION.md
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# @hsafa/ui-sdk Documentation
|
|
2
|
+
|
|
3
|
+
React SDK for integrating AI agents built with HSAFA AI Agent Studio into your applications.
|
|
4
|
+
|
|
5
|
+
## 📚 Documentation Structure
|
|
6
|
+
|
|
7
|
+
### 1. **Getting Started**
|
|
8
|
+
- [Installation & Setup](README.md#installation)
|
|
9
|
+
- [Basic AI Agent Chat](README.md#basic-ai-agent-chat)
|
|
10
|
+
- [Getting Started Example](examples/getting-started.tsx)
|
|
11
|
+
|
|
12
|
+
### 2. **Core Components**
|
|
13
|
+
- [HsafaChat](README.md#hsafachat) - AI agent chat interface
|
|
14
|
+
- [HsafaProvider](README.md#hsafaprovider) - SDK context provider
|
|
15
|
+
|
|
16
|
+
### 3. **Agent Integration**
|
|
17
|
+
- [useHsafaAction](README.md#usehsafaaction) - Register functions for agents
|
|
18
|
+
- [useHsafaComponent](README.md#usehsafacomponent) - Register UI components
|
|
19
|
+
- [useHsafa](README.md#usehsafa) - Advanced context access
|
|
20
|
+
|
|
21
|
+
### 4. **Examples**
|
|
22
|
+
- [Getting Started](examples/getting-started.tsx) - Simple setup with basic actions
|
|
23
|
+
- [E-commerce Agent](examples/ecommerce-agent.tsx) - Product search & ordering
|
|
24
|
+
|
|
25
|
+
### 5. **API Reference**
|
|
26
|
+
- [Complete API Documentation](docs/api/) - Generated from TypeScript definitions
|
|
27
|
+
- [Interactive Storybook](http://localhost:6006) - Component playground
|
|
28
|
+
|
|
29
|
+
## 🚀 Quick Navigation
|
|
30
|
+
|
|
31
|
+
### For Beginners
|
|
32
|
+
1. Start with the [Installation](README.md#installation)
|
|
33
|
+
2. Try the [Basic Usage Example](examples/basic-usage.tsx)
|
|
34
|
+
3. Explore the [Interactive Storybook](#interactive-documentation)
|
|
35
|
+
|
|
36
|
+
### For Advanced Users
|
|
37
|
+
1. Check out [Chat Integration](examples/chat-integration.tsx)
|
|
38
|
+
2. Review [Custom Actions](README.md#custom-actions--components)
|
|
39
|
+
3. Browse the [API Reference](docs/api/)
|
|
40
|
+
|
|
41
|
+
## 📖 Interactive Documentation
|
|
42
|
+
|
|
43
|
+
### Storybook
|
|
44
|
+
Run the interactive component documentation:
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
cd sdk
|
|
48
|
+
pnpm storybook
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Then visit [http://localhost:6006](http://localhost:6006) to:
|
|
52
|
+
- 🎮 **Play with components** interactively
|
|
53
|
+
- 📝 **View live documentation** with examples
|
|
54
|
+
- 🎨 **Test different props** and configurations
|
|
55
|
+
- 📱 **See responsive behavior**
|
|
56
|
+
|
|
57
|
+
### API Documentation
|
|
58
|
+
Generate comprehensive API documentation:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
cd sdk
|
|
62
|
+
pnpm docs:api
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
This creates detailed API docs in `docs/api/` with:
|
|
66
|
+
- 📋 **Complete type definitions**
|
|
67
|
+
- 🔍 **Function signatures**
|
|
68
|
+
- 💡 **Usage examples**
|
|
69
|
+
- 🏷️ **Parameter descriptions**
|
|
70
|
+
|
|
71
|
+
## 🎨 Theming & Styling
|
|
72
|
+
|
|
73
|
+
### CSS Modules
|
|
74
|
+
The SDK uses CSS Modules for styling. Each component has its own stylesheet:
|
|
75
|
+
|
|
76
|
+
```
|
|
77
|
+
src/components/
|
|
78
|
+
├── Button.tsx
|
|
79
|
+
├── Button.module.css
|
|
80
|
+
├── HsafaChat.tsx
|
|
81
|
+
└── HsafaChat.module.css
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### Customization
|
|
85
|
+
You can customize the appearance by:
|
|
86
|
+
|
|
87
|
+
1. **Using component props** (recommended):
|
|
88
|
+
```tsx
|
|
89
|
+
<HsafaChat
|
|
90
|
+
primaryColor="#3b82f6"
|
|
91
|
+
backgroundColor="#ffffff"
|
|
92
|
+
borderColor="#e5e7eb"
|
|
93
|
+
/>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
2. **CSS custom properties**:
|
|
97
|
+
```css
|
|
98
|
+
.my-chat {
|
|
99
|
+
--hsafa-primary-color: #3b82f6;
|
|
100
|
+
--hsafa-background-color: #ffffff;
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
3. **CSS Module overrides**:
|
|
105
|
+
```tsx
|
|
106
|
+
import styles from './MyCustomStyles.module.css';
|
|
107
|
+
|
|
108
|
+
<Button className={styles.customButton} />
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## 🔧 Development Workflow
|
|
112
|
+
|
|
113
|
+
### Building Documentation
|
|
114
|
+
```bash
|
|
115
|
+
# Build all documentation
|
|
116
|
+
pnpm docs:build
|
|
117
|
+
|
|
118
|
+
# Development mode with hot reload
|
|
119
|
+
pnpm docs:dev
|
|
120
|
+
|
|
121
|
+
# Build API docs only
|
|
122
|
+
pnpm docs:api
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Testing
|
|
126
|
+
```bash
|
|
127
|
+
# Run all tests
|
|
128
|
+
pnpm test
|
|
129
|
+
|
|
130
|
+
# Run tests with UI
|
|
131
|
+
pnpm test:ui
|
|
132
|
+
|
|
133
|
+
# Type checking
|
|
134
|
+
pnpm type-check
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 📁 Project Structure
|
|
138
|
+
|
|
139
|
+
```
|
|
140
|
+
sdk/
|
|
141
|
+
├── src/
|
|
142
|
+
│ ├── components/ # React components
|
|
143
|
+
│ ├── hooks/ # Custom hooks
|
|
144
|
+
│ ├── providers/ # Context providers
|
|
145
|
+
│ └── index.ts # Main exports
|
|
146
|
+
├── examples/ # Usage examples
|
|
147
|
+
├── docs/ # Generated documentation
|
|
148
|
+
├── .storybook/ # Storybook configuration
|
|
149
|
+
└── README.md # Main documentation
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## 🤝 Contributing
|
|
153
|
+
|
|
154
|
+
We welcome contributions! Please see our [Contributing Guide](README.md#contributing) for details.
|
|
155
|
+
|
|
156
|
+
### Documentation Contributions
|
|
157
|
+
- 📝 Improve existing documentation
|
|
158
|
+
- 🌟 Add new examples
|
|
159
|
+
- 🐛 Fix documentation bugs
|
|
160
|
+
- 💡 Suggest better explanations
|
|
161
|
+
|
|
162
|
+
## 📞 Support
|
|
163
|
+
|
|
164
|
+
- 📖 **Documentation**: You're reading it!
|
|
165
|
+
- 🐛 **Issues**: [GitHub Issues](https://github.com/husamabusafa/hsafa/issues)
|
|
166
|
+
- 💬 **Discussions**: [GitHub Discussions](https://github.com/husamabusafa/hsafa/discussions)
|
|
167
|
+
|
|
168
|
+
## 📄 License
|
|
169
|
+
|
|
170
|
+
MIT © [Husam Abu Safa](https://github.com/husamabusafa)
|
|
171
|
+
|
|
172
|
+
---
|
|
173
|
+
|
|
174
|
+
**Happy coding!** 🎉
|
package/README.md
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
# @hsafa/ui-sdk
|
|
2
|
+
|
|
3
|
+
React SDK for building AI agent interfaces with custom actions and interactive components.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🤖 **AI Agent Chat**: Ready-to-use chat interface for AI agents
|
|
8
|
+
- ⚡ **Custom Actions**: Register functions that AI agents can call
|
|
9
|
+
- 🎨 **Dynamic Components**: Create UI components that agents can render
|
|
10
|
+
- 🔧 **TypeScript**: Full TypeScript support with comprehensive type definitions
|
|
11
|
+
- 📦 **Lightweight**: Tree-shakable with minimal dependencies
|
|
12
|
+
- 🎯 **Agent-Focused**: Built specifically for AI agent interactions
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @hsafa/ui-sdk
|
|
18
|
+
# or
|
|
19
|
+
yarn add @hsafa/ui-sdk
|
|
20
|
+
# or
|
|
21
|
+
pnpm add @hsafa/ui-sdk
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Quick Start
|
|
25
|
+
|
|
26
|
+
### Basic AI Agent Chat
|
|
27
|
+
|
|
28
|
+
```tsx
|
|
29
|
+
import { HsafaProvider, HsafaChat } from '@hsafa/ui-sdk';
|
|
30
|
+
|
|
31
|
+
function App() {
|
|
32
|
+
return (
|
|
33
|
+
<HsafaProvider baseUrl="https://your-hsafa-api.com">
|
|
34
|
+
<HsafaChat
|
|
35
|
+
agentId="your-agent-id"
|
|
36
|
+
width={400}
|
|
37
|
+
height={600}
|
|
38
|
+
placeholder="Ask your AI agent anything..."
|
|
39
|
+
/>
|
|
40
|
+
</HsafaProvider>
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Adding Custom Actions
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
import { HsafaProvider, HsafaChat, useHsafaAction } from '@hsafa/ui-sdk';
|
|
49
|
+
|
|
50
|
+
function MyApp() {
|
|
51
|
+
return (
|
|
52
|
+
<HsafaProvider baseUrl="https://your-hsafa-api.com">
|
|
53
|
+
<ActionProviders />
|
|
54
|
+
<HsafaChat agentId="your-agent-id" />
|
|
55
|
+
</HsafaProvider>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function ActionProviders() {
|
|
60
|
+
// Register an action that your AI agent can call
|
|
61
|
+
useHsafaAction('getUserData', async (params) => {
|
|
62
|
+
const { userId } = params;
|
|
63
|
+
// Fetch user data from your database
|
|
64
|
+
return {
|
|
65
|
+
name: 'John Doe',
|
|
66
|
+
email: 'john@example.com',
|
|
67
|
+
status: 'active'
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
useHsafaAction('createTask', async (params) => {
|
|
72
|
+
const { title, description } = params;
|
|
73
|
+
// Create task in your system
|
|
74
|
+
return { taskId: '123', status: 'created' };
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Custom UI Components
|
|
82
|
+
|
|
83
|
+
```tsx
|
|
84
|
+
import { useHsafaComponent } from '@hsafa/ui-sdk';
|
|
85
|
+
|
|
86
|
+
function ComponentProviders() {
|
|
87
|
+
// Register UI components that agents can render
|
|
88
|
+
useHsafaComponent('ProductCard', ({ product }) => (
|
|
89
|
+
<div className="border rounded-lg p-4">
|
|
90
|
+
<img src={product.image} alt={product.name} />
|
|
91
|
+
<h3>{product.name}</h3>
|
|
92
|
+
<p>${product.price}</p>
|
|
93
|
+
<button>Add to Cart</button>
|
|
94
|
+
</div>
|
|
95
|
+
));
|
|
96
|
+
|
|
97
|
+
useHsafaComponent('StatusChart', ({ data }) => (
|
|
98
|
+
<div className="chart-container">
|
|
99
|
+
{/* Your chart implementation */}
|
|
100
|
+
<h4>Status Overview</h4>
|
|
101
|
+
{data.map(item => (
|
|
102
|
+
<div key={item.id}>{item.label}: {item.value}</div>
|
|
103
|
+
))}
|
|
104
|
+
</div>
|
|
105
|
+
));
|
|
106
|
+
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Components
|
|
112
|
+
|
|
113
|
+
### Button
|
|
114
|
+
|
|
115
|
+
A versatile button component with multiple variants and states.
|
|
116
|
+
|
|
117
|
+
```tsx
|
|
118
|
+
import { Button } from '@hsafa/ui-sdk';
|
|
119
|
+
|
|
120
|
+
// Basic usage
|
|
121
|
+
<Button>Click me</Button>
|
|
122
|
+
|
|
123
|
+
// With variants
|
|
124
|
+
<Button variant="primary">Primary</Button>
|
|
125
|
+
<Button variant="secondary">Secondary</Button>
|
|
126
|
+
<Button variant="outline">Outline</Button>
|
|
127
|
+
<Button variant="ghost">Ghost</Button>
|
|
128
|
+
|
|
129
|
+
// With sizes
|
|
130
|
+
<Button size="sm">Small</Button>
|
|
131
|
+
<Button size="md">Medium</Button>
|
|
132
|
+
<Button size="lg">Large</Button>
|
|
133
|
+
|
|
134
|
+
// With loading state
|
|
135
|
+
<Button loading>Loading...</Button>
|
|
136
|
+
|
|
137
|
+
// Disabled
|
|
138
|
+
<Button disabled>Disabled</Button>
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
#### Props
|
|
142
|
+
|
|
143
|
+
| Prop | Type | Default | Description |
|
|
144
|
+
|------|------|---------|-------------|
|
|
145
|
+
| `variant` | `'primary' \| 'secondary' \| 'outline' \| 'ghost'` | `'primary'` | Button style variant |
|
|
146
|
+
| `size` | `'sm' \| 'md' \| 'lg'` | `'md'` | Button size |
|
|
147
|
+
| `loading` | `boolean` | `false` | Show loading spinner |
|
|
148
|
+
| `disabled` | `boolean` | `false` | Disable the button |
|
|
149
|
+
| `children` | `ReactNode` | - | Button content |
|
|
150
|
+
|
|
151
|
+
## Core Concepts
|
|
152
|
+
|
|
153
|
+
### AI Agent Integration
|
|
154
|
+
|
|
155
|
+
The SDK connects to your HSAFA AI Agent Studio, allowing your agents to:
|
|
156
|
+
- **Execute Actions**: Call functions in your application
|
|
157
|
+
- **Render Components**: Display custom UI elements in chat
|
|
158
|
+
- **Access Data**: Interact with your backend systems
|
|
159
|
+
|
|
160
|
+
### How It Works
|
|
161
|
+
|
|
162
|
+
1. **Agent Calls Action**: Your AI agent (built in HSAFA Studio) decides to call a registered action
|
|
163
|
+
2. **SDK Executes**: The action runs in your React app with the provided parameters
|
|
164
|
+
3. **Return Data**: Results are sent back to the agent to continue the conversation
|
|
165
|
+
4. **Render UI**: Agent can display custom components based on the data
|
|
166
|
+
|
|
167
|
+
## API Reference
|
|
168
|
+
|
|
169
|
+
### Components
|
|
170
|
+
|
|
171
|
+
#### HsafaChat
|
|
172
|
+
|
|
173
|
+
Chat interface for your AI agents built in HSAFA Studio.
|
|
174
|
+
|
|
175
|
+
```tsx
|
|
176
|
+
<HsafaChat
|
|
177
|
+
agentId="your-agent-id"
|
|
178
|
+
width={400}
|
|
179
|
+
height={600}
|
|
180
|
+
/>
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
| Prop | Type | Description |
|
|
184
|
+
|------|------|-------------|
|
|
185
|
+
| `agentId` | `string` | **Required** - ID of your agent from HSAFA Studio |
|
|
186
|
+
| `width` | `number` | Chat panel width (default: 400) |
|
|
187
|
+
| `height` | `number` | Chat panel height (default: 600) |
|
|
188
|
+
| `placeholder` | `string` | Input placeholder text |
|
|
189
|
+
| `primaryColor` | `string` | Primary theme color |
|
|
190
|
+
|
|
191
|
+
#### HsafaProvider
|
|
192
|
+
|
|
193
|
+
Provides context for agent communication.
|
|
194
|
+
|
|
195
|
+
```tsx
|
|
196
|
+
<HsafaProvider baseUrl="https://your-hsafa-api.com">
|
|
197
|
+
{/* Your app */}
|
|
198
|
+
</HsafaProvider>
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
| Prop | Type | Description |
|
|
202
|
+
|------|------|-------------|
|
|
203
|
+
| `baseUrl` | `string` | **Required** - Your HSAFA API endpoint |
|
|
204
|
+
| `children` | `ReactNode` | **Required** - App components |
|
|
205
|
+
|
|
206
|
+
### Hooks
|
|
207
|
+
|
|
208
|
+
#### useHsafaAction
|
|
209
|
+
|
|
210
|
+
Register functions that your AI agent can call. Perfect for connecting agents to your business logic.
|
|
211
|
+
|
|
212
|
+
```tsx
|
|
213
|
+
import { useHsafaAction } from '@hsafa/ui-sdk';
|
|
214
|
+
|
|
215
|
+
function MyApp() {
|
|
216
|
+
// Register actions your agent can use
|
|
217
|
+
useHsafaAction('getUserProfile', async ({ userId }) => {
|
|
218
|
+
const user = await fetchUserFromDatabase(userId);
|
|
219
|
+
return { name: user.name, email: user.email };
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
useHsafaAction('placeOrder', async ({ productId, quantity }) => {
|
|
223
|
+
const order = await createOrder(productId, quantity);
|
|
224
|
+
return { orderId: order.id, total: order.total };
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
return <YourApp />;
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
#### useHsafaComponent
|
|
232
|
+
|
|
233
|
+
Register UI components that agents can render in chat. Great for displaying data visually.
|
|
234
|
+
|
|
235
|
+
```tsx
|
|
236
|
+
import { useHsafaComponent } from '@hsafa/ui-sdk';
|
|
237
|
+
|
|
238
|
+
function MyApp() {
|
|
239
|
+
// Register components your agent can display
|
|
240
|
+
useHsafaComponent('OrderSummary', ({ order }) => (
|
|
241
|
+
<div className="order-card">
|
|
242
|
+
<h3>Order #{order.id}</h3>
|
|
243
|
+
<p>Total: ${order.total}</p>
|
|
244
|
+
<p>Status: {order.status}</p>
|
|
245
|
+
</div>
|
|
246
|
+
));
|
|
247
|
+
|
|
248
|
+
useHsafaComponent('ProductList', ({ products }) => (
|
|
249
|
+
<div className="grid">
|
|
250
|
+
{products.map(product => (
|
|
251
|
+
<div key={product.id} className="product-card">
|
|
252
|
+
<img src={product.image} alt={product.name} />
|
|
253
|
+
<h4>{product.name}</h4>
|
|
254
|
+
<p>${product.price}</p>
|
|
255
|
+
</div>
|
|
256
|
+
))}
|
|
257
|
+
</div>
|
|
258
|
+
));
|
|
259
|
+
|
|
260
|
+
return <YourApp />;
|
|
261
|
+
}
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
#### useHsafa
|
|
265
|
+
|
|
266
|
+
Advanced hook for manual registration and context access.
|
|
267
|
+
|
|
268
|
+
```tsx
|
|
269
|
+
import { useHsafa } from '@hsafa/ui-sdk';
|
|
270
|
+
|
|
271
|
+
function MyComponent() {
|
|
272
|
+
const { registerAction, registerComponent } = useHsafa();
|
|
273
|
+
|
|
274
|
+
// Manual registration with cleanup
|
|
275
|
+
useEffect(() => {
|
|
276
|
+
const cleanup1 = registerAction('customAction', handler);
|
|
277
|
+
const cleanup2 = registerComponent('CustomComponent', Component);
|
|
278
|
+
|
|
279
|
+
return () => {
|
|
280
|
+
cleanup1();
|
|
281
|
+
cleanup2();
|
|
282
|
+
};
|
|
283
|
+
}, []);
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
## Development
|
|
288
|
+
|
|
289
|
+
### Prerequisites
|
|
290
|
+
|
|
291
|
+
- Node.js 18+
|
|
292
|
+
- pnpm (recommended)
|
|
293
|
+
|
|
294
|
+
### Setup
|
|
295
|
+
|
|
296
|
+
```bash
|
|
297
|
+
# Clone the repository
|
|
298
|
+
git clone https://github.com/husamabusafa/hsafa.git
|
|
299
|
+
cd hsafa/sdk
|
|
300
|
+
|
|
301
|
+
# Install dependencies
|
|
302
|
+
pnpm install
|
|
303
|
+
|
|
304
|
+
# Start development
|
|
305
|
+
pnpm dev
|
|
306
|
+
|
|
307
|
+
# Run tests
|
|
308
|
+
pnpm test
|
|
309
|
+
|
|
310
|
+
# Start Storybook
|
|
311
|
+
pnpm storybook
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
### Scripts
|
|
315
|
+
|
|
316
|
+
- `pnpm build` - Build the library for production
|
|
317
|
+
- `pnpm dev` - Build in watch mode
|
|
318
|
+
- `pnpm test` - Run tests
|
|
319
|
+
- `pnpm test:ui` - Run tests with UI
|
|
320
|
+
- `pnpm storybook` - Start Storybook development server
|
|
321
|
+
- `pnpm build:storybook` - Build Storybook for production
|
|
322
|
+
- `pnpm lint` - Run ESLint
|
|
323
|
+
- `pnpm type-check` - Run TypeScript type checking
|
|
324
|
+
|
|
325
|
+
## Publishing
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
# Build the library
|
|
329
|
+
pnpm build
|
|
330
|
+
|
|
331
|
+
# Publish to npm
|
|
332
|
+
npm publish --access public
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
## License
|
|
336
|
+
|
|
337
|
+
MIT © [Husam Abu Safa](https://github.com/husamabusafa)
|
|
338
|
+
|
|
339
|
+
## Contributing
|
|
340
|
+
|
|
341
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
342
|
+
|
|
343
|
+
1. Fork the repository
|
|
344
|
+
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
345
|
+
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
|
|
346
|
+
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
347
|
+
5. Open a Pull Request
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
'use strict';var jsxRuntime=require('react/jsx-runtime'),react=require('react'),reactDom=require('react-dom'),iconsReact=require('@tabler/icons-react');var Z={};var er=({variant:a="primary",size:u="md",loading:p=false,disabled:m,children:A,className:T,...z})=>{let j=[Z.button,Z[a],Z[u],p&&Z.loading,T].filter(Boolean).join(" ");return jsxRuntime.jsxs("button",{className:j,disabled:m||p,...z,children:[p&&jsxRuntime.jsx("span",{className:Z.spinner}),jsxRuntime.jsx("span",{className:p?Z.hiddenText:void 0,children:A})]})};function nr(a=false){let[u,p]=react.useState(a),m=react.useCallback(()=>p(z=>!z),[]),A=react.useCallback(()=>p(true),[]),T=react.useCallback(()=>p(false),[]);return {on:u,toggle:m,setOn:p,setTrue:A,setFalse:T}}function lr(){let a=react.useRef(null);return react.useEffect(()=>{let u=a.current;if(!u)return;let p=new MutationObserver(()=>{u.scrollTop=u.scrollHeight;});return p.observe(u,{childList:true,subtree:true}),u.scrollTop=u.scrollHeight,()=>p.disconnect()},[]),a}var We=react.createContext(void 0);function Et({baseUrl:a,children:u}){let[p,m]=react.useState(new Map),[A,T]=react.useState(new Map),z=react.useCallback((M,v)=>(m($=>{let g=new Map($);return g.set(String(M),v),g}),()=>{m($=>{let g=new Map($),y=g.get(String(M));return (!v||y===v)&&g.delete(String(M)),g});}),[]),j=react.useCallback((M,v)=>{m($=>{let g=new Map($),y=g.get(String(M));return (!v||y===v)&&g.delete(String(M)),g});},[]),Y=react.useCallback((M,v)=>(T($=>{let g=new Map($);return g.set(String(M),v),g}),()=>{T($=>{let g=new Map($),y=g.get(String(M));return (!v||y===v)&&g.delete(String(M)),g});}),[]),te=react.useCallback((M,v)=>{T($=>{let g=new Map($),y=g.get(String(M));return (!v||y===v)&&g.delete(String(M)),g});},[]),ce=react.useMemo(()=>({baseUrl:a,actions:p,components:A,registerAction:z,unregisterAction:j,registerComponent:Y,unregisterComponent:te}),[a,p,A,z,j,Y,te]);return jsxRuntime.jsx(We.Provider,{value:ce,children:u})}function ee(){let a=react.useContext(We);return a||{baseUrl:void 0,actions:new Map,components:new Map,registerAction:()=>()=>{},unregisterAction:()=>{},registerComponent:()=>()=>{},unregisterComponent:()=>{}}}function mr(a,u){let{registerAction:p}=ee(),m=react.useRef(u);react.useEffect(()=>{m.current=u;},[u]),react.useEffect(()=>!a||typeof m.current!="function"?void 0:p(a,(T,z)=>m.current(T,z)),[a,p]);}function Cr(a,u){let{registerComponent:p}=ee(),m=react.useRef(u);react.useEffect(()=>{m.current=u;},[u]),react.useEffect(()=>!a||typeof m.current!="function"?void 0:p(a,m.current),[a,p]);}function _t(a){let u=Date.now()-a,p=Math.max(1,Math.floor(u/1e3));if(p<60)return `${p}s`;let m=Math.floor(p/60);if(m<60)return `${m}m`;let A=Math.floor(m/60);if(A<24)return `${A}h`;let T=Math.floor(A/24);if(T<7)return `${T}d`;let z=Math.floor(T/7);if(z<4)return `${z}w`;let j=Math.floor(T/30);return j<12?`${j}mo`:`${Math.floor(j/12)}y`}function Qe(a,u){if(!a)return u;let p=a.endsWith("/")?a.slice(0,-1):a,m=u.startsWith("/")?u:`/${u}`;return `${p}${m}`}var Wt={dark:{primaryColor:"#4D78FF",backgroundColor:"#0B0B0F",borderColor:"#2A2C33",textColor:"#EDEEF0",accentColor:"#17181C",mutedTextColor:"#9AA0A6",inputBackground:"#17181C",cardBackground:"#121318",hoverBackground:"#1c1e25"},light:{primaryColor:"#2563EB",backgroundColor:"#FFFFFF",borderColor:"#E5E7EB",textColor:"#111827",accentColor:"#F9FAFB",mutedTextColor:"#6B7280",inputBackground:"#F9FAFB",cardBackground:"#F3F4F6",hoverBackground:"#F3F4F6"}};function Xt({agentId:a,children:u,theme:p="dark",primaryColor:m,backgroundColor:A,borderColor:T,textColor:z,accentColor:j,width:Y=420,maxWidth:te=420,height:ce="100vh",expandable:M=true,alwaysOpen:v=false,defaultOpen:$=true,dir:g="ltr",floatingButtonPosition:y=g==="rtl"?{bottom:16,left:16}:{bottom:16,right:16},enableBorderAnimation:Ae=true,enableContentPadding:Ze=true,borderRadius:Ce=16,enableContentBorder:$e=true,placeholder:et="Ask your question...",title:He="Agent",className:tt="",chatContainerClassName:rt=""}){let{baseUrl:Ie,actions:Ee,components:ot}=ee(),ue="hsafaChat",Re=`${ue}.chats`,he=e=>`${ue}.chat.${e}`,V=`${ue}.currentChatId`,Be=`${ue}.showChat`,[de,Fe]=react.useState(""),[_,pe]=react.useState(()=>{if(v)return true;try{let e=localStorage.getItem(Be);return e!==null?e==="true":$}catch{return $}});async function ze(e,n){if(!a)return;let r=n.trim();if(!r)return;U(null),re(true);let s=N.findIndex(d=>d.id===e);if(s===-1||N[s].role!=="user"){re(false);return}let c=N.slice(0,s),H={id:e,role:"user",text:r},O=ie(),C=[...c,H,{id:O,role:"assistant",items:[],reasoning:"",reasoningOpen:false}];w(C),ge(null);try{let d=[...c.map(E=>E.role==="user"?{role:"user",content:E.text}:{role:"assistant",items:Array.isArray(E.items)?E.items:[]}),{role:"user",content:r}],I={prompt:r,chatId:k??void 0,messages:d};w(E=>E.map(q=>q.id===O||q.id===e?{...q,requestParams:I}:q));let S=await fetch(Qe(Ie,`/api/run/${a}`),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(I)});if(!S.ok||!S.body){let E=await S.text().catch(()=>"");throw new Error(E||`Request failed with ${S.status}`)}let P=S.body.getReader(),Q=new TextDecoder,D="";for(;;){let{done:E,value:q}=await P.read();if(E)break;D+=Q.decode(q,{stream:!0});let f;for(;(f=D.indexOf(`
|
|
2
|
+
`))!==-1;){let R=D.slice(0,f).trim();if(D=D.slice(f+1),!!R)try{let i=JSON.parse(R);if(i?.type==="meta"){if(i.actionExecuteMap&&typeof i.actionExecuteMap=="object"&&(Te.current=i.actionExecuteMap),i.assistantMessageId&&(oe.current=String(i.assistantMessageId),me.current.clear(),ye.current.clear(),G.current.clear(),ne(new Map)),i.chatId&&!k){W(i.chatId),L.current=!0;let l=r,K=(X.current||l||"New chat").slice(0,80),b=Date.now();le({id:i.chatId,title:K,createdAt:b,updatedAt:b}),se({id:i.chatId,messages:C,agentId:a});try{localStorage.setItem(V,i.chatId);}catch{}}continue}if(i?.type==="reasoning"){let l=String(i.text??"");w(K=>K.map(b=>b.id===O&&b.role==="assistant"?{...b,reasoning:(b.reasoning??"")+l}:b));continue}if(i?.type==="partial"||i?.type==="final"){let l=i.value;l&&Array.isArray(l.items)&&(w(K=>K.map(b=>b.id===O&&b.role==="assistant"?{...b,items:l.items}:b)),Ue(l.items,i.type==="partial"?"partial":"final")),i?.type==="final"&&w(K=>K.map(b=>b.id===O&&b.role==="assistant"?{...b,reasoningOpen:!1}:b));continue}if(i?.type==="usage"){let l=i?.value?.reasoningTokens;typeof l=="number"&&w(K=>K.map(b=>b.id===O&&b.role==="assistant"?{...b,reasoningTokens:l}:b));continue}if(i?.type==="error"){U(String(i.error??"Unknown error"));continue}}catch{}}}}catch(d){U(String(d?.message??d));}finally{if(re(false),!k&&!L.current){let d=`local-${ie()}`;W(d),L.current=true;let I=(X.current||"New chat").slice(0,80),S=Date.now();le({id:d,title:I,createdAt:S,updatedAt:S}),se({id:d,messages:N,agentId:a});try{localStorage.setItem(V,d);}catch{}}}}let[N,w]=react.useState([]),[h,re]=react.useState(false),[Oe,U]=react.useState(null),ae=react.useRef(null),[k,W]=react.useState(null),[nt,ve]=react.useState(false),[De,at]=react.useState(""),[Gt,st]=react.useState(0),[lt,it]=react.useState(false),[ct,ge]=react.useState(null),[fe,Le]=react.useState(""),ut=react.useRef(null),Pe=react.useRef(null),dt=react.useRef(null),[ke,pt]=react.useState(true),we=react.useRef(false),L=react.useRef(false),X=react.useRef(null),gt=react.useRef(null),ft=react.useRef(null),Te=react.useRef({}),oe=react.useRef(void 0),me=react.useRef(new Set),ye=react.useRef(new Map),G=react.useRef(new Map),[mt,ne]=react.useState(new Map),je=react.useCallback((e,n)=>{let r=ye.current.get(e)||[],s=JSON.stringify(n);if(r.push(s),r.length>3&&r.shift(),ye.current.set(e,r),r.length>=2){let c=r.slice(-2);return c[0]===c[1]}return false},[]),Ue=react.useCallback((e,n)=>{!Array.isArray(e)||e.length===0||e.forEach((r,s)=>{if(!(!r||typeof r!="object")&&r.type==="action"){let c=String(r.name??"").trim();if(!c)return;let H=Ee.get(c);if(!H)return;let O=!!Te.current[c],C=`${oe.current||"assist"}:${c}:${s}`,d=`${c}:${s}`;try{if(n==="partial"&&O)ne(I=>new Map(I).set(d,"executing")),Promise.resolve(H(r.params,{name:c,trigger:n,index:s,assistantMessageId:oe.current,chatId:k||void 0})).catch(()=>{});else if(n==="partial"&&!O){let I=je(d,r.params),S=G.current.get(d);I&&S!=="executed"?(G.current.set(d,"executed"),ne(P=>new Map(P).set(d,"executed")),Promise.resolve(H(r.params,{name:c,trigger:"params_complete",index:s,assistantMessageId:oe.current,chatId:k||void 0})).catch(()=>{})):S||(G.current.set(d,"executing"),ne(P=>new Map(P).set(d,"executing")));}else n==="final"&&G.current.get(d)!=="executed"&&!me.current.has(C)&&(me.current.add(C),G.current.set(d,"executed"),ne(S=>new Map(S).set(d,"executed")),Promise.resolve(H(r.params,{name:c,trigger:O?"final":"params_complete",index:s,assistantMessageId:oe.current,chatId:k||void 0})).catch(()=>{}));}catch{}}});},[Ee,k,je]),Me=()=>{try{let e=localStorage.getItem(Re);return e?JSON.parse(e):[]}catch{return []}},Je=e=>{try{localStorage.setItem(Re,JSON.stringify(e));}catch{}},qe=e=>{try{let n=localStorage.getItem(he(e));return n?JSON.parse(n):null}catch{return null}},se=e=>{try{localStorage.setItem(he(e.id),JSON.stringify(e));}catch{}},le=e=>{let n=Me(),r=n.findIndex(s=>s.id===e.id);r>=0?n[r]=e:n.unshift(e),Je(n);},yt=e=>{let r=Me().filter(s=>s.id!==e);Je(r);},bt=e=>{try{localStorage.removeItem(he(e));}catch{}},xt=e=>{if(bt(e),yt(e),k===e){w([]),U(null),W(null),L.current=false,X.current=null;try{localStorage.removeItem(V);}catch{}}};react.useEffect(()=>{if(we.current){we.current=false;return}ke&&Pe.current?.scrollIntoView({behavior:"smooth",block:"end"});},[N,h,ke]),react.useEffect(()=>{try{let e=localStorage.getItem(V);if(e){let n=qe(e);n&&(W(n.id),L.current=!0,w(n.messages||[]));}}catch{}},[]),react.useEffect(()=>{try{localStorage.setItem(Be,String(_));}catch{}},[_]),react.useEffect(()=>{if(!k||!L.current)return;se({id:k,messages:N,agentId:a});let n=N.find(c=>c.role==="user"),r=(X.current||(n?.text??"New chat")).slice(0,80),s={id:k,title:r,createdAt:Date.now(),updatedAt:Date.now()};le(s);try{localStorage.setItem(V,k);}catch{}},[N,k,a]);let ie=()=>`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;function Ct(){ae.current&&(ae.current.abort(),ae.current=null),re(false),U("Request stopped by user");}async function Ke(){if(!a)return;let e=de.trim();if(!e)return;U(null),re(true),!k&&N.length===0&&(X.current=e);let n=ie(),r=ie(),s={id:n,role:"user",text:e},c={id:r,role:"assistant",items:[],reasoning:"",reasoningOpen:false},H=[...N,s,c],O=[...N.map(C=>C.role==="user"?{role:"user",content:C.text}:{role:"assistant",items:Array.isArray(C.items)?C.items:[]}),{role:"user",content:e}];w(H),Fe("");try{ae.current=new AbortController;let C={prompt:e,chatId:k??void 0,messages:O};w(Q=>Q.map(D=>D.id===r||D.id===n?{...D,requestParams:C}:D));let d=await fetch(Qe(Ie,`/api/run/${a}`),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(C),signal:ae.current.signal});if(!d.ok||!d.body){let Q=await d.text().catch(()=>"");throw new Error(Q||`Request failed with ${d.status}`)}let I=d.body.getReader(),S=new TextDecoder,P="";for(;;){let{done:Q,value:D}=await I.read();if(Q)break;P+=S.decode(D,{stream:!0});let E;for(;(E=P.indexOf(`
|
|
3
|
+
`))!==-1;){let q=P.slice(0,E).trim();if(P=P.slice(E+1),!!q)try{let f=JSON.parse(q);if(f?.type==="meta"){if(f.actionExecuteMap&&typeof f.actionExecuteMap=="object"&&(Te.current=f.actionExecuteMap),f.assistantMessageId&&(oe.current=String(f.assistantMessageId),me.current.clear(),ye.current.clear(),G.current.clear(),ne(new Map)),f.chatId&&!k){W(f.chatId),L.current=!0;let R=e,i=(X.current||R||"New chat").slice(0,80),l=Date.now();le({id:f.chatId,title:i,createdAt:l,updatedAt:l}),se({id:f.chatId,messages:H,agentId:a});try{localStorage.setItem(V,f.chatId);}catch{}}continue}if(f?.type==="reasoning"){let R=String(f.text??"");w(i=>i.map(l=>l.id===r&&l.role==="assistant"?{...l,reasoning:(l.reasoning??"")+R}:l));continue}if(f?.type==="partial"||f?.type==="final"){let R=f.value;R&&Array.isArray(R.items)&&(w(i=>i.map(l=>l.id===r&&l.role==="assistant"?{...l,items:R.items}:l)),Ue(R.items,f.type==="partial"?"partial":"final")),f?.type==="final"&&w(i=>i.map(l=>l.id===r&&l.role==="assistant"?{...l,reasoningOpen:!1}:l));continue}if(f?.type==="usage"){let R=f?.value?.reasoningTokens;typeof R=="number"&&w(i=>i.map(l=>l.id===r&&l.role==="assistant"?{...l,reasoningTokens:R}:l));continue}if(f?.type==="error"){U(String(f.error??"Unknown error"));continue}}catch{}}}}catch(C){U(String(C?.message??C));}finally{if(re(false),!k&&!L.current){let C=`local-${ie()}`;W(C),L.current=true;let d=(X.current||"New chat").slice(0,80),I=Date.now();le({id:C,title:d,createdAt:I,updatedAt:I}),se({id:C,messages:N,agentId:a});try{localStorage.setItem(V,C);}catch{}}}}function ht(e){return !Array.isArray(e)||e.length===0?null:jsxRuntime.jsx("div",{className:"space-y-3",children:e.map((n,r)=>{let s=`it-${r}`;if(typeof n=="string")return jsxRuntime.jsx("div",{className:"rounded-xl p-4 text-[14px] whitespace-pre-wrap",children:n},s);if(n&&typeof n=="object"){if(n.type==="action"){let c=`${String(n.name??"action")}:${r}`,H=mt.get(c);return jsxRuntime.jsx("div",{className:"space-y-2",children:jsxRuntime.jsx("div",{className:"px-2 py-1 text-xs",style:{color:t.mutedTextColor},children:H==="executing"?jsxRuntime.jsxs("span",{className:"flex items-center gap-2",children:[jsxRuntime.jsxs("svg",{className:"animate-spin h-3 w-3",xmlns:"http://www.w3.org/2000/svg",fill:"none",viewBox:"0 0 24 24",children:[jsxRuntime.jsx("circle",{className:"opacity-25",cx:"12",cy:"12",r:"10",stroke:"currentColor",strokeWidth:"4"}),jsxRuntime.jsx("path",{className:"opacity-75",fill:"currentColor",d:"m4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"})]}),String(n.name??"action")," is executing"]}):jsxRuntime.jsxs("span",{className:"flex items-center gap-1",children:[jsxRuntime.jsx("span",{className:"inline-block h-1.5 w-1.5 rounded-full",style:{backgroundColor:"#10b981"}}),String(n.name??"action")," has executed"]})})},s)}if(n.type==="ui-component"||n.type==="ui"){let c=String(n.name??n.component??"").trim(),H=c?ot.get(c):void 0;return H?jsxRuntime.jsx(H,{...n.props||{}}):jsxRuntime.jsxs("div",{className:"rounded-xl p-4",style:{backgroundColor:t.inputBackground,border:`1px solid ${t.borderColor}`},children:[jsxRuntime.jsxs("div",{className:"inline-flex items-center gap-2 text-xs mb-2",style:{color:t.mutedTextColor},children:[jsxRuntime.jsx("span",{className:"px-2 py-0.5 rounded",style:{backgroundColor:t.accentColor,border:`1px solid ${t.borderColor}`},children:"UI"}),jsxRuntime.jsx("span",{children:c||"component"}),jsxRuntime.jsx("span",{className:"ml-2 opacity-70",children:"(unregistered)"})]}),jsxRuntime.jsx("pre",{className:"text-xs overflow-auto",style:{color:t.mutedTextColor},children:JSON.stringify(n.props??{},null,2)})]},s)}return jsxRuntime.jsx("div",{className:"rounded-xl p-4 text-[14px]",style:{backgroundColor:t.cardBackground,border:`1px solid ${t.borderColor}`},children:jsxRuntime.jsx("pre",{className:"text-xs overflow-auto",style:{color:t.mutedTextColor},children:JSON.stringify(n,null,2)})},s)}return null})})}let J=Wt[p],t={primaryColor:m||J.primaryColor,backgroundColor:A||J.backgroundColor,borderColor:T||J.borderColor,textColor:z||J.textColor,accentColor:j||J.accentColor,mutedTextColor:J.mutedTextColor,inputBackground:J.inputBackground,cardBackground:J.cardBackground,hoverBackground:J.hoverBackground},vt={backgroundColor:t.backgroundColor,color:t.textColor,height:ce},kt={width:typeof Y=="number"?`${Y}px`:Y,maxWidth:typeof te=="number"?`${te}px`:te},wt={position:"fixed",bottom:typeof y.bottom=="number"?`${y.bottom}px`:y.bottom,right:y.right?typeof y.right=="number"?`${y.right}px`:y.right:void 0,top:y.top?typeof y.top=="number"?`${y.top}px`:y.top:void 0,left:y.left?typeof y.left=="number"?`${y.left}px`:y.left:void 0},Ne=typeof Ce=="number"?`${Ce}px`:Ce;return jsxRuntime.jsxs("div",{className:`flex h-full w-full ${tt}`,style:vt,dir:g,children:[jsxRuntime.jsx("div",{className:`flex items-stretch transition-all duration-1000 justify-stretch w-full h-full ${_&&Ze?"p-4":"p-0"}`,children:jsxRuntime.jsx("div",{className:"relative flex w-full h-full transition-all duration-1000 ease-out",style:{borderRadius:_&&$e?Ne:"0"},children:_&&$e?jsxRuntime.jsx("div",{className:`w-full h-full transition-all duration-600 ease-out ${h&&Ae?"tc-animated-border p-[1.5px]":"border p-0"}`,style:{borderRadius:Ne,borderColor:!h||!Ae?t.borderColor:"transparent"},children:jsxRuntime.jsx("div",{className:"w-full h-full",style:{borderRadius:Ne,backgroundColor:t.backgroundColor},children:u})}):jsxRuntime.jsx("div",{className:"w-full h-full",children:u})})}),jsxRuntime.jsxs("div",{className:`${rt} flex flex-col transition-all duration-300 ease-out overflow-hidden ${_||v?lt&&M?"fixed inset-0 z-50 w-full max-w-full px-6 py-6":"px-4 py-6 opacity-100 translate-x-0":`w-0 max-w-0 px-0 py-6 opacity-0 ${g==="rtl"?"translate-x-2":"-translate-x-2"} pointer-events-none`}`,style:{...kt,height:ce,backgroundColor:_||v?t.backgroundColor:"transparent"},children:[jsxRuntime.jsxs("div",{className:"mb-6 flex items-center justify-between",children:[jsxRuntime.jsx("div",{className:"min-w-0",children:jsxRuntime.jsx("h1",{title:He,className:"truncate text-[18px] font-semibold",style:{color:t.textColor},children:He})}),jsxRuntime.jsxs("div",{className:"flex items-center gap-2 relative",style:{color:t.mutedTextColor},children:[M&&jsxRuntime.jsx("button",{"aria-label":"Pop out",className:"rounded-lg p-2 transition-all duration-200 ease-out",style:{backgroundColor:"transparent",color:t.mutedTextColor},onMouseEnter:e=>{e.currentTarget.style.backgroundColor=t.hoverBackground,e.currentTarget.style.color=t.textColor;},onMouseLeave:e=>{e.currentTarget.style.backgroundColor="transparent",e.currentTarget.style.color=t.mutedTextColor;},onClick:()=>{pe(true),it(e=>!e);},children:jsxRuntime.jsx(iconsReact.IconArrowsMaximize,{size:20,stroke:2})}),jsxRuntime.jsx("button",{"aria-label":"New",className:"rounded-lg p-2 transition-all duration-200 ease-out",style:{backgroundColor:"transparent",color:t.mutedTextColor},onMouseEnter:e=>{e.currentTarget.style.backgroundColor=t.hoverBackground,e.currentTarget.style.color=t.textColor;},onMouseLeave:e=>{e.currentTarget.style.backgroundColor="transparent",e.currentTarget.style.color=t.mutedTextColor;},onClick:()=>{h||(w([]),U(null),W(null),L.current=false,X.current=null);},children:jsxRuntime.jsx(iconsReact.IconPlus,{size:20,stroke:2})}),jsxRuntime.jsx("button",{"aria-label":"History",className:"rounded-lg p-2 transition-all duration-200 ease-out",style:{backgroundColor:"transparent",color:t.mutedTextColor},onMouseEnter:e=>{e.currentTarget.style.backgroundColor=t.hoverBackground,e.currentTarget.style.color=t.textColor;},onMouseLeave:e=>{e.currentTarget.style.backgroundColor="transparent",e.currentTarget.style.color=t.mutedTextColor;},onClick:()=>ve(e=>!e),ref:gt,children:jsxRuntime.jsx(iconsReact.IconHistory,{size:20,stroke:2})}),nt&&reactDom.createPortal(jsxRuntime.jsxs(jsxRuntime.Fragment,{children:[jsxRuntime.jsx("div",{className:"fixed inset-0 z-[900] bg-black/40 backdrop-blur-sm",onClick:()=>ve(false)}),jsxRuntime.jsxs("div",{ref:ft,className:"fixed left-1/2 top-16 -translate-x-1/2 z-[1000] w-[680px] max-w-[94vw] overflow-hidden rounded-2xl border border-[#2A2C33] bg-[#0F1116]/95 shadow-2xl ring-1 ring-black/10",children:[jsxRuntime.jsx("div",{className:"flex items-center gap-3 border-b border-[#2A2C33] px-4 py-3",children:jsxRuntime.jsx("div",{className:"flex-1",children:jsxRuntime.jsx("input",{autoFocus:true,value:De,onChange:e=>at(e.target.value),placeholder:"Search",className:"w-full rounded-lg bg-[#0B0B0F] px-3 py-2 text-sm text-[#EDEEF0] placeholder:text-[#9AA0A6] outline-none border border-[#2A2C33] focus:border-[#3a3d46]"})})}),jsxRuntime.jsx("div",{className:"max-h-[60vh] overflow-y-auto",children:(()=>{let e=De.toLowerCase().trim(),n=Me();return e&&(n=n.filter(r=>(r.title||"").toLowerCase().includes(e))),!n||n.length===0?jsxRuntime.jsx("div",{className:"p-6 text-[#9AA0A6]",children:"No chats found."}):jsxRuntime.jsx("ul",{className:"divide-y divide-[#2A2C33]",children:n.map(r=>jsxRuntime.jsx("li",{children:jsxRuntime.jsxs("div",{className:`flex w-full items-center justify-between gap-3 p-3 ${r.id===k?"bg-[#121318]":""}`,children:[jsxRuntime.jsx("button",{className:"flex-1 text-left transition-colors hover:bg-[#17181C] rounded-lg px-2 py-2",onClick:()=>{let s=qe(r.id);if(s){W(r.id),L.current=true,w(s.messages||[]);try{localStorage.setItem(V,r.id);}catch{}ve(false),pe(true);}},children:jsxRuntime.jsxs("div",{className:"flex items-center justify-between gap-3",children:[jsxRuntime.jsx("div",{className:"min-w-0",children:jsxRuntime.jsx("div",{className:"truncate text-[14px] text-[#EDEEF0]",children:r.title||"Untitled chat"})}),jsxRuntime.jsx("div",{className:"shrink-0 text-[12px] text-[#9AA0A6]",children:_t(r.updatedAt)})]})}),jsxRuntime.jsx("button",{className:"shrink-0 rounded-md p-2 text-[#9AA0A6] hover:text-red-300 hover:bg-red-500/10 border border-transparent hover:border-red-500/30",title:"Delete chat",onClick:s=>{s.stopPropagation(),xt(r.id),st(c=>c+1);},children:jsxRuntime.jsx(iconsReact.IconTrash,{size:16,stroke:2})})]})},r.id))})})()})]})]}),document.body),!v&&jsxRuntime.jsx("button",{"aria-label":"Close chat",className:"rounded-lg p-2 transition-all duration-200 ease-out",style:{backgroundColor:"transparent",color:t.mutedTextColor},onMouseEnter:e=>{e.currentTarget.style.backgroundColor=t.hoverBackground,e.currentTarget.style.color=t.textColor;},onMouseLeave:e=>{e.currentTarget.style.backgroundColor="transparent",e.currentTarget.style.color=t.mutedTextColor;},onClick:()=>pe(false),children:jsxRuntime.jsx(iconsReact.IconChevronRight,{size:20,stroke:2,style:{transform:g==="rtl"?"rotate(180deg)":"none"}})})]})]}),jsxRuntime.jsxs("div",{className:"flex-1 overflow-y-auto space-y-4 px-1 pb-4 pt-4",ref:dt,onScroll:e=>{let n=e.currentTarget,c=n.scrollHeight-(n.scrollTop+n.clientHeight)<=64;c!==ke&&pt(c);},children:[Oe&&jsxRuntime.jsx("div",{className:"mx-2 rounded-xl bg-red-500/10 text-red-300 border border-red-500/30 p-3 text-sm",children:Oe}),N.length===0&&!h&&jsxRuntime.jsx("div",{className:"mx-2 rounded-xl p-4",style:{border:`1px solid ${t.borderColor}`,backgroundColor:t.accentColor,color:t.mutedTextColor},children:"Start by sending a message to the agent."}),jsxRuntime.jsx("ul",{className:"space-y-4",children:N.map((e,n)=>jsxRuntime.jsx("li",{className:"px-1",children:e.role==="user"?ct===e.id?jsxRuntime.jsxs("div",{className:"max-w-[720px] rounded-2xl p-2 text-[15px] ring-2",style:{backgroundColor:t.accentColor,color:t.textColor,borderColor:t.primaryColor},children:[jsxRuntime.jsx("textarea",{autoFocus:true,className:"w-full resize-none bg-transparent p-2 leading-relaxed outline-none",rows:Math.max(2,Math.min(10,Math.ceil((fe||e.text).length/60))),value:fe,onChange:r=>Le(r.target.value),onKeyDown:r=>{r.key==="Escape"?ge(null):r.key==="Enter"&&!r.shiftKey&&(r.preventDefault(),h||ze(e.id,fe||e.text));}}),jsxRuntime.jsxs("div",{className:"flex items-center justify-end gap-2 px-2 pb-2",children:[jsxRuntime.jsx("button",{className:"rounded-lg px-3 py-1 text-sm transition-colors",style:{border:`1px solid ${t.borderColor}`,color:t.mutedTextColor,backgroundColor:"transparent"},onMouseEnter:r=>r.currentTarget.style.backgroundColor=t.inputBackground,onMouseLeave:r=>r.currentTarget.style.backgroundColor="transparent",onClick:()=>ge(null),children:"Cancel"}),jsxRuntime.jsx("button",{className:"rounded-lg px-3 py-1 text-sm transition-colors",style:{border:`1px solid ${t.borderColor}`,backgroundColor:t.cardBackground,color:t.textColor},onMouseEnter:r=>r.currentTarget.style.borderColor=t.primaryColor,onMouseLeave:r=>r.currentTarget.style.borderColor=t.borderColor,onClick:()=>{h||ze(e.id,fe||e.text);},children:"Save"})]})]}):jsxRuntime.jsx("div",{title:"Click to edit",onClick:()=>{h||(ge(e.id),Le(e.text));},className:"max-w-[720px] rounded-2xl p-4 text-[15px] leading-relaxed whitespace-pre-wrap cursor-pointer transition",style:{backgroundColor:t.accentColor,color:t.textColor},onMouseEnter:r=>r.currentTarget.style.backgroundColor=t.hoverBackground,onMouseLeave:r=>r.currentTarget.style.backgroundColor=t.accentColor,children:e.text}):jsxRuntime.jsxs("div",{className:"space-y-3",children:[e.reasoning&&jsxRuntime.jsxs("div",{className:"rounded-xl p-3 cursor-pointer",style:{backgroundColor:t.inputBackground,border:`1px solid ${t.borderColor}`},onClick:()=>{we.current=true,w(r=>r.map(s=>s.id===e.id&&s.role==="assistant"?{...s,reasoningOpen:!s.reasoningOpen}:s));},children:[jsxRuntime.jsxs("div",{className:"flex items-center justify-between mb-1",children:[jsxRuntime.jsx("div",{className:"text-xs",style:{color:t.mutedTextColor},children:"Reasoning"}),jsxRuntime.jsx("button",{type:"button",className:"text-xs transition-colors",style:{color:t.mutedTextColor},onMouseEnter:r=>r.currentTarget.style.color=t.textColor,onMouseLeave:r=>r.currentTarget.style.color=t.mutedTextColor,children:e.reasoningOpen?"Hide":"Show full"})]}),e.reasoningOpen?jsxRuntime.jsx("pre",{className:"text-xs whitespace-pre-wrap break-words",style:{color:t.mutedTextColor},children:e.reasoning}):(()=>{let r=(e.reasoning||"").trim().split(`
|
|
4
|
+
`).filter(c=>c.trim()),s=r.length>0?r[r.length-1]:"";return jsxRuntime.jsx("pre",{className:"text-xs whitespace-pre-wrap break-words",style:{color:t.mutedTextColor},children:s||"\u2026"})})()]}),ht(e.items),h&&n===N.length-1&&jsxRuntime.jsxs("div",{className:"flex items-center gap-2 text-xs",style:{color:t.mutedTextColor},children:[jsxRuntime.jsx("span",{className:"inline-block h-2 w-2 rounded-full animate-pulse",style:{backgroundColor:t.mutedTextColor}}),jsxRuntime.jsx("span",{children:"Working\u2026"})]})]})},e.id))}),jsxRuntime.jsx("div",{ref:Pe})]}),jsxRuntime.jsx("div",{className:"sticky bottom-0 mt-auto space-y-2 pb-2 pt-1",style:{backgroundColor:t.backgroundColor},children:jsxRuntime.jsx("div",{className:"relative flex-1",children:jsxRuntime.jsxs("div",{className:"relative w-full rounded-2xl pb-12 pt-4",style:{border:`1px solid ${t.borderColor}`,backgroundColor:t.accentColor},children:[jsxRuntime.jsx("div",{className:"px-4",children:jsxRuntime.jsx("textarea",{"aria-label":"Prompt",rows:2,className:"h-auto w-full resize-none bg-transparent text-[15px] leading-relaxed focus:outline-none hsafa-chat-textarea",style:{color:t.textColor},placeholder:et,value:de,onChange:e=>Fe(e.target.value),onKeyDown:e=>{e.key==="Enter"&&!e.shiftKey&&(e.preventDefault(),h||Ke());},ref:ut})}),jsxRuntime.jsxs("div",{className:"absolute bottom-2 left-2 flex items-center gap-1",style:{color:t.mutedTextColor},children:[jsxRuntime.jsx("button",{className:"rounded-lg p-2 transition-colors",style:{backgroundColor:"transparent"},onMouseEnter:e=>{e.currentTarget.style.backgroundColor=`${t.backgroundColor}99`,e.currentTarget.style.color=t.textColor;},onMouseLeave:e=>{e.currentTarget.style.backgroundColor="transparent",e.currentTarget.style.color=t.mutedTextColor;},"aria-label":"Attach files",children:jsxRuntime.jsx(iconsReact.IconPaperclip,{size:18,stroke:2})}),jsxRuntime.jsx("button",{className:"rounded-lg p-2 transition-colors",style:{backgroundColor:"transparent"},onMouseEnter:e=>{e.currentTarget.style.backgroundColor=`${t.backgroundColor}99`,e.currentTarget.style.color=t.textColor;},onMouseLeave:e=>{e.currentTarget.style.backgroundColor="transparent",e.currentTarget.style.color=t.mutedTextColor;},"aria-label":"Insert link",children:jsxRuntime.jsx(iconsReact.IconLink,{size:18,stroke:2})})]}),jsxRuntime.jsx("div",{className:"absolute bottom-2 right-2",children:jsxRuntime.jsx("button",{"aria-label":h?"Stop":"Send",disabled:!h&&!de.trim(),className:"rounded-xl p-3 transition-all duration-200 ease-out",style:{border:`1px solid ${h?"#ef4444":t.borderColor}`,backgroundColor:h?"#ef444420":t.cardBackground,color:h?"#ef4444":t.mutedTextColor,opacity:!h&&!de.trim()?.4:1},onMouseEnter:e=>{e.currentTarget.disabled||(h?(e.currentTarget.style.borderColor="#dc2626",e.currentTarget.style.backgroundColor="#dc262630",e.currentTarget.style.color="#dc2626"):(e.currentTarget.style.borderColor=t.primaryColor,e.currentTarget.style.backgroundColor=t.hoverBackground,e.currentTarget.style.color=t.textColor));},onMouseLeave:e=>{e.currentTarget.disabled||(h?(e.currentTarget.style.borderColor="#ef4444",e.currentTarget.style.backgroundColor="#ef444420",e.currentTarget.style.color="#ef4444"):(e.currentTarget.style.borderColor=t.borderColor,e.currentTarget.style.backgroundColor=t.cardBackground,e.currentTarget.style.color=t.mutedTextColor));},onClick:()=>{h?Ct():Ke();},children:h?jsxRuntime.jsx(iconsReact.IconPlayerStop,{size:18,stroke:2}):jsxRuntime.jsx(iconsReact.IconArrowUp,{size:18,stroke:2})})})]})})})]}),!_&&!v&&jsxRuntime.jsx("button",{"aria-label":"Open chat",onClick:()=>pe(true),className:"rounded-full border p-3 shadow-md transition-colors",style:{...wt,borderColor:t.borderColor,backgroundColor:t.accentColor,color:t.textColor,borderRadius:"50%"},onMouseEnter:e=>{e.currentTarget.style.borderColor=t.primaryColor,e.currentTarget.style.backgroundColor=`${t.accentColor}dd`;},onMouseLeave:e=>{e.currentTarget.style.borderColor=t.borderColor,e.currentTarget.style.backgroundColor=t.accentColor;},children:jsxRuntime.jsx(iconsReact.IconMessage,{size:20,stroke:2})}),jsxRuntime.jsx("style",{children:`
|
|
5
|
+
@keyframes tc-border-flow {
|
|
6
|
+
0% { background-position: 0% 50%; }
|
|
7
|
+
50% { background-position: 100% 50%; }
|
|
8
|
+
100% { background-position: 0% 50%; }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.tc-animated-border {
|
|
12
|
+
position: relative;
|
|
13
|
+
/* Animated shimmer border using primary color */
|
|
14
|
+
background: linear-gradient(120deg,
|
|
15
|
+
${t.primaryColor}dd 0%,
|
|
16
|
+
${t.primaryColor}88 25%,
|
|
17
|
+
${t.primaryColor}00 50%,
|
|
18
|
+
${t.primaryColor}88 75%,
|
|
19
|
+
${t.primaryColor}dd 100%
|
|
20
|
+
);
|
|
21
|
+
background-size: 300% 300%;
|
|
22
|
+
animation: tc-border-flow 3s ease-in-out infinite;
|
|
23
|
+
filter: drop-shadow(0 0 10px ${t.primaryColor}40);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
.hsafa-chat-textarea::placeholder {
|
|
27
|
+
color: ${t.mutedTextColor};
|
|
28
|
+
}
|
|
29
|
+
`})]})}exports.Button=er;exports.HsafaChat=Xt;exports.HsafaProvider=Et;exports.useAutoScroll=lr;exports.useHsafa=ee;exports.useHsafaAction=mr;exports.useHsafaComponent=Cr;exports.useToggle=nr;//# sourceMappingURL=index.cjs.map
|
|
30
|
+
//# sourceMappingURL=index.cjs.map
|