@helpai/elements 1.7.0 → 1.9.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.
@@ -0,0 +1,302 @@
1
+ # Browser support
2
+
3
+ ## Supported browsers
4
+
5
+ Baseline support matches modern evergreen browsers:
6
+
7
+ | Browser | Minimum version | Notes |
8
+ | ---------------- | --------------- | -------------------------- |
9
+ | Chrome / Edge | 100 | Released April 2022 |
10
+ | Firefox | 100 | Released May 2022 |
11
+ | Safari | 15 | macOS Big Sur + / iOS 15 + |
12
+ | Opera | 86 | Chromium-based |
13
+ | Samsung Internet | 17 | Android |
14
+
15
+ Chromium-based browsers (Brave, Vivaldi, Arc, DuckDuckGo Browser)
16
+ work if their underlying Chromium version is ≥ 100.
17
+
18
+ ## Explicitly not supported
19
+
20
+ - **Internet Explorer** (any version).
21
+ - **Legacy Edge** (pre-Chromium, EdgeHTML).
22
+ - **Opera Mini** (proxy-rendered, no JS).
23
+ - **UC Browser** (ancient WebKit fork).
24
+
25
+ If you need to support IE or similar, the widget won't render. Detect
26
+ and show a fallback contact form:
27
+
28
+ ```js
29
+ const supportsWidget = 'attachShadow' in Element.prototype && 'fetch' in window && typeof ReadableStream === 'function';
30
+
31
+ if (!supportsWidget) {
32
+ document.getElementById('legacy-contact').style.display = 'block';
33
+ }
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Features used
39
+
40
+ The widget relies on:
41
+
42
+ | API | Feature detection | Why |
43
+ | ------------------------------ | ---------------------------------------------- | ----------------------------------------------------------------- |
44
+ | Shadow DOM (`attachShadow`) | `'attachShadow' in Element.prototype` | Widget rendering isolation |
45
+ | Custom Elements | `typeof customElements` | `<web-ai-chat>` element |
46
+ | Constructable Stylesheets | `'adoptedStyleSheets' in ShadowRoot.prototype` | Efficient CSS adoption (falls back to `<style>`) |
47
+ | ES Modules | Native | NPM + web-component sub-entry |
48
+ | `fetch` | Native | API calls |
49
+ | `ReadableStream` | Native | Streaming responses |
50
+ | `TextDecoder` / `TextEncoder` | Native | SSE frame parsing |
51
+ | Async generators (`for await`) | Native | Stream consumers |
52
+ | CSS custom properties | `:root { --var: ... }` | Theming |
53
+ | CSS `contain: size` | Supported everywhere we support | Inline-mode layout containment |
54
+ | `IntersectionObserver` | Native | Auto-scroll behaviour |
55
+ | `matchMedia` | Native | `prefers-color-scheme`, `prefers-reduced-motion`, touch detection |
56
+ | `MediaRecorder` | Feature-detected | Voice input (server mode) |
57
+ | Web Speech API | Feature-detected | Voice input (local mode) |
58
+ | `navigator.vibrate` | Feature-detected | Haptic feedback (Android) |
59
+ | `AudioContext` | Feature-detected | Sound effects |
60
+
61
+ Features marked "Feature-detected" gracefully degrade when unavailable
62
+ — e.g., on iOS 17.3 and below, `navigator.vibrate` is missing, so
63
+ haptics silently no-op.
64
+
65
+ ---
66
+
67
+ ## Mobile specifics
68
+
69
+ ### iOS Safari
70
+
71
+ - **Full support** on iOS 15+.
72
+ - **Haptics** — WebKit doesn't expose `navigator.vibrate`. We use a
73
+ programmatic `<input type="checkbox" switch>` click on iOS 17.4+ to
74
+ trigger a single haptic tick. Custom patterns flatten to one tick.
75
+ - **Voice (local)** — `SpeechRecognition` is available but quality
76
+ varies. Recommend `features.voice: "server"` for production.
77
+ - **Keyboard avoidance** — when the on-screen keyboard appears, the
78
+ panel auto-adjusts to stay visible.
79
+ - **Text-entry focus** — the composer, Help search, and form/HITL fields keep a
80
+ minimum 16px computed font on touch devices so focusing them does not trigger
81
+ iOS page zoom. Each uses its existing border as the single focus indicator.
82
+ - **Viewport units** — we use `dvh` where supported (iOS 16+) and
83
+ fall back to `vh` below.
84
+
85
+ ### Android Chrome
86
+
87
+ - **Full support**.
88
+ - **Haptics** — `navigator.vibrate` supports both single and pattern
89
+ vibrations.
90
+ - **Voice (local)** — Web Speech works well.
91
+
92
+ ### Samsung Internet + other Android browsers
93
+
94
+ - **Samsung Internet 17+** — Chromium-based, full support.
95
+ - **Firefox Android** — tested and working.
96
+ - **Brave / DuckDuckGo** — Chromium-based, work identically to Chrome.
97
+
98
+ ---
99
+
100
+ ## Accessibility
101
+
102
+ ### Keyboard navigation
103
+
104
+ - **Tab** rotates through all interactive elements (launcher, header
105
+ buttons, menu items, textarea, send, history rows).
106
+ - **Shift+Tab** reverses.
107
+ - **Enter / Space** on the launcher opens the panel.
108
+ - **Escape** closes the panel (or exits fullscreen in inline mode).
109
+ - **Arrow Up / Down** navigates within popover menus.
110
+ - **Home / End** jump to first / last menu item.
111
+ - **Enter** on a menu item selects.
112
+
113
+ ### Screen readers
114
+
115
+ - Every icon-only button has an `aria-label`.
116
+ - Popover menus use `role="menu"` + `role="menuitem"` with proper
117
+ `aria-haspopup` + `aria-expanded`.
118
+ - Switch-style actions carry `aria-pressed`.
119
+ - Active language / theme options use `aria-current="true"`.
120
+ - The panel is a `role="dialog"` with `aria-modal="false"`
121
+ (non-blocking) and focus trap.
122
+
123
+ ### `prefers-reduced-motion`
124
+
125
+ When the user has motion reduced:
126
+
127
+ - Launcher callout animations disabled.
128
+ - Panel open/close animations shortened.
129
+ - Haptic feedback disabled.
130
+ - Sound volume halved.
131
+
132
+ ### `prefers-color-scheme`
133
+
134
+ The default theme mode is `"auto"` — follows the OS preference.
135
+ Users can override via the in-widget theme picker.
136
+
137
+ ### Touch vs pointer
138
+
139
+ The widget detects touch capability via
140
+ `matchMedia("(hover: none) and (pointer: coarse)")` and enables
141
+ haptics only on touch devices. Desktop users with mice never get
142
+ vibration prompts.
143
+
144
+ ---
145
+
146
+ ## Feature-detection code
147
+
148
+ If you want to check for widget compatibility before installing:
149
+
150
+ ```js
151
+ function helpaiSupported() {
152
+ if (typeof window === 'undefined') return false;
153
+ if (!('customElements' in window)) return false;
154
+ if (!('attachShadow' in Element.prototype)) return false;
155
+ if (!('fetch' in window)) return false;
156
+ if (typeof ReadableStream !== 'function') return false;
157
+ if (typeof Promise !== 'function') return false;
158
+ return true;
159
+ }
160
+
161
+ if (helpaiSupported()) {
162
+ // Load the widget
163
+ const s = document.createElement('script');
164
+ s.src = 'https://cdn.help.ai/sdk/js/elements/latest/elements.js';
165
+ s.setAttribute('data-public-key', 'agent_pk_...');
166
+ s.setAttribute('data-ai-agent-deployment-id', '01900000-0000-7000-8000-000000000000');
167
+ s.defer = true;
168
+ document.head.appendChild(s);
169
+ } else {
170
+ // Show fallback
171
+ document.getElementById('legacy-chat-fallback').style.display = 'block';
172
+ }
173
+ ```
174
+
175
+ ---
176
+
177
+ ## Polyfills
178
+
179
+ We don't ship any — the feature set is chosen so that every supported
180
+ browser has native implementations.
181
+
182
+ If you need to support an older browser via your own polyfills
183
+ (`core-js`, `whatwg-fetch`, etc.), the widget should work, but we
184
+ don't test this path. File an issue if something breaks and we'll
185
+ look.
186
+
187
+ ---
188
+
189
+ ## Performance targets
190
+
191
+ On a mid-tier laptop (M1 MacBook Air, 2020):
192
+
193
+ | Metric | Target | Measured (current) |
194
+ | ------------------------------------ | -------- | ------------------ |
195
+ | Bundle download (gzipped) | < 110 KB | ~107 KB |
196
+ | First byte to first bubble painted | < 200ms | ~150ms |
197
+ | Time to interactive (first open) | < 1s | ~600ms |
198
+ | Per-token stream render latency | < 5ms | ~2ms |
199
+ | Panel close → FAB visible transition | < 200ms | ~180ms |
200
+
201
+ On a 2019 Android mid-range (Galaxy A30):
202
+
203
+ | Metric | Target | Measured |
204
+ | ---------------------------------- | ------- | -------- |
205
+ | First byte to first bubble painted | < 500ms | ~350ms |
206
+ | Time to interactive (first open) | < 2s | ~1.1s |
207
+
208
+ We run Lighthouse audits on every release; the widget never regresses
209
+ the host page's performance score by more than 2 points.
210
+
211
+ ---
212
+
213
+ ## Degraded modes
214
+
215
+ ### Offline
216
+
217
+ - If the bundle is cached, the widget renders.
218
+ - Attempting to send fires an `error` event. Listen to provide a
219
+ fallback:
220
+ ```ts
221
+ init({
222
+ onError: (err) => {
223
+ if (!navigator.onLine) {
224
+ alert('You appear to be offline. Please try again later.');
225
+ }
226
+ },
227
+ });
228
+ ```
229
+ - Cached chats remain viewable.
230
+ - When the connection returns, the widget continues working
231
+ automatically.
232
+
233
+ ### Slow networks
234
+
235
+ - The streaming pipeline is resilient to per-frame delays.
236
+ - If the stream gets stuck, the user sees a "thinking…" indicator.
237
+ - User can click Stop to abort and retry.
238
+
239
+ ### No localStorage (private mode on some browsers)
240
+
241
+ - The widget falls back to a no-op storage adapter (writes succeed
242
+ but don't persist).
243
+ - Chat history doesn't persist across reloads.
244
+ - Everything else works.
245
+
246
+ ### Old browsers
247
+
248
+ - The widget shows nothing (custom elements / shadow DOM aren't
249
+ available). Your page renders normally; the widget is just absent.
250
+ - Feature-detect if you want to show a fallback.
251
+
252
+ ---
253
+
254
+ ## Device form factors
255
+
256
+ Tested on:
257
+
258
+ - **Desktop** (1280×720 minimum — smaller works but cramped in
259
+ floating mode).
260
+ - **Tablet** (iPad landscape/portrait, Android tablets).
261
+ - **Mobile** (360×640 minimum — iPhone SE, Android Pixel).
262
+ - **Foldable** (Galaxy Z Fold — adapts via `matchMedia`).
263
+
264
+ Responsive behavior:
265
+
266
+ - `initialSize: "auto"` expands the panel on wide viewports
267
+ (`≥ autoSizeBreakpoint`, default 900px).
268
+ - Below the breakpoint, the panel defaults to a phone-friendly
269
+ compact size.
270
+
271
+ ---
272
+
273
+ ## Known limitations
274
+
275
+ - **iOS Safari viewport units** — we use `dvh` when supported (iOS
276
+ 16+). On older iOS, use `100vh` fallback may over-expand by the
277
+ browser chrome height.
278
+ - **Android haptics vary by device** — OEM customizations (Samsung,
279
+ Xiaomi) sometimes override or weaken `navigator.vibrate`. Not
280
+ much we can do.
281
+ - **Firefox streaming markdown** — Firefox's `streaming-markdown`
282
+ runs ~5% slower than Chromium on long streams. Imperceptible unless
283
+ streaming tens of thousands of tokens.
284
+ - **Dark reader extensions** — "Dark Reader" (the popular dark-mode
285
+ browser extension) can invert the widget's colors even in dark
286
+ mode. Workaround: users disable Dark Reader for your site.
287
+
288
+ ---
289
+
290
+ ## Reporting compatibility issues
291
+
292
+ Found a browser where the widget misbehaves? Please file an issue
293
+ with:
294
+
295
+ - Browser name + version.
296
+ - OS + version.
297
+ - Device type (desktop / mobile / tablet).
298
+ - Steps to reproduce.
299
+ - Screenshot or screen recording.
300
+ - Console output.
301
+
302
+ [github.com/help-ai/elements/issues](https://github.com/help-ai/elements/issues)