@aiden-voice/widget 0.5.3 → 0.7.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/README.md CHANGED
@@ -102,8 +102,11 @@ throws synchronously, at call time, if you pass both or neither.
102
102
  | `inkColor` | Body text color (chat title and replies). Darkened automatically if needed to stay readable. Overrides the color configured in whoo-aiden; omit it to use that one. | whoo-aiden's, else `'#111111'` |
103
103
  | `accentColor` | Link color in replies. Darkened automatically if needed to stay readable. Overrides the color configured in whoo-aiden; omit it to use that one. | whoo-aiden's, else `'#0000ee'` |
104
104
  | `name` | Agent name for the panel header and the dialog's screen-reader label ("Chat with {name}"). Overrides the name configured in whoo-aiden; omit it to use that one. | whoo-aiden's, else `'Aiden'` |
105
+ | `title` | Full panel title, used for the header heading and the dialog's screen-reader label. Replaces the whole "Chat with {name}" string (e.g. `'Ask our concierge'`), with surrounding whitespace trimmed; the agent's messages are still labelled with its name. A blank value is ignored. | `'Chat with {name}'` |
105
106
  | `greeting` | Welcome text shown in the panel before the first message. | none |
106
- | `launcherIconUrl` | Image shown on the launcher bubble instead of the default chat icon. `https:` or `data:image/` only. Until it loads, and permanently if it fails, the default icon shows. | none (default icon) |
107
+ | `launcherIconUrl` | Image shown on the launcher bubble instead of the default chat icon. `https:` or `data:image/` only. Until it loads, and permanently if it fails, the default icon shows. Alias of `theme.launcher.iconUrl`. | none (default icon) |
108
+ | `theme` | Colors, font and launcher icons. See [Theming](#theming). | defaults |
109
+ | `layout` | Launcher position and size, and panel size. See [Layout](#layout). | defaults |
107
110
  | `emptyStateImageUrl` | Image (e.g. a brand lockup) shown above the greeting while the conversation is empty. `https:` or `data:image/` only. Removed if it fails to load. | none |
108
111
  | `emptyStateImageAlt` | Alt text for `emptyStateImageUrl`. Set it when the image carries meaning (e.g. your brand name); omit it for a purely decorative image. | none (decorative) |
109
112
  | `showFeedback` | Show thumbs up/down controls under each reply so visitors can rate answers (a thumbs-down opens an optional correction form). | `false` (hidden) |
@@ -114,6 +117,82 @@ throws synchronously, at call time, if you pass both or neither.
114
117
 
115
118
  Some third-party overlays (accessibility toolbars, chat or cookie widgets) sit at the maximum possible z-index, `2147483647`, in the same corner. No `zIndex` value can beat that: at an equal level, whichever element comes later in the page wins, and those overlays are usually injected after the widget. Move the widget to the other corner with `position: 'bottom-left'` instead.
116
119
 
120
+ ## Theming
121
+
122
+ `color`, `inkColor` and `accentColor` set the brand colors, and the widget calculates the rest (the text on your color, the header text, and so on) so everything stays readable. When an edge case breaks that, the `theme` option overrides any individual color, the font, and the launcher icons.
123
+
124
+ ```js
125
+ init({
126
+ publishableKey: 'pk_live_...',
127
+ theme: {
128
+ colors: {
129
+ // A dark theme: every surface is overridden together with the roles drawn on it.
130
+ primary: '#0a7d5a',
131
+ onPrimary: '#ffffff', // text on `primary`; calculated if you leave it out
132
+ panel: '#0f172a',
133
+ border: '#334155',
134
+ headerHover: '#1e293b',
135
+ primaryText: '#f1f5f9', // header buttons, on `panel` and `headerHover`
136
+ text: '#f8fafc', // inputs and feedback buttons
137
+ focusRing: '#f8fafc', // keyboard focus outline, on `panel`
138
+ assistantBubble: '#1e293b',
139
+ ink: '#f8fafc',
140
+ link: '#7dd3fc',
141
+ muted: '#cbd5e1',
142
+ },
143
+ fonts: { family: '"Inter", system-ui, sans-serif' },
144
+ launcher: { icon: 'sparkle', openIcon: 'close' },
145
+ },
146
+ })
147
+ ```
148
+
149
+ **Colors.** An override is used exactly as you give it: the widget does not darken it or fix its contrast, and only logs a `console.warn` when the contrast looks too low. You own the result for every role you override. An unusable value (a typo, `currentColor`, a CSS variable) is ignored with a warning and the calculated color is used instead. A role you don't set keeps the widget's calculated color. `theme.colors.primary`, `.ink` and `.link` beat `color`, `inkColor` and `accentColor`, which beat the agent's colors configured in whoo-aiden.
150
+
151
+ | Role | What it colors | Default |
152
+ | --- | --- | --- |
153
+ | `primary` | Launcher, your visitor's bubbles, Send and Submit buttons | `#4f46e5` |
154
+ | `onPrimary` | Text and icons on `primary` | black or white, whichever reads best |
155
+ | `primaryText` | `primary` used as text on the panel (header controls) | `primary`, darkened until readable |
156
+ | `ink` | Header title and replies | `#111111` |
157
+ | `link` | Links in replies | `#0000ee` |
158
+ | `text` | Form-control and feedback-button text | `#111111` |
159
+ | `panel` | Panel background | `#ffffff` |
160
+ | `border` | Dividers | `#e5e5e5` |
161
+ | `headerHover` | Header control hover fill | `#f3f4f6` |
162
+ | `assistantBubble` | Reply bubble background | `#f0f0f0` |
163
+ | `muted` | Secondary text on replies | `#4b5563` |
164
+ | `typingDots` | "Waiting for a reply" dots | `#6b7280` |
165
+ | `errorBackground`, `errorText` | Error banner | `#fee2e2`, `#991b1b` |
166
+ | `inputBorder` | Input and form borders | `#6b7280` |
167
+ | `focusRing` | Dark tone of the keyboard focus outline | `#111827` |
168
+
169
+ If you override a surface (`panel`, `assistantBubble`, ...), also override the roles drawn on it: the defaults are made for the default surfaces, and an override of one is never adjusted to fit another. The roles drawn on each surface are `panel`: `primaryText`, `text`, `focusRing`, `border`, `inputBorder`; `headerHover`: `primaryText`; `assistantBubble`: `ink`, `link`, `muted`, `typingDots`, `text`; `errorBackground`: `errorText`. (The example above leaves `inputBorder`, `typingDots` and the error colors at their defaults, which already read well on it.)
170
+
171
+ **Fonts.** `theme.fonts.family` takes a CSS font-family stack. The widget never loads fonts, so the font must already be available: a system font, or one your page loads (a Google Fonts `<link>`, or your own `@font-face`). A stack that is over 200 characters or contains `url(`, `@`, `;`, `{`, `}` or `\` is ignored with a warning.
172
+
173
+ **Launcher icons.** `theme.launcher.icon` picks a built-in icon for the closed launcher (`'chat'`, `'message'`, `'sparkle'`); `theme.launcher.openIcon` picks the open one (`'chevron-down'`, `'close'`). `theme.launcher.iconUrl` and `theme.launcher.openIconUrl` show your own image instead (`https:` or `data:image/` only; the built-in icon shows until the image loads, and for good if it fails).
174
+
175
+ ## Layout
176
+
177
+ `position` picks the corner. `layout` fine-tunes where the launcher sits and how big the launcher and panel are. All values are in px.
178
+
179
+ ```js
180
+ init({
181
+ publishableKey: 'pk_live_...',
182
+ position: 'bottom-right',
183
+ layout: {
184
+ offset: { x: 24, y: 96 }, // distance from the chosen corner (default 20, 20)
185
+ launcherSize: 64, // launcher diameter, 24-120 (default 56)
186
+ panel: { width: 420, height: 640 }, // preferred panel size (default 360×480, minimum 280×320)
187
+ },
188
+ })
189
+ ```
190
+
191
+ - The launcher can't be moved off-screen, and not so far from its corner that the chat panel loses its room: an offset that doesn't leave space for the launcher and a minimum-size panel is held back (a warning is logged if that applies when the page loads). A smaller offset than the 20px default is always honored.
192
+ - A `launcherSize` outside 24-120 is clamped (the 24px floor is WCAG 2.2's minimum target size).
193
+ - The panel is always placed above the launcher, whatever its size or offset, and is capped to the viewport. `panel` is a preferred size: it can never run past the screen, and on very small screens (a viewport 400px wide or less, or 420px tall or less) it fills the viewport as before. A `panel.width` or `panel.height` below 280×320 is raised to that minimum, with a warning.
194
+ - A value that isn't a non-negative number is ignored with a warning and the default is used.
195
+
117
196
  ## Theme helper
118
197
 
119
198
  `resolveTheme` (npm package only) returns the exact colors the widget will render for a set of brand colors, the same computation the widget runs internally. Use it to preview branding without mounting the widget:
@@ -129,6 +208,19 @@ const theme = resolveTheme({ color: '#3b82f6', inkColor: '#1f2937', accentColor:
129
208
  // opaque look over white doesn't count.
130
209
  ```
131
210
 
211
+ `resolveTheme` also accepts `overrides`, the same per-role object as `theme.colors`, and returns three more fields:
212
+
213
+ ```ts
214
+ const dark = resolveTheme({ overrides: { panel: '#0f172a', ink: '#f8fafc' } })
215
+ // dark.roles: every color the widget renders, by role (all 16 of them).
216
+ // dark.overridden: which roles came from `overrides`.
217
+ // dark.contrastWarnings: overridden roles whose contrast against the surface
218
+ // they are drawn on is below 4.5:1 (text) or 3:1 (icons, borders, focus ring),
219
+ // each with { role, against, value, ratio, required }.
220
+ ```
221
+
222
+ An override is never adjusted (an opaque one is only normalized to `#rrggbb`). In particular a *translucent* override (`rgba(…, 0.5)`, `#rrggbbaa`) is kept as given, not flattened to its look over white the way `color` is, so a translucent `primary` or `panel` is see-through over the host page, and the host owns the result. `resolveTheme` never logs; read `contrastWarnings` instead.
223
+
132
224
  It needs a DOM (a browser, or jsdom in tests).
133
225
 
134
226
  ## Versions
@@ -159,26 +251,34 @@ version it needs exists — don't pre-embed `/v1/` in anticipation of a `1.0.0`
159
251
 
160
252
  ## Releasing
161
253
 
162
- Releases are tag-driven via `.github/workflows/release.yml` (the `Release`
163
- workflow), running in the `release` GitHub environment. It has two jobs:
164
- `cdn` (build, archive upload, alias rewrite, Static Web App deploy) and
165
- `publish` (npm), with `publish` gated on `cdn` succeeding first.
254
+ Releases start from the version bump itself, via `.github/workflows/release.yml`
255
+ (the `Release` workflow), running in the `release` GitHub environment. It has
256
+ three jobs: `tag` (creates the version tag), `cdn` (build, archive upload,
257
+ alias rewrite, Static Web App deploy) and `publish` (npm), with `publish`
258
+ gated on `cdn` succeeding first.
166
259
 
167
260
  1. Bump `version` in **both** `package.json` and `src/version.ts`'s
168
- `WIDGET_VERSION` (a normal PR — `tests/version.test.ts` asserts the two
169
- stay in sync), and merge it to `main`.
170
- 2. Tag the merge commit and push the tag:
171
-
172
- ```sh
173
- git tag v<version> && git push origin v<version>
174
- ```
175
-
176
- The tag must match `package.json`'s `version` exactly, for a stable
177
- release (e.g. `v1.3.0` ↔ `1.3.0`) and for a prerelease alike (e.g.
178
- `v1.3.0-rc.1` ↔ `1.3.0-rc.1`) — the workflow refuses a mismatch.
179
- Prereleases use a `-rc.N` suffix.
180
-
181
- Pushing a `v*` tag runs the workflow. The `cdn` job:
261
+ `WIDGET_VERSION` in a normal PR. `tests/version.test.ts` fails the PR's
262
+ required `quality` check unless the two agree, so a mismatched bump can't
263
+ be merged.
264
+ 2. Merge it to `main`. That is the whole release step: merging is the
265
+ approval, and there is no tag to push.
266
+
267
+ When a push to `main` changes `package.json` or `src/version.ts`, the
268
+ workflow runs and `tag` looks for `v<version>`. If the tag doesn't exist yet,
269
+ `tag` creates it on the pushed commit (a lightweight tag, via the API) and
270
+ `cdn` then `publish` run in that same run. If it does exist, the change
271
+ wasn't a version bump (e.g. a dependency edit in `package.json`), so
272
+ `cdn`/`publish` are skipped. A version that isn't plain SemVer is refused
273
+ before any tag is created. Stable releases and prereleases alike are named
274
+ from the version: `1.3.0` → `v1.3.0`, `1.3.0-rc.1` → `v1.3.0-rc.1`
275
+ (prereleases use a `-rc.N` suffix).
276
+
277
+ Pushing a `v*` tag by hand still starts the workflow too (it skips `tag`),
278
+ and then the tag must match `package.json`'s `version` exactly or the
279
+ workflow refuses.
280
+
281
+ The `cdn` job:
182
282
 
183
283
  - Builds and re-runs the full quality gate (lint, typecheck, unit tests,
184
284
  build) against the tagged commit.
@@ -257,11 +357,14 @@ for a failed `cdn` job.
257
357
 
258
358
  ### Recovering a failed release
259
359
 
260
- If the `cdn` job fails partway through — after the version folder was
261
- already uploaded to the archive — simply re-pushing the same tag will not
262
- work: `scripts/release-plan.mjs plan` refuses a version that already
263
- exists in the archive, since versions are immutable by design. To recover,
264
- delete that version's folder from the archive first, then re-push the tag.
360
+ If the `cdn` job fails before it uploads anything (a flaky test, an Azure
361
+ login), use **Re-run failed jobs** on that run: `tag` already succeeded and
362
+ is not repeated. If it fails partway through — after the version folder was
363
+ already uploaded to the archive — re-running will not work:
364
+ `scripts/release-plan.mjs plan` refuses a version that already exists in the
365
+ archive, since versions are immutable by design. To recover, delete that
366
+ version's folder from the archive first, then re-run the failed `cdn` job (or,
367
+ if you deleted the tag too, re-push it as below).
265
368
  Run this as an operator, not the workflow's identity — the release
266
369
  identity is the only principal with a data-plane role on the container, so
267
370
  an operator's own `az storage blob` command needs `--auth-mode key`
@@ -271,7 +374,9 @@ key for that):
271
374
  ```sh
272
375
  az storage blob delete-batch --account-name <acct> --source widget-releases \
273
376
  --pattern "vX.Y.Z/*" --auth-mode key
274
- git push origin :refs/tags/vX.Y.Z # delete the remote tag
377
+ # Only if you'd rather start a fresh run than re-run the failed job: delete the remote
378
+ # tag and push it again by hand (a manual tag push skips the `tag` job).
379
+ git push origin :refs/tags/vX.Y.Z
275
380
  git tag -d vX.Y.Z && git tag vX.Y.Z && git push origin vX.Y.Z
276
381
  ```
277
382
 
@@ -1,7 +1,11 @@
1
1
  import { RefObject } from 'preact';
2
- export declare function Launcher({ isOpen, onClick, iconUrl, buttonRef, }: {
2
+ import { LauncherIcon, LauncherOpenIcon } from '../types';
3
+ export declare function Launcher({ isOpen, onClick, iconUrl, icon, openIconUrl, openIcon, buttonRef, }: {
3
4
  isOpen: boolean;
4
5
  onClick: () => void;
5
6
  iconUrl?: string;
7
+ icon?: LauncherIcon;
8
+ openIconUrl?: string;
9
+ openIcon?: LauncherOpenIcon;
6
10
  buttonRef?: RefObject<HTMLButtonElement | null>;
7
11
  }): import('preact').JSX.Element;
@@ -1,6 +1,12 @@
1
1
  export declare function ChatIcon({ size }: {
2
2
  size?: number;
3
3
  }): import('preact').JSX.Element;
4
+ export declare function MessageIcon({ size }: {
5
+ size?: number;
6
+ }): import('preact').JSX.Element;
7
+ export declare function SparkleIcon({ size }: {
8
+ size?: number;
9
+ }): import('preact').JSX.Element;
4
10
  export declare function ChevronDownIcon({ size }: {
5
11
  size?: number;
6
12
  }): import('preact').JSX.Element;
package/dist/config.d.ts CHANGED
@@ -1,7 +1,39 @@
1
- import { WidgetConfig } from './types';
1
+ import { ThemeColorOverrides } from './themeRoles';
2
+ import { LauncherIcon, LauncherOpenIcon, WidgetConfig } from './types';
2
3
  export declare const DEFAULT_API_BASE_URL = "https://api.aidenvoice.com";
3
4
  export declare const DEFAULT_Z_INDEX = 2147483000;
4
5
  export declare function resolveZIndex(zIndex: unknown): number;
5
6
  export declare const DEFAULT_AGENT_NAME = "Aiden";
6
7
  export declare function trimmedName(name: unknown): string;
7
8
  export declare function validateConfig(config: WidgetConfig): void;
9
+ export declare function safeFontFamily(value: unknown): string | undefined;
10
+ export interface NormalizedTheme {
11
+ colors: ThemeColorOverrides;
12
+ fontFamily: string | undefined;
13
+ launcher: {
14
+ icon?: LauncherIcon;
15
+ iconUrl?: string;
16
+ openIcon?: LauncherOpenIcon;
17
+ openIconUrl?: string;
18
+ };
19
+ }
20
+ export declare function normalizeTheme(theme: unknown): NormalizedTheme;
21
+ export declare const LAYOUT_DEFAULTS: {
22
+ readonly offsetX: 20;
23
+ readonly offsetY: 20;
24
+ readonly launcherSize: 56;
25
+ readonly panelWidth: 360;
26
+ readonly panelHeight: 480;
27
+ };
28
+ export declare const LAUNCHER_SIZE_MIN = 24;
29
+ export declare const LAUNCHER_SIZE_MAX = 120;
30
+ export declare const PANEL_MIN_WIDTH = 280;
31
+ export declare const PANEL_MIN_HEIGHT = 320;
32
+ export interface NormalizedLayout {
33
+ offsetX: number;
34
+ offsetY: number;
35
+ launcherSize: number;
36
+ panelWidth: number;
37
+ panelHeight: number;
38
+ }
39
+ export declare function normalizeLayout(layout: unknown): NormalizedLayout;
@@ -1,3 +1,4 @@
1
+ import { NormalizedTheme } from './config';
1
2
  import { WidgetConfig } from './types';
2
3
  export declare const SLOW_RESPONSE_DELAY_MS = 8000;
3
4
  export declare const BRANDING_LOOKUP_WAIT_MS = 3000;
@@ -40,6 +41,7 @@ export declare class WidgetController {
40
41
  private activeRequestController;
41
42
  private slowResponseTimer;
42
43
  private readonly prefersReducedMotion;
44
+ readonly launcher: NormalizedTheme['launcher'];
43
45
  readonly launcherIconUrl: string | undefined;
44
46
  readonly emptyStateImageUrl: string | undefined;
45
47
  readonly emptyStateImageAlt: string;
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import { WidgetConfig, WidgetHandle } from './types';
1
+ import { LauncherIcon, LauncherOpenIcon, WidgetConfig, WidgetHandle, WidgetLayout, WidgetTheme } from './types';
2
2
  export declare function init(config: WidgetConfig): WidgetHandle;
3
- export type { ResolvedTheme, ThemeInput } from './theme';
3
+ export type { ContrastWarning, ResolvedTheme, ThemeInput } from './theme';
4
4
  export { resolveTheme } from './theme';
5
- export type { WidgetConfig, WidgetHandle };
5
+ export type { ThemeColorOverrides, ThemeColorRole } from './themeRoles';
6
+ export type { LauncherIcon, LauncherOpenIcon, WidgetConfig, WidgetHandle, WidgetLayout, WidgetTheme, };
@@ -0,0 +1,2 @@
1
+ import { WidgetConfig } from './types';
2
+ export declare function applyLayout(root: HTMLElement, config: WidgetConfig): void;
package/dist/theme.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { ThemeColorOverrides, ThemeColorRole } from './themeRoles';
1
2
  import { WidgetConfig } from './types';
2
3
  export declare function pickTextColor(cssColor: string): '#000000' | '#ffffff';
3
4
  export declare function contrastRatio(cssColorA: string, cssColorB: string): number;
@@ -6,6 +7,17 @@ export interface ThemeInput {
6
7
  color?: string | null;
7
8
  inkColor?: string | null;
8
9
  accentColor?: string | null;
10
+ /** Per-role replacements. Used verbatim; they win over `color`/`inkColor`/`accentColor`. */
11
+ overrides?: ThemeColorOverrides;
12
+ }
13
+ export interface ContrastWarning {
14
+ role: ThemeColorRole;
15
+ /** The role whose color this one is drawn on. */
16
+ against: ThemeColorRole;
17
+ /** The overridden value. */
18
+ value: string;
19
+ ratio: number;
20
+ required: number;
9
21
  }
10
22
  export interface ResolvedTheme {
11
23
  /** Launcher, visitor bubbles, Send and Submit button fill. */
@@ -23,19 +35,26 @@ export interface ResolvedTheme {
23
35
  * Flattening a translucent color to its opaque look over white doesn't
24
36
  * count -- that's compositing, not a readability adjustment, and it
25
37
  * lightens rather than darkens, so a "shown a little darker" note would
26
- * be wrong for it.
38
+ * be wrong for it. An explicit override is never adjusted.
27
39
  */
28
40
  adjusted: {
29
41
  primary: boolean;
30
42
  ink: boolean;
31
43
  link: boolean;
32
44
  };
45
+ /** Every color the widget renders, by role. */
46
+ roles: Record<ThemeColorRole, string>;
47
+ /** Which roles came from `overrides` (and so were used verbatim). */
48
+ overridden: Record<ThemeColorRole, boolean>;
49
+ /** Overridden roles whose contrast is below what their surface needs. */
50
+ contrastWarnings: ContrastWarning[];
33
51
  }
34
52
  export declare function usableHex(color: unknown): string | null;
35
- export declare function resolveTheme({ color, inkColor, accentColor }: ThemeInput): ResolvedTheme;
53
+ export declare function resolveTheme({ color, inkColor, accentColor, overrides, }: ThemeInput): ResolvedTheme;
36
54
  export declare function applyThemeColor(root: HTMLElement, color: string, fallback?: string): void;
37
55
  export declare function applyPalette(root: HTMLElement, { inkColor, accentColor }: {
38
56
  inkColor?: string | null;
39
57
  accentColor?: string | null;
40
58
  }): void;
59
+ export declare function applyColorOverrides(root: HTMLElement, overrides: ThemeColorOverrides): void;
41
60
  export declare function applyTheme(root: HTMLElement, config: WidgetConfig): void;
@@ -0,0 +1,5 @@
1
+ export declare const THEME_COLOR_ROLES: readonly ["primary", "onPrimary", "primaryText", "ink", "link", "text", "panel", "border", "headerHover", "assistantBubble", "muted", "typingDots", "errorBackground", "errorText", "inputBorder", "focusRing"];
2
+ export type ThemeColorRole = (typeof THEME_COLOR_ROLES)[number];
3
+ export type ThemeColorOverrides = Partial<Record<ThemeColorRole, string>>;
4
+ export declare const ROLE_DEFAULTS: Readonly<Record<ThemeColorRole, string>>;
5
+ export declare const ROLE_CSS_VARS: Readonly<Record<ThemeColorRole, string>>;
package/dist/types.d.ts CHANGED
@@ -1,3 +1,74 @@
1
+ export type LauncherIcon = 'chat' | 'message' | 'sparkle';
2
+ export type LauncherOpenIcon = 'chevron-down' | 'close';
3
+ export interface WidgetTheme {
4
+ /**
5
+ * Replace any color the widget renders. Used exactly as given: no
6
+ * darkening, no contrast correction (a low-contrast value only logs a
7
+ * warning). Omit a role to keep the widget's calculated color.
8
+ */
9
+ colors?: {
10
+ /** Launcher, visitor bubbles, Send/Submit fill. Beats `color`. */
11
+ primary?: string;
12
+ /** Text and icons on `primary`. Calculated (black or white) when omitted. */
13
+ onPrimary?: string;
14
+ /** `primary` used as text on the panel (header controls). Calculated when omitted. */
15
+ primaryText?: string;
16
+ /** Header title and reply text. Beats `inkColor`. */
17
+ ink?: string;
18
+ /** Links in replies. Beats `accentColor`. */
19
+ link?: string;
20
+ /** Form-control and feedback-button text. */
21
+ text?: string;
22
+ /** Panel background (also the header and sticky action surfaces). */
23
+ panel?: string;
24
+ /** Dividers. */
25
+ border?: string;
26
+ /** Header control hover fill. */
27
+ headerHover?: string;
28
+ /** Reply bubble background. */
29
+ assistantBubble?: string;
30
+ /** Secondary text on the reply bubble. */
31
+ muted?: string;
32
+ /** Waiting-for-reply indicator. */
33
+ typingDots?: string;
34
+ errorBackground?: string;
35
+ errorText?: string;
36
+ inputBorder?: string;
37
+ /** The dark tone of the focus outline. */
38
+ focusRing?: string;
39
+ };
40
+ fonts?: {
41
+ /**
42
+ * A CSS font-family stack. The font must already be available: a system
43
+ * font, or one your page loaded. The widget never loads fonts.
44
+ */
45
+ family?: string;
46
+ };
47
+ launcher?: {
48
+ /** Built-in icon on the closed launcher. */
49
+ icon?: LauncherIcon;
50
+ /** Image on the closed launcher; wins over `icon` and over `launcherIconUrl`. */
51
+ iconUrl?: string;
52
+ /** Built-in icon on the open launcher (the minimize control). */
53
+ openIcon?: LauncherOpenIcon;
54
+ /** Image on the open launcher; wins over `openIcon`. */
55
+ openIconUrl?: string;
56
+ };
57
+ }
58
+ export interface WidgetLayout {
59
+ /** Distance in px from the corner chosen by `position`. Default `{ x: 20, y: 20 }`. */
60
+ offset?: {
61
+ x?: number;
62
+ y?: number;
63
+ };
64
+ /** Launcher diameter in px, 24-120. Default 56. */
65
+ launcherSize?: number;
66
+ /** Preferred panel size in px (minimum 280×320, always capped to the viewport). Default 360×480. */
67
+ panel?: {
68
+ width?: number;
69
+ height?: number;
70
+ };
71
+ }
1
72
  export interface WidgetConfig {
2
73
  publishableKey?: string;
3
74
  sessionToken?: string;
@@ -18,8 +89,9 @@ export interface WidgetConfig {
18
89
  */
19
90
  accentColor?: string;
20
91
  name?: string;
92
+ title?: string;
21
93
  greeting?: string;
22
- /** Image shown on the launcher bubble instead of the default chat icon. */
94
+ /** Image shown on the launcher bubble instead of the default chat icon. Alias of `theme.launcher.iconUrl`, which wins if both are set. */
23
95
  launcherIconUrl?: string;
24
96
  /** Image shown above the greeting while the conversation is empty. */
25
97
  emptyStateImageUrl?: string;
@@ -33,6 +105,10 @@ export interface WidgetConfig {
33
105
  */
34
106
  zIndex?: number;
35
107
  apiBaseUrl?: string;
108
+ /** Colors, font and launcher icons. See `WidgetTheme`. */
109
+ theme?: WidgetTheme;
110
+ /** Launcher position/size and panel size. See `WidgetLayout`. */
111
+ layout?: WidgetLayout;
36
112
  }
37
113
  export interface WidgetHandle {
38
114
  unmount(): void;
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const WIDGET_VERSION = "0.5.3";
1
+ export declare const WIDGET_VERSION = "0.7.0";