insytful-ai-search-components 2.1.2 → 2.1.3
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 +165 -212
- package/dist/insytful-ai-search-components.js +177 -177
- package/dist/insytful-search.js +30 -30
- package/dist/types/web-component/dialog-renderer.d.ts +3 -1
- package/dist/types/web-component/insytful-search-element.d.ts +2 -0
- package/package.json +1 -1
- /package/dist/types/{utilities → search}/hooks.util.d.ts +0 -0
package/README.md
CHANGED
|
@@ -2,23 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
AI-powered search modals with two delivery options:
|
|
4
4
|
|
|
5
|
-
1. **[Web Component](#web-component
|
|
6
|
-
2. **[React Components](#react-
|
|
7
|
-
|
|
8
|
-
Both share the same visual design, CSS theming, and Contensis RAG API integration.
|
|
5
|
+
1. **[Web Component](#web-component)** — Standalone `<insytful-search>` custom element for any HTML page. No React, no build step, no npm. Ideal for CMS sites (Contensis, WordPress, static HTML).
|
|
6
|
+
2. **[React Components](#react-components)** — Radix-style compound components for React applications. Install via npm.
|
|
7
|
+
|
|
8
|
+
Both share the same visual design, [CSS theming](#css-custom-properties), and Contensis RAG API integration.
|
|
9
|
+
|
|
10
|
+
## Table of Contents
|
|
11
|
+
|
|
12
|
+
- [Web Component](#web-component)
|
|
13
|
+
- [Setup](#setup)
|
|
14
|
+
- [Contensis CMS (Razor)](#contensis-cms--razor)
|
|
15
|
+
- [Attributes](#attributes)
|
|
16
|
+
- [Slots](#slots)
|
|
17
|
+
- [Child Elements](#child-elements)
|
|
18
|
+
- [JavaScript API](#javascript-api)
|
|
19
|
+
- [Dynamic Offsets](#dynamic-offsets)
|
|
20
|
+
- [React Components](#react-components)
|
|
21
|
+
- [Installation](#installation)
|
|
22
|
+
- [Quick Start](#quick-start)
|
|
23
|
+
- [Architecture](#architecture)
|
|
24
|
+
- [Components](#components)
|
|
25
|
+
- [Mode Switching](#mode-switching)
|
|
26
|
+
- [Context Hooks](#context-hooks)
|
|
27
|
+
- [Styling](#styling)
|
|
28
|
+
- [Markdown Rendering](#markdown-rendering)
|
|
29
|
+
- [TypeScript](#typescript)
|
|
30
|
+
- [CSS Custom Properties](#css-custom-properties)
|
|
31
|
+
- [Accessibility](#accessibility)
|
|
32
|
+
- [Browser Support](#browser-support)
|
|
9
33
|
|
|
10
34
|
---
|
|
11
35
|
|
|
12
|
-
## Web Component
|
|
36
|
+
## Web Component
|
|
13
37
|
|
|
14
38
|
A single script tag adds AI search to any page. No build step, no npm, no framework required.
|
|
15
39
|
|
|
16
40
|
### Setup
|
|
17
41
|
|
|
18
|
-
Add the script to your page, then use the `<insytful-search>` element:
|
|
19
|
-
|
|
20
42
|
```html
|
|
21
|
-
<script src="https://unpkg.com/insytful-ai-search-components/dist/insytful-search.js"></script>
|
|
43
|
+
<script src="https://unpkg.com/insytful-ai-search-components@2.1.2/dist/insytful-search.js"></script>
|
|
22
44
|
|
|
23
45
|
<insytful-search
|
|
24
46
|
api-uri="https://your-api.com"
|
|
@@ -29,20 +51,20 @@ Add the script to your page, then use the `<insytful-search>` element:
|
|
|
29
51
|
<span slot="description">Ask a question in your own words</span>
|
|
30
52
|
<span slot="disclaimer">AI responses may not always be accurate.</span>
|
|
31
53
|
|
|
54
|
+
<insytful-close></insytful-close>
|
|
32
55
|
<insytful-suggestion>How do I get started?</insytful-suggestion>
|
|
33
56
|
<insytful-suggestion>What courses do you offer?</insytful-suggestion>
|
|
34
57
|
</insytful-search>
|
|
35
58
|
```
|
|
36
59
|
|
|
37
|
-
### Contensis CMS
|
|
60
|
+
### Contensis CMS / Razor
|
|
38
61
|
|
|
39
62
|
For classic Contensis sites using the .NET framework, add the Web Component to your layout or view:
|
|
40
63
|
|
|
41
64
|
```cshtml
|
|
42
65
|
@{
|
|
43
|
-
// Brand the modal — vars are documented under "CSS Custom Properties" below.
|
|
44
66
|
const string InsytfulAISearchTheme = @"
|
|
45
|
-
|
|
67
|
+
.insytful-root {
|
|
46
68
|
--insytful-font-family: 'Helvetica Neue', Arial, sans-serif;
|
|
47
69
|
--insytful-btn-prompt-bg-default: #f2f2f2;
|
|
48
70
|
--insytful-btn-prompt-bg-hover: #e5e5e5;
|
|
@@ -52,11 +74,9 @@ For classic Contensis sites using the .NET framework, add the Web Component to y
|
|
|
52
74
|
";
|
|
53
75
|
}
|
|
54
76
|
|
|
55
|
-
|
|
56
|
-
<script src="https://unpkg.com/insytful-ai-search-components@2.1.0/dist/insytful-search.js"></script>
|
|
77
|
+
<script src="https://unpkg.com/insytful-ai-search-components@2.1.2/dist/insytful-search.js"></script>
|
|
57
78
|
|
|
58
79
|
<style>
|
|
59
|
-
/* Prevent flash of unstyled content before the script loads */
|
|
60
80
|
insytful-search:not(:defined) { display: none; }
|
|
61
81
|
</style>
|
|
62
82
|
|
|
@@ -66,16 +86,14 @@ For classic Contensis sites using the .NET framework, add the Web Component to y
|
|
|
66
86
|
suggestions-position="below"
|
|
67
87
|
theme="@InsytfulAISearchTheme"
|
|
68
88
|
>
|
|
69
|
-
<button slot="trigger"
|
|
89
|
+
<button slot="trigger">Search this site</button>
|
|
70
90
|
<span slot="title">Ask our AI</span>
|
|
71
91
|
<span slot="description">Get instant answers about our courses and services</span>
|
|
72
92
|
<span slot="disclaimer">AI responses may not always be accurate. Please verify important information.</span>
|
|
73
93
|
|
|
74
|
-
<!-- Built-in close button (top-right). Empty content uses the default ✕ icon. -->
|
|
75
94
|
<insytful-close></insytful-close>
|
|
76
95
|
|
|
77
|
-
|
|
78
|
-
<img slot="avatar" src="/_design/img/logo-icon.png" alt="" width="32" height="32" style="width:100%;height:100%;object-fit:contain;" />
|
|
96
|
+
<img slot="avatar" src="/logo.png" alt="" width="32" height="32" />
|
|
79
97
|
|
|
80
98
|
<insytful-suggestion>How do I apply?</insytful-suggestion>
|
|
81
99
|
<insytful-suggestion>What courses do you offer?</insytful-suggestion>
|
|
@@ -86,75 +104,21 @@ For classic Contensis sites using the .NET framework, add the Web Component to y
|
|
|
86
104
|
</insytful-search>
|
|
87
105
|
```
|
|
88
106
|
|
|
89
|
-
To
|
|
90
|
-
|
|
91
|
-
```cshtml
|
|
92
|
-
<div class="sys_textBoxWithRedirect">
|
|
93
|
-
<input type="text" name="search" aria-label="Search" placeholder="Search..." id="search" />
|
|
94
|
-
<select id="searchType" name="searchType" aria-label="Select a type of search">
|
|
95
|
-
<option value="courses">Courses</option>
|
|
96
|
-
<option value="all">Whole site</option>
|
|
97
|
-
<option value="ai">AI Search</option>
|
|
98
|
-
</select>
|
|
99
|
-
<input type="image" id="topSearchButton" alt="Search" src="/_design/img/search-button-50px-2017.png" />
|
|
100
|
-
</div>
|
|
101
|
-
|
|
102
|
-
<!-- AI search component (trigger hidden — opened programmatically) -->
|
|
103
|
-
<insytful-search
|
|
104
|
-
id="ai-search"
|
|
105
|
-
api-uri="CurrentContext.Site.AI.Endpoint"
|
|
106
|
-
project-id="CurrentContext.Site.AI.ProjectId"
|
|
107
|
-
suggestions-position="below"
|
|
108
|
-
>
|
|
109
|
-
<span slot="title">Ask our AI</span>
|
|
110
|
-
<span slot="description">Get instant answers about our courses and services</span>
|
|
111
|
-
<span slot="disclaimer">AI responses may not always be accurate.</span>
|
|
112
|
-
|
|
113
|
-
<!-- Built-in close button — focus-trap-aware, no light-DOM hacks needed -->
|
|
114
|
-
<insytful-close></insytful-close>
|
|
115
|
-
|
|
116
|
-
<!-- Avatar next to AI responses -->
|
|
117
|
-
<img slot="avatar" src="/_design/img/logo-icon.png" alt="" width="32" height="32" style="width:100%;height:100%;object-fit:contain;" />
|
|
107
|
+
To open the dialog programmatically from your own search form:
|
|
118
108
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
(function($) {
|
|
130
|
-
$(function() {
|
|
131
|
-
var element = document.getElementById('ai-search');
|
|
132
|
-
|
|
133
|
-
$('#search').keypress(function(e) {
|
|
134
|
-
if (e.which == 13) {
|
|
135
|
-
e.preventDefault();
|
|
136
|
-
$('#btn').trigger('click');
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
|
|
140
|
-
$('#btn').on('click', function(e) {
|
|
141
|
-
e.preventDefault();
|
|
142
|
-
var type = $('#type :selected').val();
|
|
143
|
-
var query = $('#search')
|
|
144
|
-
.val()
|
|
145
|
-
.replace(/[^0-9a-z\s]/gi, '')
|
|
146
|
-
.replace(/\s+/gi, '+');
|
|
147
|
-
|
|
148
|
-
if (type === 'ai') element.open();
|
|
149
|
-
});
|
|
150
|
-
});
|
|
151
|
-
})(jQuery);
|
|
152
|
-
";
|
|
153
|
-
CurrentContext.Page.Scripts.AddInline(custom, ScriptLocation.BodyEnd);
|
|
154
|
-
}
|
|
109
|
+
```javascript
|
|
110
|
+
const element = document.getElementById('ai-search');
|
|
111
|
+
const input = document.getElementById('search');
|
|
112
|
+
|
|
113
|
+
input.addEventListener('keydown', (e) => {
|
|
114
|
+
if (e.key === 'Enter') {
|
|
115
|
+
e.preventDefault();
|
|
116
|
+
element.open(input.value.trim());
|
|
117
|
+
}
|
|
118
|
+
});
|
|
155
119
|
```
|
|
156
120
|
|
|
157
|
-
###
|
|
121
|
+
### Attributes
|
|
158
122
|
|
|
159
123
|
| Attribute | Required | Description |
|
|
160
124
|
|-----------|----------|-------------|
|
|
@@ -162,8 +126,8 @@ To integrate with an existing search form (e.g. a dropdown with search types), y
|
|
|
162
126
|
| `project-id` | Yes | Project identifier for the RAG API |
|
|
163
127
|
| `sections` | No | Comma-separated section slugs to scope results |
|
|
164
128
|
| `dev-mode` | No | Enable mock responses for development (no backend needed) |
|
|
165
|
-
| `theme` | No | Custom CSS string injected into the Shadow DOM |
|
|
166
|
-
| `suggestions-position` | No | `"above"` (default) or `"below"` — position of
|
|
129
|
+
| `theme` | No | Custom CSS string injected into the Shadow DOM (use `.insytful-root` to set [CSS custom properties](#css-custom-properties)) |
|
|
130
|
+
| `suggestions-position` | No | `"above"` (default) or `"below"` — position of suggestion chips relative to the input field |
|
|
167
131
|
|
|
168
132
|
### Slots
|
|
169
133
|
|
|
@@ -173,7 +137,7 @@ To integrate with an existing search form (e.g. a dropdown with search types), y
|
|
|
173
137
|
| `title` | Heading text for the empty state |
|
|
174
138
|
| `description` | Subheading text below the title |
|
|
175
139
|
| `disclaimer` | Footer text (e.g. AI accuracy warning) |
|
|
176
|
-
| `logo` |
|
|
140
|
+
| `logo` | Image shown in the dialog empty state (not in messages) |
|
|
177
141
|
| `avatar` | Image shown next to AI responses and the typing indicator |
|
|
178
142
|
|
|
179
143
|
### Child Elements
|
|
@@ -182,8 +146,8 @@ To integrate with an existing search form (e.g. a dropdown with search types), y
|
|
|
182
146
|
<!-- Suggestion chips (shown before the first query) -->
|
|
183
147
|
<insytful-suggestion>How do I apply?</insytful-suggestion>
|
|
184
148
|
|
|
185
|
-
<!-- Close button (
|
|
186
|
-
Empty content uses the default
|
|
149
|
+
<!-- Close button (top-right inside the dialog).
|
|
150
|
+
Empty content uses the default X icon; or pass your own markup. -->
|
|
187
151
|
<insytful-close></insytful-close>
|
|
188
152
|
<insytful-close aria-label="Dismiss search">Cancel</insytful-close>
|
|
189
153
|
|
|
@@ -195,9 +159,9 @@ To integrate with an existing search form (e.g. a dropdown with search types), y
|
|
|
195
159
|
<insytful-mode name="classic" path="/search?q=">Classic Search</insytful-mode>
|
|
196
160
|
```
|
|
197
161
|
|
|
198
|
-
The close button lives
|
|
162
|
+
The **close button** lives inside the dialog (focus-trap-aware) and is styled via `--insytful-btn-close-*` variables.
|
|
199
163
|
|
|
200
|
-
The avatar appears next to each AI response and the typing indicator. On desktop it sits as a column beside the message; on mobile it floats left so the first line of text wraps beside it and subsequent content flows full width. Style the wrapper via `.insytful-search-message-logo` in your theme CSS. This is the Web Component equivalent of the React `logo` prop on `Root`.
|
|
164
|
+
The **avatar** appears next to each AI response and the typing indicator. On desktop it sits as a column beside the message; on mobile it floats left so the first line of text wraps beside it and subsequent content flows full width. Style the wrapper via `.insytful-search-message-logo` in your theme CSS. This is the Web Component equivalent of the React `logo` prop on `Root`.
|
|
201
165
|
|
|
202
166
|
### JavaScript API
|
|
203
167
|
|
|
@@ -205,7 +169,8 @@ The avatar appears next to each AI response and the typing indicator. On desktop
|
|
|
205
169
|
const element = document.querySelector('insytful-search');
|
|
206
170
|
|
|
207
171
|
// Open/close programmatically
|
|
208
|
-
element.open();
|
|
172
|
+
element.open(); // open the empty dialog
|
|
173
|
+
element.open('query'); // open and immediately send a query
|
|
209
174
|
element.close();
|
|
210
175
|
element.toggle();
|
|
211
176
|
|
|
@@ -232,9 +197,11 @@ If your site has a sticky header, add `data-insytful-modal-offset` so the dialog
|
|
|
232
197
|
<header data-insytful-modal-offset>Your sticky header</header>
|
|
233
198
|
```
|
|
234
199
|
|
|
200
|
+
The modal measures their combined height via `ResizeObserver` and adjusts its `top` offset.
|
|
201
|
+
|
|
235
202
|
---
|
|
236
203
|
|
|
237
|
-
## React
|
|
204
|
+
## React Components
|
|
238
205
|
|
|
239
206
|
Radix-style compound components for React applications.
|
|
240
207
|
|
|
@@ -281,16 +248,16 @@ function App() {
|
|
|
281
248
|
### Architecture
|
|
282
249
|
|
|
283
250
|
```
|
|
284
|
-
InsytfulSearch.Root
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
251
|
+
InsytfulSearch.Root -- Context provider (lives in your DOM tree)
|
|
252
|
+
+-- InsytfulSearch.Trigger -- Toggle button (place anywhere in your DOM)
|
|
253
|
+
+-- InsytfulSearch.Portal -- Shadow DOM dialog (portalled to document.body)
|
|
254
|
+
+-- InsytfulSearch.Close -- Close button (top-right; optional)
|
|
255
|
+
+-- InsytfulSearch.Title
|
|
256
|
+
+-- InsytfulSearch.Description
|
|
257
|
+
+-- InsytfulSearch.Input
|
|
258
|
+
+-- InsytfulSearch.Messages
|
|
259
|
+
+-- InsytfulSearch.Suggestions
|
|
260
|
+
+-- InsytfulSearch.Disclaimer
|
|
294
261
|
```
|
|
295
262
|
|
|
296
263
|
`Root` lives in the consumer's DOM so components like `Trigger` can be placed anywhere (e.g. in a site header). `Portal` creates the Shadow DOM boundary for the modal dialog.
|
|
@@ -355,7 +322,7 @@ Toggles the modal. Renders a `<button>` by default, or merges props onto your ch
|
|
|
355
322
|
|
|
356
323
|
#### `InsytfulSearch.Close`
|
|
357
324
|
|
|
358
|
-
Closes the modal. Place inside `InsytfulSearch.Portal` so the focus trap includes it. Renders a top-right
|
|
325
|
+
Closes the modal. Place inside `InsytfulSearch.Portal` so the focus trap includes it. Renders a top-right X button styled via `--insytful-btn-close-*` tokens; pass children to override the icon, or `asChild` to merge props onto your own element.
|
|
359
326
|
|
|
360
327
|
```tsx
|
|
361
328
|
<InsytfulSearch.Portal>
|
|
@@ -368,7 +335,7 @@ Closes the modal. Place inside `InsytfulSearch.Portal` so the focus trap include
|
|
|
368
335
|
|
|
369
336
|
{/* Or your own button element */}
|
|
370
337
|
<InsytfulSearch.Close asChild>
|
|
371
|
-
<button
|
|
338
|
+
<button aria-label="Dismiss">x</button>
|
|
372
339
|
</InsytfulSearch.Close>
|
|
373
340
|
</InsytfulSearch.Portal>
|
|
374
341
|
```
|
|
@@ -418,6 +385,24 @@ Displays the AI conversation thread with auto-scroll, typing indicator, gradient
|
|
|
418
385
|
<InsytfulSearch.Messages className="px-4" />
|
|
419
386
|
```
|
|
420
387
|
|
|
388
|
+
#### `InsytfulSearch.ErrorCallout`
|
|
389
|
+
|
|
390
|
+
Renders an error callout when the AI search fails. Place it conditionally based on the `error` state from `useSearchContext`. Optionally includes a "Try classic?" button to switch modes.
|
|
391
|
+
|
|
392
|
+
```tsx
|
|
393
|
+
const { error } = InsytfulSearch.useSearchContext('MyComponent');
|
|
394
|
+
|
|
395
|
+
{error && <InsytfulSearch.ErrorCallout />}
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
| Prop | Type | Description |
|
|
399
|
+
|------|------|-------------|
|
|
400
|
+
| `onSwitchClassic` | `() => void` | Optional callback to switch to classic search mode. When provided, renders a "Try classic?" button. |
|
|
401
|
+
|
|
402
|
+
Styled via `--insytful-callout-error-border`, `--insytful-callout-error-bg`, and `--insytful-callout-error-text` CSS variables.
|
|
403
|
+
|
|
404
|
+
> **Web Component:** The error callout is built-in and renders automatically when the RAG API fails. The "Try classic?" button appears when a classic mode with a `path` is configured. No consumer code needed.
|
|
405
|
+
|
|
421
406
|
#### `InsytfulSearch.Suggestions`
|
|
422
407
|
|
|
423
408
|
Clickable suggestion chips. Clicking sends the suggestion text via context `onSend`.
|
|
@@ -452,14 +437,10 @@ Switch between AI search and classic (URL-based) search:
|
|
|
452
437
|
<InsytfulSearch.Modes defaultValue="ai">
|
|
453
438
|
<InsytfulSearch.ModeSwitch>
|
|
454
439
|
{({ mode, onSwitch }) => (
|
|
455
|
-
|
|
456
|
-
<button onClick={() => onSwitch('ai')}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
<button onClick={() => onSwitch('classic')} className={mode === 'classic' ? 'active' : ''}>
|
|
460
|
-
Classic Search
|
|
461
|
-
</button>
|
|
462
|
-
</div>
|
|
440
|
+
<>
|
|
441
|
+
<button onClick={() => onSwitch('ai')}>AI Search</button>
|
|
442
|
+
<button onClick={() => onSwitch('classic')}>Classic Search</button>
|
|
443
|
+
</>
|
|
463
444
|
)}
|
|
464
445
|
</InsytfulSearch.ModeSwitch>
|
|
465
446
|
|
|
@@ -516,13 +497,13 @@ For advanced usage, the library exports context hooks:
|
|
|
516
497
|
```tsx
|
|
517
498
|
import { InsytfulSearch } from 'insytful-ai-search-components';
|
|
518
499
|
|
|
519
|
-
// Inside a Search.Root descendant
|
|
500
|
+
// Inside a Search.Root descendant -- throws if used outside Root
|
|
520
501
|
const { messages, loading, onSend, open } = InsytfulSearch.useSearchContext('MyComponent');
|
|
521
502
|
|
|
522
|
-
// Inside a Search.Modes descendant
|
|
503
|
+
// Inside a Search.Modes descendant -- throws if used outside Modes
|
|
523
504
|
const { mode, onSwitchMode } = InsytfulSearch.useModeContext('MyComponent');
|
|
524
505
|
|
|
525
|
-
// Safe variant
|
|
506
|
+
// Safe variant -- returns null if not inside Search.Modes
|
|
526
507
|
const modeCtx = InsytfulSearch.useModeContextSafe();
|
|
527
508
|
```
|
|
528
509
|
|
|
@@ -538,72 +519,9 @@ import theme from './my-theme.css?inline';
|
|
|
538
519
|
<InsytfulSearch.Root theme={theme} options={...}>
|
|
539
520
|
```
|
|
540
521
|
|
|
541
|
-
> **Security note:** The `theme` prop injects raw CSS into the Shadow DOM. Only pass trusted, developer-authored CSS
|
|
542
|
-
|
|
543
|
-
#### CSS Custom Properties
|
|
522
|
+
> **Security note:** The `theme` prop injects raw CSS into the Shadow DOM. Only pass trusted, developer-authored CSS -- never user-generated content.
|
|
544
523
|
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
```css
|
|
548
|
-
:host {
|
|
549
|
-
/* Typography */
|
|
550
|
-
--insytful-font-family: system-ui, -apple-system, sans-serif;
|
|
551
|
-
|
|
552
|
-
/* Text */
|
|
553
|
-
--insytful-text-default: #333333;
|
|
554
|
-
--insytful-text-muted: #6c6c6c;
|
|
555
|
-
--insytful-text-link-default: #1d70b8;
|
|
556
|
-
--insytful-text-link-hover: #184b76;
|
|
557
|
-
--insytful-typing-indicator-text: var(--insytful-text-muted);
|
|
558
|
-
--insytful-disclaimer-text: var(--insytful-text-muted);
|
|
559
|
-
|
|
560
|
-
/* Brand */
|
|
561
|
-
--insytful-brand-primary: #195491;
|
|
562
|
-
|
|
563
|
-
/* Modal surface */
|
|
564
|
-
--insytful-modal-bg: #ffffff;
|
|
565
|
-
--insytful-modal-max-width: 784px;
|
|
566
|
-
--insytful-modal-radius: 0px;
|
|
567
|
-
|
|
568
|
-
/* Suggestion buttons */
|
|
569
|
-
--insytful-btn-prompt-bg-default: #e2eefa;
|
|
570
|
-
--insytful-btn-prompt-bg-hover: #c8daec;
|
|
571
|
-
--insytful-btn-prompt-text: #333333;
|
|
572
|
-
--insytful-btn-prompt-radius: 12px;
|
|
573
|
-
--insytful-btn-prompt-focus: var(--insytful-semantic-search-field-focus);
|
|
574
|
-
|
|
575
|
-
/* Input card */
|
|
576
|
-
--insytful-input-card-bg: #ffffff;
|
|
577
|
-
--insytful-input-card-radius: 16px;
|
|
578
|
-
--insytful-input-card-border: var(--insytful-semantic-search-field-stroke);
|
|
579
|
-
--insytful-input-card-border-width: 1px;
|
|
580
|
-
|
|
581
|
-
/* Send button */
|
|
582
|
-
--insytful-btn-icon-search-bg-default: #2e3339;
|
|
583
|
-
--insytful-btn-icon-search-bg-hover: #3c444d;
|
|
584
|
-
--insytful-btn-icon-search-icon: #ffffff;
|
|
585
|
-
|
|
586
|
-
/* Close button */
|
|
587
|
-
--insytful-btn-close-bg: transparent;
|
|
588
|
-
--insytful-btn-close-bg-hover: #f2f2f2;
|
|
589
|
-
--insytful-btn-close-icon: var(--insytful-text-default);
|
|
590
|
-
--insytful-btn-close-size: 40px;
|
|
591
|
-
|
|
592
|
-
/* Error callout */
|
|
593
|
-
--insytful-callout-error-border: #d93025;
|
|
594
|
-
--insytful-callout-error-bg: #fce8e6;
|
|
595
|
-
|
|
596
|
-
/* Search field */
|
|
597
|
-
--insytful-semantic-search-field-stroke: #333333;
|
|
598
|
-
--insytful-semantic-search-field-focus: #35d2c5;
|
|
599
|
-
|
|
600
|
-
/* Transitions */
|
|
601
|
-
--insytful-search-transition-duration: 200ms;
|
|
602
|
-
|
|
603
|
-
/* Z-index */
|
|
604
|
-
--insytful-z-index: 999;
|
|
605
|
-
}
|
|
606
|
-
```
|
|
524
|
+
See [CSS Custom Properties](#css-custom-properties) for the full list of theming tokens.
|
|
607
525
|
|
|
608
526
|
#### Dynamic Offsets
|
|
609
527
|
|
|
@@ -628,7 +546,7 @@ import ReactMarkdown from 'react-markdown';
|
|
|
628
546
|
>
|
|
629
547
|
```
|
|
630
548
|
|
|
631
|
-
> **Security note:** Your `renderMarkdown` implementation must sanitize output. AI responses are untrusted content
|
|
549
|
+
> **Security note:** Your `renderMarkdown` implementation must sanitize output. AI responses are untrusted content -- do not use `dangerouslySetInnerHTML` or enable raw HTML passthrough. Libraries like `react-markdown` are safe by default.
|
|
632
550
|
|
|
633
551
|
### TypeScript
|
|
634
552
|
|
|
@@ -645,6 +563,71 @@ import type {
|
|
|
645
563
|
} from 'insytful-ai-search-components';
|
|
646
564
|
```
|
|
647
565
|
|
|
566
|
+
---
|
|
567
|
+
|
|
568
|
+
## CSS Custom Properties
|
|
569
|
+
|
|
570
|
+
Both versions support the same theme variables. For the Web Component, set these on `.insytful-root` inside your `theme` attribute. For React, set them on `:host` inside your `theme` prop.
|
|
571
|
+
|
|
572
|
+
```css
|
|
573
|
+
/* Typography */
|
|
574
|
+
--insytful-font-family: system-ui, -apple-system, sans-serif;
|
|
575
|
+
|
|
576
|
+
/* Text */
|
|
577
|
+
--insytful-text-default: #333333;
|
|
578
|
+
--insytful-text-muted: #6c6c6c;
|
|
579
|
+
--insytful-text-link-default: #1d70b8;
|
|
580
|
+
--insytful-text-link-hover: #184b76;
|
|
581
|
+
--insytful-typing-indicator-text: var(--insytful-text-muted);
|
|
582
|
+
--insytful-disclaimer-text: var(--insytful-text-muted);
|
|
583
|
+
|
|
584
|
+
/* Brand */
|
|
585
|
+
--insytful-brand-primary: #195491;
|
|
586
|
+
|
|
587
|
+
/* Modal surface */
|
|
588
|
+
--insytful-modal-bg: #ffffff;
|
|
589
|
+
--insytful-modal-max-width: 784px;
|
|
590
|
+
--insytful-modal-radius: 0px;
|
|
591
|
+
|
|
592
|
+
/* Suggestion buttons */
|
|
593
|
+
--insytful-btn-prompt-bg-default: #e2eefa;
|
|
594
|
+
--insytful-btn-prompt-bg-hover: #c8daec;
|
|
595
|
+
--insytful-btn-prompt-text: #333333;
|
|
596
|
+
--insytful-btn-prompt-radius: 12px;
|
|
597
|
+
--insytful-btn-prompt-focus: var(--insytful-semantic-search-field-focus);
|
|
598
|
+
|
|
599
|
+
/* Input card */
|
|
600
|
+
--insytful-input-card-bg: #ffffff;
|
|
601
|
+
--insytful-input-card-radius: 16px;
|
|
602
|
+
--insytful-input-card-border: var(--insytful-semantic-search-field-stroke);
|
|
603
|
+
--insytful-input-card-border-width: 1px;
|
|
604
|
+
|
|
605
|
+
/* Send button */
|
|
606
|
+
--insytful-btn-icon-search-bg-default: #2e3339;
|
|
607
|
+
--insytful-btn-icon-search-bg-hover: #3c444d;
|
|
608
|
+
--insytful-btn-icon-search-icon: #ffffff;
|
|
609
|
+
|
|
610
|
+
/* Close button */
|
|
611
|
+
--insytful-btn-close-bg: transparent;
|
|
612
|
+
--insytful-btn-close-bg-hover: #f2f2f2;
|
|
613
|
+
--insytful-btn-close-icon: var(--insytful-text-default);
|
|
614
|
+
--insytful-btn-close-size: 40px;
|
|
615
|
+
|
|
616
|
+
/* Error callout */
|
|
617
|
+
--insytful-callout-error-border: #d93025;
|
|
618
|
+
--insytful-callout-error-bg: #fce8e6;
|
|
619
|
+
|
|
620
|
+
/* Search field */
|
|
621
|
+
--insytful-semantic-search-field-stroke: #333333;
|
|
622
|
+
--insytful-semantic-search-field-focus: #35d2c5;
|
|
623
|
+
|
|
624
|
+
/* Transitions */
|
|
625
|
+
--insytful-search-transition-duration: 200ms;
|
|
626
|
+
|
|
627
|
+
/* Z-index */
|
|
628
|
+
--insytful-z-index: 999;
|
|
629
|
+
```
|
|
630
|
+
|
|
648
631
|
## Accessibility
|
|
649
632
|
|
|
650
633
|
Both the React and Web Component versions share the same accessibility features:
|
|
@@ -656,36 +639,6 @@ Both the React and Web Component versions share the same accessibility features:
|
|
|
656
639
|
- `inert` attribute hides the dialog from assistive tech when closed
|
|
657
640
|
- Respects `prefers-reduced-motion` (transitions disabled)
|
|
658
641
|
|
|
659
|
-
## CSS Custom Properties
|
|
660
|
-
|
|
661
|
-
Both versions support the same theme variables. Override them in your custom CSS:
|
|
662
|
-
|
|
663
|
-
```css
|
|
664
|
-
:host {
|
|
665
|
-
--insytful-font-family: system-ui, -apple-system, sans-serif;
|
|
666
|
-
--insytful-text-default: #333333;
|
|
667
|
-
--insytful-text-muted: #6c6c6c;
|
|
668
|
-
--insytful-disclaimer-text: var(--insytful-text-muted);
|
|
669
|
-
--insytful-typing-indicator-text: var(--insytful-text-muted);
|
|
670
|
-
--insytful-brand-primary: #195491;
|
|
671
|
-
--insytful-modal-bg: #ffffff;
|
|
672
|
-
--insytful-modal-max-width: 784px;
|
|
673
|
-
--insytful-btn-prompt-bg-default: #e2eefa;
|
|
674
|
-
--insytful-btn-prompt-radius: 12px;
|
|
675
|
-
--insytful-input-card-bg: #ffffff;
|
|
676
|
-
--insytful-input-card-radius: 16px;
|
|
677
|
-
--insytful-input-card-border: var(--insytful-semantic-search-field-stroke);
|
|
678
|
-
--insytful-btn-icon-search-bg-default: #2e3339;
|
|
679
|
-
--insytful-btn-close-bg-hover: #f2f2f2;
|
|
680
|
-
--insytful-btn-close-icon: var(--insytful-text-default);
|
|
681
|
-
--insytful-semantic-search-field-focus: #35d2c5;
|
|
682
|
-
--insytful-search-transition-duration: 200ms;
|
|
683
|
-
--insytful-z-index: 999;
|
|
684
|
-
}
|
|
685
|
-
```
|
|
686
|
-
|
|
687
|
-
See the [full CSS Custom Properties](#css-custom-properties) section above for the complete token list with defaults.
|
|
688
|
-
|
|
689
642
|
## Browser Support
|
|
690
643
|
|
|
691
644
|
Modern browsers with [Shadow DOM v1](https://caniuse.com/shadowdomv1). Client-side rendering only (no SSR).
|