@customerhero/js 2.1.1 → 2.3.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
@@ -56,6 +56,25 @@ chat.identify({
56
56
  | `locale` | `string` | Widget locale (e.g. `"en"`, `"es"`). Auto-detected from browser if omitted. |
57
57
  | `suggestedMessages` | `string[]` | Quick-reply options shown before the first message. |
58
58
 
59
+ ### Appearance
60
+
61
+ | Option | Type | Description |
62
+ | ------------------------ | ----------------------------------- | --------------------------------------------------------------------------------- |
63
+ | `colorScheme` | `"auto" \| "light" \| "dark"` | `auto` follows the visitor's OS preference. Defaults to `light`. |
64
+ | `primaryColorDark` | `string` | Primary color used in dark mode. Only honoured when the effective scheme is dark. |
65
+ | `backgroundColorDark` | `string` | Background color used in dark mode. |
66
+ | `textColorDark` | `string` | Text color used in dark mode. |
67
+ | `size` | `"compact" \| "default" \| "large"` | Launcher diameter, panel dimensions, and base font size. |
68
+ | `cornerStyle` | `"soft" \| "rounded" \| "square"` | Panel border-radius preset. |
69
+ | `launcher.iconUrl` | `string` | Custom launcher icon URL (replaces the default chat-bubble glyph). |
70
+ | `launcher.label` | `string` | CTA label next to the launcher (turns the bubble into a pill). Max 60 chars. |
71
+ | `launcher.showOnlineDot` | `boolean` | Show a small green dot on the launcher when agents are available. |
72
+ | `offset.bottom` | `number` | Pixel offset from the bottom edge. 0–1000. Defaults to 20. |
73
+ | `offset.side` | `number` | Pixel offset from the side (mirrors `position`). 0–1000. Defaults to 20. |
74
+ | `zIndex` | `number` | Z-index override. Defaults to 99999. Capped at 2 000 000 000. |
75
+
76
+ Dark colors are never auto-derived from `primaryColor`/`backgroundColor`/`textColor` — set them explicitly when enabling dark or auto modes.
77
+
59
78
  ## License
60
79
 
61
80
  MIT
package/dist/index.cjs CHANGED
@@ -20,8 +20,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ CORNER_RADIUS: () => CORNER_RADIUS,
23
24
  CustomerHeroChat: () => CustomerHeroChat,
24
25
  DEFAULTS: () => DEFAULTS,
26
+ SIZE_PRESETS: () => SIZE_PRESETS,
25
27
  SUPPORTED_LOCALES: () => SUPPORTED_LOCALES,
26
28
  ScreenshotCancelled: () => ScreenshotCancelled,
27
29
  ScreenshotUnavailable: () => ScreenshotUnavailable,
@@ -29,10 +31,14 @@ __export(index_exports, {
29
31
  captureScreenshot: () => captureScreenshot,
30
32
  createTranslator: () => createTranslator,
31
33
  detectLocale: () => detectLocale,
34
+ effectiveColors: () => effectiveColors,
32
35
  evaluate: () => evaluate,
33
36
  isRtlLocale: () => isRtlLocale,
37
+ panelRadius: () => panelRadius,
34
38
  pickFire: () => pickFire,
35
39
  resolveLocale: () => resolveLocale,
40
+ resolveScheme: () => resolveScheme,
41
+ sizePreset: () => sizePreset,
36
42
  startTriggersRuntime: () => startTriggersRuntime
37
43
  });
38
44
  module.exports = __toCommonJS(index_exports);
@@ -46,7 +52,29 @@ var DEFAULTS = {
46
52
  position: "bottom-right",
47
53
  placeholderText: "Type your message...",
48
54
  welcomeMessage: "Hi! How can I help you today?",
49
- title: "CustomerHero"
55
+ title: "CustomerHero",
56
+ // Appearance pack (B1–B6) defaults.
57
+ colorScheme: "light",
58
+ // Dark fallbacks used when the effective scheme is dark and no per-chatbot
59
+ // dark color is configured. Operators can — and should — override these.
60
+ primaryColorDark: "#A78BFA",
61
+ backgroundColorDark: "#0F172A",
62
+ textColorDark: "#E5E7EB",
63
+ size: "default",
64
+ cornerStyle: "rounded",
65
+ offsetBottom: 20,
66
+ offsetSide: 20,
67
+ zIndex: 99999
68
+ };
69
+ var SIZE_PRESETS = {
70
+ compact: { bubble: 48, width: 320, height: 480, fontSize: 13 },
71
+ default: { bubble: 56, width: 380, height: 520, fontSize: 14 },
72
+ large: { bubble: 64, width: 440, height: 600, fontSize: 15 }
73
+ };
74
+ var CORNER_RADIUS = {
75
+ soft: 8,
76
+ rounded: 16,
77
+ square: 0
50
78
  };
51
79
 
52
80
  // src/i18n/locales/en.ts
@@ -75,6 +103,8 @@ var en = {
75
103
  attach_menu_open: "Add attachment",
76
104
  attach_photo: "Choose file",
77
105
  drop_files_here: "Drop files here",
106
+ incident_dismiss: "Dismiss",
107
+ incident_default_link_label: "Learn more",
78
108
  attachment_unsupported_type: "Unsupported file type"
79
109
  };
80
110
 
@@ -104,6 +134,8 @@ var es = {
104
134
  attach_menu_open: "A\xF1adir adjunto",
105
135
  attach_photo: "Elegir archivo",
106
136
  drop_files_here: "Suelta los archivos aqu\xED",
137
+ incident_dismiss: "Descartar",
138
+ incident_default_link_label: "M\xE1s informaci\xF3n",
107
139
  attachment_unsupported_type: "Tipo de archivo no admitido"
108
140
  };
109
141
 
@@ -133,6 +165,8 @@ var ptBR = {
133
165
  attach_menu_open: "Adicionar anexo",
134
166
  attach_photo: "Escolher arquivo",
135
167
  drop_files_here: "Solte os arquivos aqui",
168
+ incident_dismiss: "Dispensar",
169
+ incident_default_link_label: "Saiba mais",
136
170
  attachment_unsupported_type: "Tipo de arquivo n\xE3o suportado"
137
171
  };
138
172
 
@@ -162,6 +196,8 @@ var ptPT = {
162
196
  attach_menu_open: "Adicionar anexo",
163
197
  attach_photo: "Escolher ficheiro",
164
198
  drop_files_here: "Largue os ficheiros aqui",
199
+ incident_dismiss: "Dispensar",
200
+ incident_default_link_label: "Saiba mais",
165
201
  attachment_unsupported_type: "Tipo de ficheiro n\xE3o suportado"
166
202
  };
167
203
 
@@ -191,6 +227,8 @@ var fr = {
191
227
  attach_menu_open: "Ajouter une pi\xE8ce jointe",
192
228
  attach_photo: "Choisir un fichier",
193
229
  drop_files_here: "D\xE9posez les fichiers ici",
230
+ incident_dismiss: "Ignorer",
231
+ incident_default_link_label: "En savoir plus",
194
232
  attachment_unsupported_type: "Type de fichier non pris en charge"
195
233
  };
196
234
 
@@ -220,6 +258,8 @@ var de = {
220
258
  attach_menu_open: "Anhang hinzuf\xFCgen",
221
259
  attach_photo: "Datei ausw\xE4hlen",
222
260
  drop_files_here: "Dateien hier ablegen",
261
+ incident_dismiss: "Schlie\xDFen",
262
+ incident_default_link_label: "Mehr erfahren",
223
263
  attachment_unsupported_type: "Dateityp nicht unterst\xFCtzt"
224
264
  };
225
265
 
@@ -249,6 +289,8 @@ var it = {
249
289
  attach_menu_open: "Aggiungi allegato",
250
290
  attach_photo: "Scegli file",
251
291
  drop_files_here: "Trascina qui i file",
292
+ incident_dismiss: "Chiudi",
293
+ incident_default_link_label: "Scopri di pi\xF9",
252
294
  attachment_unsupported_type: "Tipo di file non supportato"
253
295
  };
254
296
 
@@ -278,6 +320,8 @@ var nl = {
278
320
  attach_menu_open: "Bijlage toevoegen",
279
321
  attach_photo: "Bestand kiezen",
280
322
  drop_files_here: "Sleep bestanden hier",
323
+ incident_dismiss: "Sluiten",
324
+ incident_default_link_label: "Meer informatie",
281
325
  attachment_unsupported_type: "Bestandstype niet ondersteund"
282
326
  };
283
327
 
@@ -307,6 +351,8 @@ var pl = {
307
351
  attach_menu_open: "Dodaj za\u0142\u0105cznik",
308
352
  attach_photo: "Wybierz plik",
309
353
  drop_files_here: "Upu\u015B\u0107 pliki tutaj",
354
+ incident_dismiss: "Zamknij",
355
+ incident_default_link_label: "Dowiedz si\u0119 wi\u0119cej",
310
356
  attachment_unsupported_type: "Nieobs\u0142ugiwany typ pliku"
311
357
  };
312
358
 
@@ -336,6 +382,8 @@ var tr = {
336
382
  attach_menu_open: "Ek ekle",
337
383
  attach_photo: "Dosya se\xE7",
338
384
  drop_files_here: "Dosyalar\u0131 buraya b\u0131rak",
385
+ incident_dismiss: "Kapat",
386
+ incident_default_link_label: "Daha fazla bilgi",
339
387
  attachment_unsupported_type: "Desteklenmeyen dosya t\xFCr\xFC"
340
388
  };
341
389
 
@@ -365,6 +413,8 @@ var ar = {
365
413
  attach_menu_open: "\u0625\u0636\u0627\u0641\u0629 \u0645\u0631\u0641\u0642",
366
414
  attach_photo: "\u0627\u062E\u062A\u0631 \u0645\u0644\u0641\u064B\u0627",
367
415
  drop_files_here: "\u0623\u0641\u0644\u062A \u0627\u0644\u0645\u0644\u0641\u0627\u062A \u0647\u0646\u0627",
416
+ incident_dismiss: "\u0625\u063A\u0644\u0627\u0642",
417
+ incident_default_link_label: "\u0627\u0639\u0631\u0641 \u0627\u0644\u0645\u0632\u064A\u062F",
368
418
  attachment_unsupported_type: "\u0646\u0648\u0639 \u0627\u0644\u0645\u0644\u0641 \u063A\u064A\u0631 \u0645\u062F\u0639\u0648\u0645"
369
419
  };
370
420
 
@@ -394,6 +444,8 @@ var ja = {
394
444
  attach_menu_open: "\u6DFB\u4ED8\u30D5\u30A1\u30A4\u30EB\u3092\u8FFD\u52A0",
395
445
  attach_photo: "\u30D5\u30A1\u30A4\u30EB\u3092\u9078\u629E",
396
446
  drop_files_here: "\u30D5\u30A1\u30A4\u30EB\u3092\u3053\u3053\u306B\u30C9\u30ED\u30C3\u30D7",
447
+ incident_dismiss: "\u9589\u3058\u308B",
448
+ incident_default_link_label: "\u8A73\u7D30\u3092\u898B\u308B",
397
449
  attachment_unsupported_type: "\u30B5\u30DD\u30FC\u30C8\u3055\u308C\u3066\u3044\u306A\u3044\u30D5\u30A1\u30A4\u30EB\u5F62\u5F0F"
398
450
  };
399
451
 
@@ -423,6 +475,8 @@ var ko = {
423
475
  attach_menu_open: "\uCCA8\uBD80 \uD30C\uC77C \uCD94\uAC00",
424
476
  attach_photo: "\uD30C\uC77C \uC120\uD0DD",
425
477
  drop_files_here: "\uD30C\uC77C\uC744 \uC5EC\uAE30\uC5D0 \uB193\uAE30",
478
+ incident_dismiss: "\uB2EB\uAE30",
479
+ incident_default_link_label: "\uC790\uC138\uD788 \uC54C\uC544\uBCF4\uAE30",
426
480
  attachment_unsupported_type: "\uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 \uD30C\uC77C \uD615\uC2DD"
427
481
  };
428
482
 
@@ -452,6 +506,8 @@ var zhCN = {
452
506
  attach_menu_open: "\u6DFB\u52A0\u9644\u4EF6",
453
507
  attach_photo: "\u9009\u62E9\u6587\u4EF6",
454
508
  drop_files_here: "\u5C06\u6587\u4EF6\u62D6\u653E\u5230\u6B64\u5904",
509
+ incident_dismiss: "\u5173\u95ED",
510
+ incident_default_link_label: "\u4E86\u89E3\u66F4\u591A",
455
511
  attachment_unsupported_type: "\u4E0D\u652F\u6301\u7684\u6587\u4EF6\u7C7B\u578B"
456
512
  };
457
513
 
@@ -481,6 +537,8 @@ var zhTW = {
481
537
  attach_menu_open: "\u65B0\u589E\u9644\u4EF6",
482
538
  attach_photo: "\u9078\u64C7\u6A94\u6848",
483
539
  drop_files_here: "\u5C07\u6A94\u6848\u62D6\u653E\u5230\u6B64\u8655",
540
+ incident_dismiss: "\u95DC\u9589",
541
+ incident_default_link_label: "\u77AD\u89E3\u66F4\u591A",
484
542
  attachment_unsupported_type: "\u4E0D\u652F\u63F4\u7684\u6A94\u6848\u985E\u578B"
485
543
  };
486
544
 
@@ -984,7 +1042,14 @@ function startTriggersRuntime(options) {
984
1042
  }
985
1043
 
986
1044
  // src/client.ts
1045
+ function clampInt(value, min, max, fallback) {
1046
+ if (typeof value !== "number" || !Number.isFinite(value)) return fallback;
1047
+ return Math.max(min, Math.min(max, Math.trunc(value)));
1048
+ }
987
1049
  function resolveConfig(userConfig, fetched) {
1050
+ const launcherUser = userConfig.launcher ?? {};
1051
+ const launcherFetched = fetched?.launcher ?? {};
1052
+ const offsetUser = userConfig.offset ?? {};
988
1053
  return {
989
1054
  chatbotId: userConfig.chatbotId,
990
1055
  apiBase: userConfig.apiBase ?? DEFAULTS.apiBase,
@@ -997,12 +1062,78 @@ function resolveConfig(userConfig, fetched) {
997
1062
  title: userConfig.title ?? fetched?.title ?? DEFAULTS.title,
998
1063
  avatarUrl: userConfig.avatarUrl ?? fetched?.avatarUrl,
999
1064
  suggestedMessages: userConfig.suggestedMessages ?? fetched?.suggestedMessages ?? [],
1000
- stringOverrides: fetched?.stringOverrides
1065
+ stringOverrides: fetched?.stringOverrides,
1066
+ // Appearance pack. Color palette + size + corner style + launcher all
1067
+ // come from the server widget_config (with host-side override). The
1068
+ // *runtime* knobs — colorScheme, offset, zIndex — are host-only because
1069
+ // they depend on the page the widget is embedded in, not the chatbot.
1070
+ primaryColorDark: userConfig.primaryColorDark ?? fetched?.primaryColorDark,
1071
+ backgroundColorDark: userConfig.backgroundColorDark ?? fetched?.backgroundColorDark,
1072
+ textColorDark: userConfig.textColorDark ?? fetched?.textColorDark,
1073
+ size: userConfig.size ?? fetched?.size ?? DEFAULTS.size,
1074
+ cornerStyle: userConfig.cornerStyle ?? fetched?.cornerStyle ?? DEFAULTS.cornerStyle,
1075
+ launcher: {
1076
+ iconUrl: launcherUser.iconUrl ?? launcherFetched.iconUrl,
1077
+ label: launcherUser.label ?? launcherFetched.label,
1078
+ showOnlineDot: launcherUser.showOnlineDot ?? launcherFetched.showOnlineDot ?? false
1079
+ },
1080
+ colorScheme: userConfig.colorScheme ?? DEFAULTS.colorScheme,
1081
+ offset: {
1082
+ bottom: clampInt(offsetUser.bottom, 0, 1e3, DEFAULTS.offsetBottom),
1083
+ side: clampInt(offsetUser.side, 0, 1e3, DEFAULTS.offsetSide)
1084
+ },
1085
+ zIndex: clampInt(userConfig.zIndex, 0, 2e9, DEFAULTS.zIndex),
1086
+ // Defaults to true — the widget shows the attach button unless the
1087
+ // chatbot explicitly opts out via widget_config or the host passes
1088
+ // allowAttachments=false. Server still enforces the same flag at the
1089
+ // upload endpoint either way.
1090
+ allowAttachments: userConfig.allowAttachments ?? fetched?.allowAttachments ?? true
1001
1091
  };
1002
1092
  }
1093
+ function sanitizeIncidentBanner(input) {
1094
+ if (!input || typeof input !== "object") return null;
1095
+ const raw = input;
1096
+ const sev = raw.severity;
1097
+ if (sev !== "info" && sev !== "warning" && sev !== "outage") return null;
1098
+ if (typeof raw.title !== "string" || raw.title.length === 0) return null;
1099
+ if (typeof raw.expiresAt === "string") {
1100
+ const t = Date.parse(raw.expiresAt);
1101
+ if (!Number.isNaN(t) && t <= Date.now()) return null;
1102
+ }
1103
+ const out = { severity: sev, title: raw.title };
1104
+ if (typeof raw.body === "string") out.body = raw.body;
1105
+ if (typeof raw.eta === "string") out.eta = raw.eta;
1106
+ if (raw.link && typeof raw.link === "object") {
1107
+ const link = raw.link;
1108
+ if (typeof link.url === "string") {
1109
+ out.link = { url: link.url };
1110
+ if (typeof link.label === "string") out.link.label = link.label;
1111
+ }
1112
+ }
1113
+ if (typeof raw.expiresAt === "string") out.expiresAt = raw.expiresAt;
1114
+ return out;
1115
+ }
1116
+ function bannerKey(banner) {
1117
+ if (!banner) return null;
1118
+ return JSON.stringify([
1119
+ banner.severity,
1120
+ banner.title,
1121
+ banner.body ?? "",
1122
+ banner.eta ?? "",
1123
+ banner.link?.url ?? "",
1124
+ banner.link?.label ?? "",
1125
+ banner.expiresAt ?? ""
1126
+ ]);
1127
+ }
1003
1128
  function getStorage() {
1004
1129
  try {
1005
- return typeof window !== "undefined" ? window.localStorage : null;
1130
+ if (typeof window !== "undefined" && window.localStorage)
1131
+ return window.localStorage;
1132
+ if (typeof globalThis !== "undefined") {
1133
+ const ls = globalThis.localStorage;
1134
+ if (ls) return ls;
1135
+ }
1136
+ return null;
1006
1137
  } catch {
1007
1138
  return null;
1008
1139
  }
@@ -1044,9 +1175,42 @@ var CustomerHeroChat = class {
1044
1175
  preChatSubmission: null,
1045
1176
  consent: this.readStoredConsent(),
1046
1177
  pendingTriggerId: null,
1047
- pendingPrefill: null
1178
+ pendingPrefill: null,
1179
+ incidentBanner: null,
1180
+ incidentBannerDismissed: false,
1181
+ readOnly: false
1048
1182
  };
1049
1183
  }
1184
+ /**
1185
+ * Mark the config as loaded and put the client into read-only preview
1186
+ * mode without hitting the API. Used by `@customerhero/react/preview` to
1187
+ * render the widget against a host-supplied config (the dashboard preview
1188
+ * pane). Public API consumers should not call this.
1189
+ *
1190
+ * Pass a config to re-resolve and update the rendered colors/size/launcher
1191
+ * in place. Callers should reuse the same client instance across config
1192
+ * changes so the open animation only fires once.
1193
+ *
1194
+ * @internal
1195
+ */
1196
+ __seedForPreview(config, extras) {
1197
+ const resolved = config ? resolveConfig(config) : this.state.config;
1198
+ if (config) this.userConfig = config;
1199
+ const seededMessages = resolved.welcomeMessage ? [{ role: "bot", content: resolved.welcomeMessage }] : [];
1200
+ const sanitizedBanner = extras && "banner" in extras ? sanitizeIncidentBanner(extras.banner ?? null) : this.state.incidentBanner;
1201
+ this.setState({
1202
+ config: resolved,
1203
+ configLoaded: true,
1204
+ configError: null,
1205
+ readOnly: true,
1206
+ isOpen: true,
1207
+ messages: seededMessages,
1208
+ incidentBanner: sanitizedBanner,
1209
+ // Reset the dismissed flag so toggling the banner on in the dashboard
1210
+ // re-renders it after a previous preview-side dismiss.
1211
+ incidentBannerDismissed: false
1212
+ });
1213
+ }
1050
1214
  // ── Proactive engagement state ─────────────────────────────────────
1051
1215
  triggersRuntime = null;
1052
1216
  preChatFormSubmitted = false;
@@ -1123,11 +1287,18 @@ var CustomerHeroChat = class {
1123
1287
  const resolved = resolveConfig(this.userConfig, fetched);
1124
1288
  const triggers = Array.isArray(fetched.triggers) ? fetched.triggers : [];
1125
1289
  const preChatForm = fetched.preChatForm ?? null;
1290
+ const incidentBanner = sanitizeIncidentBanner(fetched.incidentBanner);
1291
+ const prevBannerKey = bannerKey(this.state.incidentBanner);
1292
+ const nextBannerKey = bannerKey(incidentBanner);
1293
+ const dismissedFromStorage = nextBannerKey && nextBannerKey === this.readStoredBannerDismissal();
1294
+ const incidentBannerDismissed = nextBannerKey === prevBannerKey ? this.state.incidentBannerDismissed || !!dismissedFromStorage : !!dismissedFromStorage;
1126
1295
  this.setState({
1127
1296
  config: resolved,
1128
1297
  configLoaded: true,
1129
1298
  triggers,
1130
- preChatForm
1299
+ preChatForm,
1300
+ incidentBanner,
1301
+ incidentBannerDismissed
1131
1302
  });
1132
1303
  if (resolved.stringOverrides) this.rebuildTranslator();
1133
1304
  this.startTriggersRuntimeIfPossible();
@@ -1185,6 +1356,7 @@ var CustomerHeroChat = class {
1185
1356
  }
1186
1357
  }
1187
1358
  async sendMessage(message, options) {
1359
+ if (this.state.readOnly) return;
1188
1360
  const trimmed = message.trim();
1189
1361
  const attachmentTokens = options?.attachmentTokens ?? [];
1190
1362
  if (!trimmed || this.state.isLoading) return;
@@ -1552,6 +1724,34 @@ var CustomerHeroChat = class {
1552
1724
  setTraits(traits) {
1553
1725
  this.triggersRuntime?.setTraits(traits);
1554
1726
  }
1727
+ /** Hide the active incident banner for this visitor. Persisted in
1728
+ * localStorage so a refresh keeps it dismissed; resets automatically
1729
+ * when the operator changes the banner content. No-op when no banner
1730
+ * is showing. */
1731
+ dismissIncidentBanner() {
1732
+ const key = bannerKey(this.state.incidentBanner);
1733
+ if (!key) return;
1734
+ this.writeStoredBannerDismissal(key);
1735
+ this.setState({ incidentBannerDismissed: true });
1736
+ }
1737
+ readStoredBannerDismissal() {
1738
+ try {
1739
+ return this.storage?.getItem(
1740
+ `ch_incident_dismissed_${this.userConfig.chatbotId}`
1741
+ ) ?? null;
1742
+ } catch {
1743
+ return null;
1744
+ }
1745
+ }
1746
+ writeStoredBannerDismissal(key) {
1747
+ try {
1748
+ this.storage?.setItem(
1749
+ `ch_incident_dismissed_${this.userConfig.chatbotId}`,
1750
+ key
1751
+ );
1752
+ } catch {
1753
+ }
1754
+ }
1555
1755
  /** Submit pre-chat form answers. Synthesizes a customer record server-side
1556
1756
  * on the next sendMessage. Resumes any pending message that was deferred
1557
1757
  * while the form was open. */
@@ -1709,6 +1909,33 @@ function pickExtension(mime) {
1709
1909
  return "jpg";
1710
1910
  }
1711
1911
 
1912
+ // src/theme.ts
1913
+ function resolveScheme(colorScheme, prefersDark) {
1914
+ if (colorScheme === "dark") return "dark";
1915
+ if (colorScheme === "light") return "light";
1916
+ return prefersDark ? "dark" : "light";
1917
+ }
1918
+ function effectiveColors(config, scheme) {
1919
+ if (scheme === "dark") {
1920
+ return {
1921
+ primary: config.primaryColorDark ?? DEFAULTS.primaryColorDark,
1922
+ background: config.backgroundColorDark ?? DEFAULTS.backgroundColorDark,
1923
+ text: config.textColorDark ?? DEFAULTS.textColorDark
1924
+ };
1925
+ }
1926
+ return {
1927
+ primary: config.primaryColor,
1928
+ background: config.backgroundColor,
1929
+ text: config.textColor
1930
+ };
1931
+ }
1932
+ function sizePreset(size) {
1933
+ return SIZE_PRESETS[size];
1934
+ }
1935
+ function panelRadius(cornerStyle) {
1936
+ return CORNER_RADIUS[cornerStyle];
1937
+ }
1938
+
1712
1939
  // src/screenshot.ts
1713
1940
  var ScreenshotCancelled = class extends Error {
1714
1941
  constructor(message = "Screenshot cancelled") {
@@ -1843,8 +2070,10 @@ async function canvasToBlob(canvas, quality) {
1843
2070
  }
1844
2071
  // Annotate the CommonJS export names for ESM import in node:
1845
2072
  0 && (module.exports = {
2073
+ CORNER_RADIUS,
1846
2074
  CustomerHeroChat,
1847
2075
  DEFAULTS,
2076
+ SIZE_PRESETS,
1848
2077
  SUPPORTED_LOCALES,
1849
2078
  ScreenshotCancelled,
1850
2079
  ScreenshotUnavailable,
@@ -1852,9 +2081,13 @@ async function canvasToBlob(canvas, quality) {
1852
2081
  captureScreenshot,
1853
2082
  createTranslator,
1854
2083
  detectLocale,
2084
+ effectiveColors,
1855
2085
  evaluate,
1856
2086
  isRtlLocale,
2087
+ panelRadius,
1857
2088
  pickFire,
1858
2089
  resolveLocale,
2090
+ resolveScheme,
2091
+ sizePreset,
1859
2092
  startTriggersRuntime
1860
2093
  });