@xapp/chat-widget 1.96.3 → 1.96.4
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/dist/index.css +1 -1
- package/dist/index.es.js +260 -15
- package/dist/index.es.js.map +1 -1
- package/dist/index.js +260 -15
- package/dist/index.js.map +1 -1
- package/dist/xapp-chat-widget.css +1 -1
- package/dist/xapp-chat-widget.js +5 -5
- package/dist/xapp-chat-widget.js.map +1 -1
- package/package.json +2 -2
package/dist/index.es.js
CHANGED
|
@@ -78,7 +78,9 @@ color.invertColorHEX = invertColorHEX;
|
|
|
78
78
|
color.invertColorRgb = invertColorRgb;
|
|
79
79
|
color.invertColor = invertColor;
|
|
80
80
|
color.isSupportedColor = isSupportedColor;
|
|
81
|
+
color.usableColorOr = usableColorOr;
|
|
81
82
|
color.readableTextOn = readableTextOn;
|
|
83
|
+
color.darkenColor = darkenColor;
|
|
82
84
|
/**
|
|
83
85
|
* Colour maths for building a widget theme from a business's own branding.
|
|
84
86
|
*
|
|
@@ -187,6 +189,19 @@ function isSupportedColor(color) {
|
|
|
187
189
|
}
|
|
188
190
|
return parseRgb(color) !== null;
|
|
189
191
|
}
|
|
192
|
+
/**
|
|
193
|
+
* The colour to theme with: the one given, or the fallback when we cannot work
|
|
194
|
+
* out what text reads on it.
|
|
195
|
+
*
|
|
196
|
+
* Every builder needs this and each was doing it by hand, which is how the
|
|
197
|
+
* chat widget ended up guarded and the other two not. A background whose
|
|
198
|
+
* contrast cannot be computed is one we must not use — the foreground would be
|
|
199
|
+
* a guess paired with an unknown, and on a dark unparseable colour that is
|
|
200
|
+
* invisible text.
|
|
201
|
+
*/
|
|
202
|
+
function usableColorOr(color, fallback) {
|
|
203
|
+
return isSupportedColor(color) ? color : fallback;
|
|
204
|
+
}
|
|
190
205
|
/**
|
|
191
206
|
* The text colour that will read on this background: black or white, never
|
|
192
207
|
* anything else.
|
|
@@ -226,6 +241,77 @@ function hexToRgb(hex) {
|
|
|
226
241
|
b: parseInt(value.slice(4, 6), 16)
|
|
227
242
|
};
|
|
228
243
|
}
|
|
244
|
+
/**
|
|
245
|
+
* A shade of the input colour, darkened by `amount` percent (negative
|
|
246
|
+
* lightens). Ported alongside the rest so the form widget's theme does not
|
|
247
|
+
* need its own copy of it.
|
|
248
|
+
*/
|
|
249
|
+
function darkenColor(colorIn, amount) {
|
|
250
|
+
if (!colorIn) {
|
|
251
|
+
return colorIn;
|
|
252
|
+
}
|
|
253
|
+
let r, g, b, a;
|
|
254
|
+
let colorOut;
|
|
255
|
+
try {
|
|
256
|
+
// Parse the color format
|
|
257
|
+
if (colorIn.startsWith('#')) {
|
|
258
|
+
// Hex format
|
|
259
|
+
const hexMatch = colorIn.match(/\w\w/g);
|
|
260
|
+
if (hexMatch) {
|
|
261
|
+
[r, g, b] = hexMatch.map(x => parseInt(x, 16));
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
else if (colorIn.startsWith('rgb')) {
|
|
265
|
+
// RGB or RGBA format
|
|
266
|
+
const rgba = parseRgb(colorIn);
|
|
267
|
+
if (rgba) {
|
|
268
|
+
({ r, g, b, a } = rgba);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
if (r === undefined || g === undefined || b === undefined) {
|
|
272
|
+
console.error(`Unsupported color format: ${colorIn}`);
|
|
273
|
+
return colorIn;
|
|
274
|
+
}
|
|
275
|
+
if (a !== undefined) {
|
|
276
|
+
// Adjust luminance for RGBA
|
|
277
|
+
// Luminance is on the 0-255 scale the channels are, so the clamp
|
|
278
|
+
// has to be too. Bounding it to 0-1 collapsed it to 1 for every
|
|
279
|
+
// real colour, which made the ratio tiny and crushed the result to
|
|
280
|
+
// near-black instead of darkening it: rgba(20, 52, 204, 0.8) at 20%
|
|
281
|
+
// came back rgba(0, 1, 3, 1).
|
|
282
|
+
const luminance = 0.3 * r + 0.59 * g + 0.11 * b;
|
|
283
|
+
let newLuminance = luminance * (1 - amount / 100);
|
|
284
|
+
newLuminance = Math.max(0, Math.min(255, newLuminance));
|
|
285
|
+
const ratio = newLuminance / (luminance || 1); // no division by zero
|
|
286
|
+
r = Math.round(r * ratio);
|
|
287
|
+
g = Math.round(g * ratio);
|
|
288
|
+
b = Math.round(b * ratio);
|
|
289
|
+
// Adjust alpha
|
|
290
|
+
a = a + amount / 100;
|
|
291
|
+
a = Math.max(0, Math.min(1, a)); // within 0 and 1
|
|
292
|
+
colorOut = `rgba(${r}, ${g}, ${b}, ${a})`;
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
// Adjust the color for RGB or Hex
|
|
296
|
+
if (amount > 0) {
|
|
297
|
+
r = Math.max(0, r - amount);
|
|
298
|
+
g = Math.max(0, g - amount);
|
|
299
|
+
b = Math.max(0, b - amount);
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
amount = Math.abs(amount); // positive for lightening
|
|
303
|
+
r = Math.min(255, r + amount);
|
|
304
|
+
g = Math.min(255, g + amount);
|
|
305
|
+
b = Math.min(255, b + amount);
|
|
306
|
+
}
|
|
307
|
+
colorOut = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
catch (e) {
|
|
311
|
+
console.error(`Unsupported color format: ${colorIn} - Error: ${e}`);
|
|
312
|
+
}
|
|
313
|
+
return colorOut;
|
|
314
|
+
}
|
|
229
315
|
|
|
230
316
|
Object.defineProperty(buildChatWidgetChannel$1, "__esModule", { value: true });
|
|
231
317
|
buildChatWidgetChannel$1.buildChatWidgetChannel = buildChatWidgetChannel;
|
|
@@ -238,7 +324,7 @@ function buildChatWidgetChannel(props) {
|
|
|
238
324
|
// Only a colour whose contrast can actually be computed, so the background
|
|
239
325
|
// and the text on it are always a matched pair rather than one scraped
|
|
240
326
|
// value and one guess.
|
|
241
|
-
const primaryColor = (0, color_1.
|
|
327
|
+
const primaryColor = (0, color_1.usableColorOr)(props.primaryColor, DEFAULT_PRIMARY);
|
|
242
328
|
return {
|
|
243
329
|
type: "chat-widget",
|
|
244
330
|
// MCP by default. The widget runs on a public page, so homeowner mode
|
|
@@ -252,7 +338,7 @@ function buildChatWidgetChannel(props) {
|
|
|
252
338
|
mode: "homeowner"
|
|
253
339
|
}
|
|
254
340
|
},
|
|
255
|
-
theme: buildChatTheme(primaryColor),
|
|
341
|
+
theme: buildChatTheme(primaryColor, props.secondaryColor),
|
|
256
342
|
actionBar: buildActionBar({ apiUrl, formWidgetKey, phoneNumber })
|
|
257
343
|
};
|
|
258
344
|
}
|
|
@@ -303,19 +389,49 @@ function buildActionBar(props) {
|
|
|
303
389
|
};
|
|
304
390
|
}
|
|
305
391
|
/**
|
|
306
|
-
*
|
|
392
|
+
* The theme a new chat widget starts with, from the business's own colour.
|
|
307
393
|
*
|
|
308
|
-
*
|
|
309
|
-
*
|
|
310
|
-
* widget
|
|
394
|
+
* A faithful port of stentor-client's buildDefaultChatTheme, deliberately: the
|
|
395
|
+
* point of moving it is that onboarding can call this instead of its own copy,
|
|
396
|
+
* and that migration should not restyle every widget created afterwards. A
|
|
397
|
+
* thinner theme would have quietly dropped the CTA, message, input, footer and
|
|
398
|
+
* button styling that new widgets have today.
|
|
399
|
+
*
|
|
400
|
+
* The one change is how the contrast colour is derived — see below.
|
|
311
401
|
*/
|
|
312
|
-
function buildChatTheme(primaryColor) {
|
|
313
|
-
const
|
|
402
|
+
function buildChatTheme(primaryColor, secondaryColor) {
|
|
403
|
+
const fontFamily = "RobotoRegular";
|
|
404
|
+
// secondaryColor is the colour of text sitting ON primaryColor — header
|
|
405
|
+
// title, subtitle, footer branding. Left unset it is computed, which is
|
|
406
|
+
// what makes the theme readable against whatever colour was scraped off
|
|
407
|
+
// the business's own site.
|
|
408
|
+
if (!secondaryColor) {
|
|
409
|
+
secondaryColor = (0, color_1.readableTextOn)(primaryColor);
|
|
410
|
+
}
|
|
314
411
|
return {
|
|
315
412
|
zIndex: "10000",
|
|
316
413
|
border: {
|
|
317
414
|
color: primaryColor,
|
|
318
|
-
radius: "10px"
|
|
415
|
+
radius: "10px",
|
|
416
|
+
},
|
|
417
|
+
carousel: {
|
|
418
|
+
button: {
|
|
419
|
+
color: primaryColor,
|
|
420
|
+
},
|
|
421
|
+
subtitle: {
|
|
422
|
+
color: "#979797",
|
|
423
|
+
fontFamily,
|
|
424
|
+
fontSize: "12px",
|
|
425
|
+
fontStyle: "normal",
|
|
426
|
+
fontWeight: "normal",
|
|
427
|
+
},
|
|
428
|
+
title: {
|
|
429
|
+
color: "#000",
|
|
430
|
+
fontFamily,
|
|
431
|
+
fontSize: "14px",
|
|
432
|
+
fontStyle: "normal",
|
|
433
|
+
fontWeight: "bold",
|
|
434
|
+
},
|
|
319
435
|
},
|
|
320
436
|
chatButton: {
|
|
321
437
|
background: primaryColor,
|
|
@@ -323,18 +439,147 @@ function buildChatTheme(primaryColor) {
|
|
|
323
439
|
bottom: "10px",
|
|
324
440
|
left: "10px",
|
|
325
441
|
right: "10px",
|
|
326
|
-
top: "10px"
|
|
327
|
-
}
|
|
442
|
+
top: "10px",
|
|
443
|
+
},
|
|
328
444
|
},
|
|
329
445
|
content: {
|
|
330
|
-
background: "#ffffff"
|
|
446
|
+
background: "#ffffff",
|
|
447
|
+
},
|
|
448
|
+
cta: {
|
|
449
|
+
background: "#e1e2e1",
|
|
450
|
+
text: {
|
|
451
|
+
// Use a dark color that contrasts well with the light grey background
|
|
452
|
+
// instead of primaryColor which may not have sufficient contrast
|
|
453
|
+
color: "#333333",
|
|
454
|
+
fontFamily,
|
|
455
|
+
fontSize: "14px",
|
|
456
|
+
},
|
|
457
|
+
},
|
|
458
|
+
footer: {
|
|
459
|
+
background: primaryColor,
|
|
460
|
+
border: {
|
|
461
|
+
color: primaryColor,
|
|
462
|
+
radius: "0px",
|
|
463
|
+
width: "0px",
|
|
464
|
+
},
|
|
465
|
+
branding: {
|
|
466
|
+
text: {
|
|
467
|
+
color: "#ffffff",
|
|
468
|
+
fontFamily,
|
|
469
|
+
fontSize: "14px",
|
|
470
|
+
fontWeight: "normal",
|
|
471
|
+
fontStyle: "normal",
|
|
472
|
+
},
|
|
473
|
+
},
|
|
331
474
|
},
|
|
332
475
|
header: {
|
|
333
476
|
background: primaryColor,
|
|
477
|
+
avatarBackground: "transparent",
|
|
478
|
+
border: {
|
|
479
|
+
color: primaryColor,
|
|
480
|
+
radius: "0px",
|
|
481
|
+
width: "0px",
|
|
482
|
+
},
|
|
334
483
|
text: {
|
|
335
|
-
color:
|
|
336
|
-
|
|
337
|
-
|
|
484
|
+
color: secondaryColor,
|
|
485
|
+
fontFamily,
|
|
486
|
+
fontSize: "16px",
|
|
487
|
+
fontWeight: "normal",
|
|
488
|
+
fontStyle: "normal",
|
|
489
|
+
},
|
|
490
|
+
subtitle: {
|
|
491
|
+
color: secondaryColor,
|
|
492
|
+
fontFamily,
|
|
493
|
+
fontSize: "10px",
|
|
494
|
+
fontWeight: "normal",
|
|
495
|
+
fontStyle: "normal",
|
|
496
|
+
},
|
|
497
|
+
},
|
|
498
|
+
input: {
|
|
499
|
+
background: "#ffffff",
|
|
500
|
+
border: {
|
|
501
|
+
radius: "20px",
|
|
502
|
+
},
|
|
503
|
+
text: {
|
|
504
|
+
color: "#000000",
|
|
505
|
+
fontFamily,
|
|
506
|
+
fontSize: "14px",
|
|
507
|
+
},
|
|
508
|
+
placeholder: {
|
|
509
|
+
color: "#e1e2e1",
|
|
510
|
+
fontFamily,
|
|
511
|
+
fontSize: "14px",
|
|
512
|
+
fontWeight: "normal",
|
|
513
|
+
fontStyle: "normal",
|
|
514
|
+
},
|
|
515
|
+
},
|
|
516
|
+
textTypingStatus: {
|
|
517
|
+
text: {
|
|
518
|
+
color: "#bfbfbf",
|
|
519
|
+
fontFamily,
|
|
520
|
+
fontSize: "14px",
|
|
521
|
+
fontWeight: "normal",
|
|
522
|
+
fontStyle: "normal",
|
|
523
|
+
},
|
|
524
|
+
},
|
|
525
|
+
menu: {
|
|
526
|
+
item: {
|
|
527
|
+
height: "24px",
|
|
528
|
+
text: {
|
|
529
|
+
fontSize: "14px",
|
|
530
|
+
},
|
|
531
|
+
},
|
|
532
|
+
},
|
|
533
|
+
menuButton: {
|
|
534
|
+
color: "#ffffff",
|
|
535
|
+
},
|
|
536
|
+
messages: {
|
|
537
|
+
maxWidth: "400px",
|
|
538
|
+
mine: {
|
|
539
|
+
bubbleColor: "#f2f2f2",
|
|
540
|
+
text: {
|
|
541
|
+
color: "#454545",
|
|
542
|
+
fontFamily,
|
|
543
|
+
fontSize: "18px",
|
|
544
|
+
fontStyle: "normal",
|
|
545
|
+
fontWeight: "normal",
|
|
546
|
+
},
|
|
547
|
+
},
|
|
548
|
+
others: {
|
|
549
|
+
bubbleColor: "#e1e2e1",
|
|
550
|
+
text: {
|
|
551
|
+
color: "#262726",
|
|
552
|
+
fontFamily,
|
|
553
|
+
fontSize: "18px",
|
|
554
|
+
fontStyle: "normal",
|
|
555
|
+
fontWeight: "normal",
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
padding: {
|
|
559
|
+
bottom: "0px",
|
|
560
|
+
left: "20px",
|
|
561
|
+
right: "16px",
|
|
562
|
+
top: "16px",
|
|
563
|
+
},
|
|
564
|
+
},
|
|
565
|
+
refreshButton: {
|
|
566
|
+
color: secondaryColor,
|
|
567
|
+
},
|
|
568
|
+
minimizeButton: {
|
|
569
|
+
color: secondaryColor,
|
|
570
|
+
},
|
|
571
|
+
cancelButton: {
|
|
572
|
+
color: secondaryColor,
|
|
573
|
+
},
|
|
574
|
+
primaryColor: primaryColor,
|
|
575
|
+
sendButton: {
|
|
576
|
+
color: "#505050",
|
|
577
|
+
width: "20px",
|
|
578
|
+
},
|
|
579
|
+
size: {
|
|
580
|
+
width: "500px",
|
|
581
|
+
height: "700px",
|
|
582
|
+
},
|
|
338
583
|
};
|
|
339
584
|
}
|
|
340
585
|
|