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 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-setup)** — 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-setup)** — Radix-style compound components for React applications. Install via npm.
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 Setup
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 (C# / Razor)
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
- :host {
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
- <!-- Insytful AI Search Web Component -->
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" class="search-trigger">Search this site</button>
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
- <!-- Avatar shown next to AI responses -->
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 integrate with an existing search form (e.g. a dropdown with search types), you can open the AI search dialog programmatically when the user selects "AI Search":
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
- <insytful-suggestion>How do I apply?</insytful-suggestion>
120
- <insytful-suggestion>What courses do you offer?</insytful-suggestion>
121
- </insytful-search>
122
-
123
- <script src="https://unpkg.com/insytful-ai-search-components@2.1.0/dist/insytful-search.js"></script>
124
- ```
125
-
126
- ```cshtml
127
- @{
128
- string custom = @"
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
- ### Web Component Attributes
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 the suggestion chips relative to the input field |
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` | Logo image shown in the dialog empty state |
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 (renders a top-right inside the dialog).
186
- Empty content uses the default icon; or pass your own markup. -->
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 **inside the dialog** (so the focus trap includes it) and is styled via the `--insytful-btn-close-*` CSS variables.
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 Setup
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 Context provider (lives in your DOM tree)
285
- ├── InsytfulSearch.Trigger Toggle button (place anywhere in your DOM)
286
- └── InsytfulSearch.Portal Shadow DOM dialog (portalled to document.body)
287
- ├── InsytfulSearch.Close Close button (top-right; optional)
288
- ├── InsytfulSearch.Title
289
- ├── InsytfulSearch.Description
290
- ├── InsytfulSearch.Input
291
- ├── InsytfulSearch.Messages
292
- ├── InsytfulSearch.Suggestions
293
- └── InsytfulSearch.Disclaimer
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 button styled via `--insytful-btn-close-*` tokens; pass children to override the icon, or `asChild` to merge props onto your own element.
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 className="my-close-btn" aria-label="Dismiss">×</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
- <div className="tabs">
456
- <button onClick={() => onSwitch('ai')} className={mode === 'ai' ? 'active' : ''}>
457
- AI Search
458
- </button>
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 throws if used outside Root
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 throws if used outside Modes
503
+ // Inside a Search.Modes descendant -- throws if used outside Modes
523
504
  const { mode, onSwitchMode } = InsytfulSearch.useModeContext('MyComponent');
524
505
 
525
- // Safe variant returns null if not inside Search.Modes
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 never user-generated content.
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
- Override these variables in your theme CSS to change colours:
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 do not use `dangerouslySetInnerHTML` or enable raw HTML passthrough. Libraries like `react-markdown` are safe by default.
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).