@cloudflare/ai-search-snippet 0.0.17
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/LICENSE +21 -0
- package/README.md +573 -0
- package/dist/clouds.json +417 -0
- package/dist/main.d.ts +359 -0
- package/dist/search-snippet.es.js +3413 -0
- package/dist/search-snippet.es.js.map +1 -0
- package/dist/search-snippet.umd.js +2206 -0
- package/dist/search-snippet.umd.js.map +1 -0
- package/dist/vite.svg +1 -0
- package/package.json +66 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Cloudflare, Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
# ๐ Search Snippet Library
|
|
2
|
+
|
|
3
|
+
A production-ready, self-contained TypeScript Web Component library providing both search and chat interfaces with streaming support. Zero dependencies, fully customizable, and framework-agnostic.
|
|
4
|
+
|
|
5
|
+
## โจ Features
|
|
6
|
+
|
|
7
|
+
- **๐จ Fully Customizable** - 20+ CSS variables for complete theme control
|
|
8
|
+
- **โก Zero Dependencies** - Self-contained with everything bundled
|
|
9
|
+
- **๐ฑ Responsive Design** - Works seamlessly on all devices
|
|
10
|
+
- **๐ญ Framework Agnostic** - Native Web Components work everywhere
|
|
11
|
+
- **โฟ Accessible** - WCAG 2.1 AA compliant with ARIA support
|
|
12
|
+
- **๐ Streaming Support** - Real-time streaming responses with low latency
|
|
13
|
+
- **๐ Dark Mode** - Automatic theme switching based on system preferences
|
|
14
|
+
- **๐ฆ Tiny Bundle** - Optimized for minimal size (< 50KB gzipped)
|
|
15
|
+
- **๐ Secure** - XSS protection with HTML sanitization
|
|
16
|
+
- **โ๏ธ TypeScript** - Full type definitions included
|
|
17
|
+
|
|
18
|
+
## ๐ Quick Start
|
|
19
|
+
|
|
20
|
+
> **Note:** This library requires an active AI Search endpoint in your Cloudflare Dashboard. Make sure to enable and configure your AI Search service before using these components.
|
|
21
|
+
|
|
22
|
+
### Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install @cloudflare/ai-search-snippet
|
|
26
|
+
# or
|
|
27
|
+
yarn add @cloudflare/ai-search-snippet
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Basic Usage
|
|
31
|
+
|
|
32
|
+
> **Note:** Replace `<hash>` with your Cloudflare AI Search endpoint hash (you can find it in the Cloudflare Dashboard).
|
|
33
|
+
|
|
34
|
+
```html
|
|
35
|
+
<!-- Import the library -->
|
|
36
|
+
<script
|
|
37
|
+
type="module"
|
|
38
|
+
src="https:/<hash>/search.ai.cloudflare.com/search-snippet.es.js"
|
|
39
|
+
></script>
|
|
40
|
+
|
|
41
|
+
<!-- Search bar with results -->
|
|
42
|
+
<search-bar-snippet
|
|
43
|
+
api-url="https:/<hash>/search.ai.cloudflare.com/"
|
|
44
|
+
placeholder="Search..."
|
|
45
|
+
max-results="10"
|
|
46
|
+
>
|
|
47
|
+
</search-bar-snippet>
|
|
48
|
+
|
|
49
|
+
<!-- Modal search (opens with Cmd/Ctrl+K) -->
|
|
50
|
+
<search-modal-snippet
|
|
51
|
+
api-url="https:/<hash>/search.ai.cloudflare.com/"
|
|
52
|
+
placeholder="Search documentation..."
|
|
53
|
+
max-results="10"
|
|
54
|
+
>
|
|
55
|
+
</search-modal-snippet>
|
|
56
|
+
|
|
57
|
+
<!-- Floating chat bubble -->
|
|
58
|
+
<chat-bubble-snippet
|
|
59
|
+
api-url="https:/<hash>/search.ai.cloudflare.com/"
|
|
60
|
+
placeholder="Type a message..."
|
|
61
|
+
>
|
|
62
|
+
</chat-bubble-snippet>
|
|
63
|
+
|
|
64
|
+
<!-- Full-page chat with history -->
|
|
65
|
+
<chat-page-snippet
|
|
66
|
+
api-url="https:/<hash>/search.ai.cloudflare.com/"
|
|
67
|
+
placeholder="Type a message..."
|
|
68
|
+
>
|
|
69
|
+
</chat-page-snippet>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## ๐ API Reference
|
|
73
|
+
|
|
74
|
+
### Components
|
|
75
|
+
|
|
76
|
+
The library provides four Web Components:
|
|
77
|
+
|
|
78
|
+
| Component | Tag | Description |
|
|
79
|
+
| -------------------- | ------------------------ | ------------------------------------- |
|
|
80
|
+
| `SearchBarSnippet` | `<search-bar-snippet>` | Search input with results dropdown |
|
|
81
|
+
| `SearchModalSnippet` | `<search-modal-snippet>` | Modal search with Cmd/Ctrl+K shortcut |
|
|
82
|
+
| `ChatBubbleSnippet` | `<chat-bubble-snippet>` | Floating chat bubble overlay |
|
|
83
|
+
| `ChatPageSnippet` | `<chat-page-snippet>` | Full-page chat with session history |
|
|
84
|
+
|
|
85
|
+
### Common Attributes
|
|
86
|
+
|
|
87
|
+
These attributes are available on all components:
|
|
88
|
+
|
|
89
|
+
| Attribute | Type | Default | Description |
|
|
90
|
+
| --------------- | ----------------------------- | ----------------------- | ------------------------------ |
|
|
91
|
+
| `api-url` | string | `http://localhost:3000` | API endpoint URL |
|
|
92
|
+
| `placeholder` | string | Component-specific | Input placeholder text |
|
|
93
|
+
| `theme` | `'light' \| 'dark' \| 'auto'` | `'auto'` | Color scheme |
|
|
94
|
+
| `hide-branding` | boolean | `false` | Hide the "Powered by" branding |
|
|
95
|
+
|
|
96
|
+
### Search Components Attributes
|
|
97
|
+
|
|
98
|
+
Additional attributes for `<search-bar-snippet>` and `<search-modal-snippet>`:
|
|
99
|
+
|
|
100
|
+
| Attribute | Type | Default | Description |
|
|
101
|
+
| ------------- | ------ | ------- | ------------------------------------ |
|
|
102
|
+
| `max-results` | number | `10` | Maximum search results to display |
|
|
103
|
+
| `debounce-ms` | number | `300` | Input debounce delay in milliseconds |
|
|
104
|
+
|
|
105
|
+
### Modal-Specific Attributes
|
|
106
|
+
|
|
107
|
+
Additional attributes for `<search-modal-snippet>`:
|
|
108
|
+
|
|
109
|
+
| Attribute | Type | Default | Description |
|
|
110
|
+
| -------------- | ------- | ------- | ------------------------------------------ |
|
|
111
|
+
| `shortcut` | string | `'k'` | Keyboard shortcut key (with Cmd/Ctrl) |
|
|
112
|
+
| `use-meta-key` | boolean | `true` | Use meta key (Cmd on Mac, Ctrl on Windows) |
|
|
113
|
+
|
|
114
|
+
### JavaScript API
|
|
115
|
+
|
|
116
|
+
#### Search Bar (`<search-bar-snippet>`)
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
const searchBar = document.querySelector("search-bar-snippet");
|
|
120
|
+
|
|
121
|
+
// Perform a search programmatically
|
|
122
|
+
searchBar.search("query");
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
#### Search Modal (`<search-modal-snippet>`)
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const modal = document.querySelector("search-modal-snippet");
|
|
129
|
+
|
|
130
|
+
modal.open(); // Open the modal
|
|
131
|
+
modal.close(); // Close the modal
|
|
132
|
+
modal.toggle(); // Toggle open/closed
|
|
133
|
+
modal.search("query"); // Open and search
|
|
134
|
+
const results = modal.getResults(); // Get current results
|
|
135
|
+
const isOpen = modal.isModalOpen(); // Check if open
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
#### Chat Bubble (`<chat-bubble-snippet>`)
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
const chatBubble = document.querySelector("chat-bubble-snippet");
|
|
142
|
+
|
|
143
|
+
await chatBubble.sendMessage("Hello!"); // Send a message
|
|
144
|
+
const messages = chatBubble.getMessages(); // Get message history
|
|
145
|
+
chatBubble.clearChat(); // Clear chat history
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### Chat Page (`<chat-page-snippet>`)
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const chatPage = document.querySelector("chat-page-snippet");
|
|
152
|
+
|
|
153
|
+
await chatPage.sendMessage("Hello!"); // Send a message
|
|
154
|
+
const messages = chatPage.getMessages(); // Get message history
|
|
155
|
+
chatPage.clearChat(); // Clear current chat
|
|
156
|
+
const sessions = chatPage.getSessions(); // Get all chat sessions
|
|
157
|
+
const current = chatPage.getCurrentSession(); // Get current session
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Events
|
|
161
|
+
|
|
162
|
+
#### Common Events (all components)
|
|
163
|
+
|
|
164
|
+
```javascript
|
|
165
|
+
const component = document.querySelector("search-bar-snippet");
|
|
166
|
+
|
|
167
|
+
component.addEventListener("ready", () => {
|
|
168
|
+
console.log("Component ready");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
component.addEventListener("error", (e) => {
|
|
172
|
+
console.error("Error:", e.detail.error);
|
|
173
|
+
});
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
#### Modal-Specific Events
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
const modal = document.querySelector("search-modal-snippet");
|
|
180
|
+
|
|
181
|
+
modal.addEventListener("open", () => {
|
|
182
|
+
console.log("Modal opened");
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
modal.addEventListener("close", () => {
|
|
186
|
+
console.log("Modal closed");
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
modal.addEventListener("result-select", (e) => {
|
|
190
|
+
console.log("Selected result:", e.detail.result);
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
#### Chat Events
|
|
195
|
+
|
|
196
|
+
```javascript
|
|
197
|
+
const chat = document.querySelector("chat-bubble-snippet");
|
|
198
|
+
|
|
199
|
+
chat.addEventListener("message", (e) => {
|
|
200
|
+
console.log("New message:", e.detail.message);
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
## ๐จ Customization
|
|
205
|
+
|
|
206
|
+
### CSS Variables
|
|
207
|
+
|
|
208
|
+
Customize the appearance using CSS variables:
|
|
209
|
+
|
|
210
|
+
```css
|
|
211
|
+
search-bar-snippet,
|
|
212
|
+
search-modal-snippet,
|
|
213
|
+
chat-bubble-snippet,
|
|
214
|
+
chat-page-snippet {
|
|
215
|
+
/* ========== COLORS ========== */
|
|
216
|
+
/* Primary */
|
|
217
|
+
--search-snippet-primary-color: #2563eb;
|
|
218
|
+
--search-snippet-primary-hover: #0f51dfff;
|
|
219
|
+
|
|
220
|
+
/* Background & Surface */
|
|
221
|
+
--search-snippet-background: #ffffff;
|
|
222
|
+
--search-snippet-surface: #f8f9fa;
|
|
223
|
+
--search-snippet-hover-background: #f1f3f5;
|
|
224
|
+
|
|
225
|
+
/* Text */
|
|
226
|
+
--search-snippet-text-color: #212529;
|
|
227
|
+
--search-snippet-text-secondary: #6c757d;
|
|
228
|
+
|
|
229
|
+
/* Border & Focus */
|
|
230
|
+
--search-snippet-border-color: #dee2e6;
|
|
231
|
+
--search-snippet-focus-ring: #0066cc40;
|
|
232
|
+
|
|
233
|
+
/* Status Colors */
|
|
234
|
+
--search-snippet-error-color: #dc3545;
|
|
235
|
+
--search-snippet-error-background: #f8d7da;
|
|
236
|
+
--search-snippet-success-color: #28a745;
|
|
237
|
+
--search-snippet-success-background: #d4edda;
|
|
238
|
+
--search-snippet-warning-color: #ffc107;
|
|
239
|
+
--search-snippet-warning-background: #fff3cd;
|
|
240
|
+
|
|
241
|
+
/* Message Colors */
|
|
242
|
+
--search-snippet-user-message-bg: #0066cc;
|
|
243
|
+
--search-snippet-user-message-text: #ffffff;
|
|
244
|
+
--search-snippet-assistant-message-bg: #f1f3f5;
|
|
245
|
+
--search-snippet-assistant-message-text: #212529;
|
|
246
|
+
--search-snippet-system-message-bg: #fff3cd;
|
|
247
|
+
--search-snippet-system-message-text: #856404;
|
|
248
|
+
|
|
249
|
+
/* ========== TYPOGRAPHY ========== */
|
|
250
|
+
--search-snippet-font-family:
|
|
251
|
+
-apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue",
|
|
252
|
+
Arial, sans-serif;
|
|
253
|
+
--search-snippet-font-family-mono:
|
|
254
|
+
"SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace;
|
|
255
|
+
--search-snippet-font-size-base: 14px;
|
|
256
|
+
--search-snippet-font-size-sm: 12px;
|
|
257
|
+
--search-snippet-font-size-lg: 16px;
|
|
258
|
+
--search-snippet-font-size-xl: 18px;
|
|
259
|
+
--search-snippet-line-height: 1.5;
|
|
260
|
+
--search-snippet-font-weight-normal: 400;
|
|
261
|
+
--search-snippet-font-weight-medium: 500;
|
|
262
|
+
--search-snippet-font-weight-bold: 600;
|
|
263
|
+
|
|
264
|
+
/* ========== SPACING ========== */
|
|
265
|
+
--search-snippet-spacing-xs: 4px;
|
|
266
|
+
--search-snippet-spacing-sm: 8px;
|
|
267
|
+
--search-snippet-spacing-md: 12px;
|
|
268
|
+
--search-snippet-spacing-lg: 16px;
|
|
269
|
+
--search-snippet-spacing-xl: 24px;
|
|
270
|
+
--search-snippet-spacing-xxl: 32px;
|
|
271
|
+
|
|
272
|
+
/* ========== SIZING ========== */
|
|
273
|
+
--search-snippet-width: 100%;
|
|
274
|
+
--search-snippet-max-width: 100%;
|
|
275
|
+
--search-snippet-min-width: 320px;
|
|
276
|
+
--search-snippet-max-height: 600px;
|
|
277
|
+
--search-snippet-input-height: 44px;
|
|
278
|
+
--search-snippet-button-height: 36px;
|
|
279
|
+
--search-snippet-icon-size: 20px;
|
|
280
|
+
--search-snippet-icon-margin-left: 6px;
|
|
281
|
+
|
|
282
|
+
/* ========== BORDER ========== */
|
|
283
|
+
--search-snippet-border-width: 1px;
|
|
284
|
+
--search-snippet-border-radius: 18px;
|
|
285
|
+
|
|
286
|
+
/* ========== SHADOWS ========== */
|
|
287
|
+
--search-snippet-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
288
|
+
--search-snippet-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
|
|
289
|
+
--search-snippet-shadow-md: 0 4px 12px rgba(0, 0, 0, 0.15);
|
|
290
|
+
--search-snippet-shadow-lg: 0 8px 24px rgba(0, 0, 0, 0.2);
|
|
291
|
+
--search-snippet-shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);
|
|
292
|
+
--search-snippet-result-item-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
|
|
293
|
+
|
|
294
|
+
/* ========== ANIMATION ========== */
|
|
295
|
+
--search-snippet-transition-fast: 150ms ease;
|
|
296
|
+
--search-snippet-transition: 200ms ease;
|
|
297
|
+
--search-snippet-transition-slow: 300ms ease;
|
|
298
|
+
--search-snippet-animation-duration: 0.2s;
|
|
299
|
+
|
|
300
|
+
/* ========== Z-INDEX ========== */
|
|
301
|
+
--search-snippet-z-dropdown: 1000;
|
|
302
|
+
--search-snippet-z-modal: 1050;
|
|
303
|
+
--search-snippet-z-popover: 1060;
|
|
304
|
+
--search-snippet-z-tooltip: 1070;
|
|
305
|
+
|
|
306
|
+
/* ========== CHAT BUBBLE SPECIFIC ========== */
|
|
307
|
+
--chat-bubble-button-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
|
308
|
+
--chat-bubble-window-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
|
309
|
+
--chat-bubble-button-size: 60px;
|
|
310
|
+
--chat-bubble-button-radius: 50%;
|
|
311
|
+
--chat-bubble-button-icon-size: 28px;
|
|
312
|
+
--chat-bubble-button-icon-color: white;
|
|
313
|
+
--chat-bubble-button-bottom: 20px;
|
|
314
|
+
--chat-bubble-button-right: 20px;
|
|
315
|
+
--chat-bubble-button-z-index: 9999;
|
|
316
|
+
--chat-bubble-position: fixed;
|
|
317
|
+
}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
### Theme Examples
|
|
321
|
+
|
|
322
|
+
**Dark Theme:**
|
|
323
|
+
|
|
324
|
+
```css
|
|
325
|
+
search-bar-snippet {
|
|
326
|
+
--search-snippet-primary-color: #4dabf7;
|
|
327
|
+
--search-snippet-background: #1a1b1e;
|
|
328
|
+
--search-snippet-text-color: #c1c2c5;
|
|
329
|
+
--search-snippet-border-color: #373a40;
|
|
330
|
+
}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
**Custom Brand:**
|
|
334
|
+
|
|
335
|
+
```css
|
|
336
|
+
chat-bubble-snippet {
|
|
337
|
+
--search-snippet-primary-color: #667eea;
|
|
338
|
+
--search-snippet-primary-hover: #5568d3;
|
|
339
|
+
--search-snippet-border-radius: 12px;
|
|
340
|
+
--search-snippet-shadow: 0 4px 12px rgba(102, 126, 234, 0.2);
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
## ๐ง Advanced Usage
|
|
345
|
+
|
|
346
|
+
### TypeScript
|
|
347
|
+
|
|
348
|
+
```typescript
|
|
349
|
+
import {
|
|
350
|
+
SearchBarSnippet,
|
|
351
|
+
SearchModalSnippet,
|
|
352
|
+
ChatBubbleSnippet,
|
|
353
|
+
ChatPageSnippet,
|
|
354
|
+
type SearchSnippetProps,
|
|
355
|
+
} from "@cloudflare/ai-search-snippet";
|
|
356
|
+
|
|
357
|
+
// Type-safe usage
|
|
358
|
+
const searchBar = document.createElement(
|
|
359
|
+
"search-bar-snippet",
|
|
360
|
+
) as SearchBarSnippet;
|
|
361
|
+
searchBar.setAttribute("api-url", "https://api.example.com");
|
|
362
|
+
searchBar.setAttribute("max-results", "10");
|
|
363
|
+
|
|
364
|
+
const chatBubble = document.createElement(
|
|
365
|
+
"chat-bubble-snippet",
|
|
366
|
+
) as ChatBubbleSnippet;
|
|
367
|
+
chatBubble.setAttribute("api-url", "https://api.example.com");
|
|
368
|
+
await chatBubble.sendMessage("Hello, world!");
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
### React Integration
|
|
372
|
+
|
|
373
|
+
```tsx
|
|
374
|
+
import { useEffect, useRef } from "react";
|
|
375
|
+
import "@cloudflare/ai-search-snippet";
|
|
376
|
+
|
|
377
|
+
function ChatWidget() {
|
|
378
|
+
const ref = useRef<HTMLElement>(null);
|
|
379
|
+
|
|
380
|
+
useEffect(() => {
|
|
381
|
+
const chat = ref.current;
|
|
382
|
+
|
|
383
|
+
const handleMessage = (e: CustomEvent) => {
|
|
384
|
+
console.log("Message:", e.detail);
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
chat?.addEventListener("message", handleMessage as EventListener);
|
|
388
|
+
|
|
389
|
+
return () => {
|
|
390
|
+
chat?.removeEventListener("message", handleMessage as EventListener);
|
|
391
|
+
};
|
|
392
|
+
}, []);
|
|
393
|
+
|
|
394
|
+
return (
|
|
395
|
+
<chat-bubble-snippet
|
|
396
|
+
ref={ref}
|
|
397
|
+
api-url="https://api.example.com"
|
|
398
|
+
placeholder="Ask a question..."
|
|
399
|
+
/>
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Vue Integration
|
|
405
|
+
|
|
406
|
+
```vue
|
|
407
|
+
<template>
|
|
408
|
+
<chat-bubble-snippet
|
|
409
|
+
:api-url="apiUrl"
|
|
410
|
+
placeholder="Ask a question..."
|
|
411
|
+
@message="handleMessage"
|
|
412
|
+
@error="handleError"
|
|
413
|
+
/>
|
|
414
|
+
</template>
|
|
415
|
+
|
|
416
|
+
<script setup>
|
|
417
|
+
import { ref } from "vue";
|
|
418
|
+
import "@cloudflare/ai-search-snippet";
|
|
419
|
+
|
|
420
|
+
const apiUrl = ref("https://api.example.com");
|
|
421
|
+
|
|
422
|
+
const handleMessage = (event) => {
|
|
423
|
+
console.log("Message:", event.detail.message);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const handleError = (event) => {
|
|
427
|
+
console.error("Error:", event.detail.error);
|
|
428
|
+
};
|
|
429
|
+
</script>
|
|
430
|
+
```
|
|
431
|
+
|
|
432
|
+
## ๐๏ธ Development
|
|
433
|
+
|
|
434
|
+
### Build from Source
|
|
435
|
+
|
|
436
|
+
```bash
|
|
437
|
+
# Install dependencies
|
|
438
|
+
npm install
|
|
439
|
+
|
|
440
|
+
# Development mode with hot reload
|
|
441
|
+
npm run dev
|
|
442
|
+
|
|
443
|
+
# Build for production
|
|
444
|
+
npm run build
|
|
445
|
+
|
|
446
|
+
# Preview production build
|
|
447
|
+
npm run preview
|
|
448
|
+
|
|
449
|
+
# Lint and format
|
|
450
|
+
npm run lint
|
|
451
|
+
npm run format
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Project Structure
|
|
455
|
+
|
|
456
|
+
```
|
|
457
|
+
nlweb-cl-snippet/
|
|
458
|
+
โโโ src/
|
|
459
|
+
โ โโโ api/
|
|
460
|
+
โ โ โโโ index.ts # Base Client abstract class
|
|
461
|
+
โ โ โโโ ai-search.ts # AISearchClient with streaming
|
|
462
|
+
โ โโโ components/
|
|
463
|
+
โ โ โโโ search-bar-snippet.ts # Search input with results
|
|
464
|
+
โ โ โโโ search-modal-snippet.ts # Modal search with Cmd/Ctrl+K
|
|
465
|
+
โ โ โโโ chat-bubble-snippet.ts # Floating chat bubble
|
|
466
|
+
โ โ โโโ chat-page-snippet.ts # Full-page chat with history
|
|
467
|
+
โ โ โโโ chat-view.ts # Shared chat interface
|
|
468
|
+
โ โโโ styles/
|
|
469
|
+
โ โ โโโ theme.ts # Base styles & CSS variables
|
|
470
|
+
โ โ โโโ search.ts # Search-specific styles
|
|
471
|
+
โ โ โโโ chat.ts # Chat-specific styles
|
|
472
|
+
โ โโโ types/
|
|
473
|
+
โ โ โโโ index.ts # TypeScript definitions
|
|
474
|
+
โ โโโ utils/
|
|
475
|
+
โ โ โโโ index.ts # Utility functions
|
|
476
|
+
โ โโโ main.ts # Entry point
|
|
477
|
+
โโโ dist/ # Build output
|
|
478
|
+
โโโ index.html # Demo page
|
|
479
|
+
โโโ package.json
|
|
480
|
+
โโโ tsconfig.json
|
|
481
|
+
โโโ vite.config.ts
|
|
482
|
+
โโโ README.md
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
## ๐ API Server Requirements
|
|
486
|
+
|
|
487
|
+
The component expects the API server to implement the following endpoints:
|
|
488
|
+
|
|
489
|
+
### Search Endpoint
|
|
490
|
+
|
|
491
|
+
**POST** `/search`
|
|
492
|
+
|
|
493
|
+
Request:
|
|
494
|
+
|
|
495
|
+
```json
|
|
496
|
+
{
|
|
497
|
+
"query": "search query",
|
|
498
|
+
"max_results": 10,
|
|
499
|
+
"filters": {}
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Response:
|
|
504
|
+
|
|
505
|
+
```json
|
|
506
|
+
{
|
|
507
|
+
"results": [
|
|
508
|
+
{
|
|
509
|
+
"id": "result-1",
|
|
510
|
+
"title": "Result Title",
|
|
511
|
+
"snippet": "Result description...",
|
|
512
|
+
"url": "https://example.com",
|
|
513
|
+
"metadata": {}
|
|
514
|
+
}
|
|
515
|
+
],
|
|
516
|
+
"total": 42
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
### Chat Endpoint (Streaming)
|
|
521
|
+
|
|
522
|
+
**POST** `/ask`
|
|
523
|
+
|
|
524
|
+
Request:
|
|
525
|
+
|
|
526
|
+
```json
|
|
527
|
+
{
|
|
528
|
+
"query": "user message",
|
|
529
|
+
"generate_mode": "summarize",
|
|
530
|
+
"prev": [
|
|
531
|
+
{
|
|
532
|
+
"role": "user",
|
|
533
|
+
"content": "previous message",
|
|
534
|
+
"timestamp": 1234567890
|
|
535
|
+
}
|
|
536
|
+
]
|
|
537
|
+
}
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
Response: Streaming text chunks via ReadableStream
|
|
541
|
+
|
|
542
|
+
## ๐งช Browser Support
|
|
543
|
+
|
|
544
|
+
- Chrome 90+
|
|
545
|
+
- Firefox 88+
|
|
546
|
+
- Safari 14+
|
|
547
|
+
- Edge 90+
|
|
548
|
+
|
|
549
|
+
## ๐ License
|
|
550
|
+
|
|
551
|
+
MIT License - see LICENSE file for details
|
|
552
|
+
|
|
553
|
+
## ๐ค Contributing
|
|
554
|
+
|
|
555
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
556
|
+
|
|
557
|
+
## ๐ Bug Reports
|
|
558
|
+
|
|
559
|
+
If you discover any bugs, please create an issue on GitHub with:
|
|
560
|
+
|
|
561
|
+
- Description of the bug
|
|
562
|
+
- Steps to reproduce
|
|
563
|
+
- Expected behavior
|
|
564
|
+
- Actual behavior
|
|
565
|
+
- Browser and version
|
|
566
|
+
|
|
567
|
+
## ๐ฎ Support
|
|
568
|
+
|
|
569
|
+
For questions and support, please open a GitHub issue.
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
Built with TypeScript, Web Components, and โค๏ธ
|