@xapp/stentor-chat-widget 1.95.2 → 1.97.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/lib/__clientTheme.d.ts +12 -0
- package/lib/__clientTheme.js +250 -0
- package/lib/__clientTheme.js.map +1 -0
- package/lib/__tests__/buildChatWidgetChannel.test.d.ts +1 -0
- package/lib/__tests__/buildChatWidgetChannel.test.js +115 -0
- package/lib/__tests__/buildChatWidgetChannel.test.js.map +1 -0
- package/lib/__tests__/color.test.d.ts +1 -0
- package/lib/__tests__/color.test.js +157 -0
- package/lib/__tests__/color.test.js.map +1 -0
- package/lib/__tests__/themeParity.test.d.ts +1 -0
- package/lib/__tests__/themeParity.test.js +36 -0
- package/lib/__tests__/themeParity.test.js.map +1 -0
- package/lib/buildChatWidgetChannel.d.ts +62 -0
- package/lib/buildChatWidgetChannel.js +271 -0
- package/lib/buildChatWidgetChannel.js.map +1 -0
- package/lib/color.d.ts +60 -0
- package/lib/color.js +243 -0
- package/lib/color.js.map +1 -0
- package/lib/index.d.ts +2 -0
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/package.json +6 -2
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
type WidgetTheme = any;
|
|
2
|
+
export declare function parseRgb(colorString: string): {
|
|
3
|
+
r: number;
|
|
4
|
+
g: number;
|
|
5
|
+
b: number;
|
|
6
|
+
a?: number;
|
|
7
|
+
} | null;
|
|
8
|
+
export declare function invertColorRgb(rgb: string, bw?: boolean): string;
|
|
9
|
+
export declare function invertColorHEX(hex: string, bw?: boolean): string;
|
|
10
|
+
export declare function invertColor(color: string, bw?: boolean): string;
|
|
11
|
+
export declare function buildDefaultChatTheme(primaryColor: string, secondaryColor?: string): WidgetTheme;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseRgb = parseRgb;
|
|
4
|
+
exports.invertColorRgb = invertColorRgb;
|
|
5
|
+
exports.invertColorHEX = invertColorHEX;
|
|
6
|
+
exports.invertColor = invertColor;
|
|
7
|
+
exports.buildDefaultChatTheme = buildDefaultChatTheme;
|
|
8
|
+
function padZero(str, len = 2) { const zeros = new Array(len).join("0"); return (zeros + str).slice(-len); }
|
|
9
|
+
function parseRgb(colorString) {
|
|
10
|
+
const rgbaRegex = /^rgba?\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)$/;
|
|
11
|
+
const rgbRegex = /^rgb?\((\d+),\s*(\d+),\s*(\d+)\)$/;
|
|
12
|
+
let match;
|
|
13
|
+
// eslint-disable-next-line no-cond-assign
|
|
14
|
+
if (match = colorString.match(rgbaRegex)) {
|
|
15
|
+
const r = parseInt(match[1]);
|
|
16
|
+
const g = parseInt(match[2]);
|
|
17
|
+
const b = parseInt(match[3]);
|
|
18
|
+
const a = parseFloat(match[4]);
|
|
19
|
+
return { r, g, b, a };
|
|
20
|
+
// eslint-disable-next-line no-cond-assign
|
|
21
|
+
}
|
|
22
|
+
else if (match = colorString.match(rgbRegex)) {
|
|
23
|
+
const r = parseInt(match[1]);
|
|
24
|
+
const g = parseInt(match[2]);
|
|
25
|
+
const b = parseInt(match[3]);
|
|
26
|
+
return { r, g, b };
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
function invertColorRgb(rgb, bw) {
|
|
33
|
+
const rgba = parseRgb(rgb);
|
|
34
|
+
if (!rgba) {
|
|
35
|
+
return rgb;
|
|
36
|
+
}
|
|
37
|
+
const { r, g, b } = rgba;
|
|
38
|
+
if (bw) {
|
|
39
|
+
// http://stackoverflow.com/a/3943023/112731
|
|
40
|
+
return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? "rgba(0, 0, 0, 1)" : "rgba(255, 255, 255, 1)";
|
|
41
|
+
}
|
|
42
|
+
return `rgba(${255 - r}, ${255 - g}, ${255 - b}, 1)`;
|
|
43
|
+
}
|
|
44
|
+
function invertColorHEX(hex, bw) {
|
|
45
|
+
if (!hex) {
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
if (hex.indexOf("#") === 0) {
|
|
49
|
+
hex = hex.slice(1);
|
|
50
|
+
}
|
|
51
|
+
// convert 3-digit hex to 6-digits.
|
|
52
|
+
if (hex.length === 3) {
|
|
53
|
+
hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
|
|
54
|
+
}
|
|
55
|
+
if (hex.length !== 6) {
|
|
56
|
+
throw new Error("Invalid HEX color.");
|
|
57
|
+
}
|
|
58
|
+
const r = parseInt(hex.slice(0, 2), 16);
|
|
59
|
+
const g = parseInt(hex.slice(2, 4), 16);
|
|
60
|
+
const b = parseInt(hex.slice(4, 6), 16);
|
|
61
|
+
if (bw) {
|
|
62
|
+
// http://stackoverflow.com/a/3943023/112731
|
|
63
|
+
return r * 0.299 + g * 0.587 + b * 0.114 > 186 ? "#000000" : "#FFFFFF";
|
|
64
|
+
}
|
|
65
|
+
// pad each with zeros and return
|
|
66
|
+
return "#" + padZero((255 - r).toString(16)) + padZero((255 - g).toString(16)) + padZero((255 - b).toString(16));
|
|
67
|
+
}
|
|
68
|
+
function invertColor(color, bw) {
|
|
69
|
+
return color.startsWith("#") ? invertColorHEX(color, bw) : invertColorRgb(color, bw);
|
|
70
|
+
}
|
|
71
|
+
function buildDefaultChatTheme(primaryColor, secondaryColor) {
|
|
72
|
+
const fontFamily = "RobotoRegular";
|
|
73
|
+
if (!secondaryColor) {
|
|
74
|
+
secondaryColor = invertColor(primaryColor, true);
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
zIndex: "10000",
|
|
78
|
+
border: {
|
|
79
|
+
color: primaryColor,
|
|
80
|
+
radius: "10px",
|
|
81
|
+
},
|
|
82
|
+
carousel: {
|
|
83
|
+
button: {
|
|
84
|
+
color: primaryColor,
|
|
85
|
+
},
|
|
86
|
+
subtitle: {
|
|
87
|
+
color: "#979797",
|
|
88
|
+
fontFamily,
|
|
89
|
+
fontSize: "12px",
|
|
90
|
+
fontStyle: "normal",
|
|
91
|
+
fontWeight: "normal",
|
|
92
|
+
},
|
|
93
|
+
title: {
|
|
94
|
+
color: "#000",
|
|
95
|
+
fontFamily,
|
|
96
|
+
fontSize: "14px",
|
|
97
|
+
fontStyle: "normal",
|
|
98
|
+
fontWeight: "bold",
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
chatButton: {
|
|
102
|
+
background: primaryColor,
|
|
103
|
+
margin: {
|
|
104
|
+
bottom: "10px",
|
|
105
|
+
left: "10px",
|
|
106
|
+
right: "10px",
|
|
107
|
+
top: "10px",
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
content: {
|
|
111
|
+
background: "#ffffff",
|
|
112
|
+
},
|
|
113
|
+
cta: {
|
|
114
|
+
background: "#e1e2e1",
|
|
115
|
+
text: {
|
|
116
|
+
// Use a dark color that contrasts well with the light grey background
|
|
117
|
+
// instead of primaryColor which may not have sufficient contrast
|
|
118
|
+
color: "#333333",
|
|
119
|
+
fontFamily,
|
|
120
|
+
fontSize: "14px",
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
footer: {
|
|
124
|
+
background: primaryColor,
|
|
125
|
+
border: {
|
|
126
|
+
color: primaryColor,
|
|
127
|
+
radius: "0px",
|
|
128
|
+
width: "0px",
|
|
129
|
+
},
|
|
130
|
+
branding: {
|
|
131
|
+
text: {
|
|
132
|
+
color: "#ffffff",
|
|
133
|
+
fontFamily,
|
|
134
|
+
fontSize: "14px",
|
|
135
|
+
fontWeight: "normal",
|
|
136
|
+
fontStyle: "normal",
|
|
137
|
+
},
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
header: {
|
|
141
|
+
background: primaryColor,
|
|
142
|
+
avatarBackground: "transparent",
|
|
143
|
+
border: {
|
|
144
|
+
color: primaryColor,
|
|
145
|
+
radius: "0px",
|
|
146
|
+
width: "0px",
|
|
147
|
+
},
|
|
148
|
+
text: {
|
|
149
|
+
color: secondaryColor,
|
|
150
|
+
fontFamily,
|
|
151
|
+
fontSize: "16px",
|
|
152
|
+
fontWeight: "normal",
|
|
153
|
+
fontStyle: "normal",
|
|
154
|
+
},
|
|
155
|
+
subtitle: {
|
|
156
|
+
color: secondaryColor,
|
|
157
|
+
fontFamily,
|
|
158
|
+
fontSize: "10px",
|
|
159
|
+
fontWeight: "normal",
|
|
160
|
+
fontStyle: "normal",
|
|
161
|
+
},
|
|
162
|
+
},
|
|
163
|
+
input: {
|
|
164
|
+
background: "#ffffff",
|
|
165
|
+
border: {
|
|
166
|
+
radius: "20px",
|
|
167
|
+
},
|
|
168
|
+
text: {
|
|
169
|
+
color: "#000000",
|
|
170
|
+
fontFamily,
|
|
171
|
+
fontSize: "14px",
|
|
172
|
+
},
|
|
173
|
+
placeholder: {
|
|
174
|
+
color: "#e1e2e1",
|
|
175
|
+
fontFamily,
|
|
176
|
+
fontSize: "14px",
|
|
177
|
+
fontWeight: "normal",
|
|
178
|
+
fontStyle: "normal",
|
|
179
|
+
},
|
|
180
|
+
},
|
|
181
|
+
textTypingStatus: {
|
|
182
|
+
text: {
|
|
183
|
+
color: "#bfbfbf",
|
|
184
|
+
fontFamily,
|
|
185
|
+
fontSize: "14px",
|
|
186
|
+
fontWeight: "normal",
|
|
187
|
+
fontStyle: "normal",
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
menu: {
|
|
191
|
+
item: {
|
|
192
|
+
height: "24px",
|
|
193
|
+
text: {
|
|
194
|
+
fontSize: "14px",
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
menuButton: {
|
|
199
|
+
color: "#ffffff",
|
|
200
|
+
},
|
|
201
|
+
messages: {
|
|
202
|
+
maxWidth: "400px",
|
|
203
|
+
mine: {
|
|
204
|
+
bubbleColor: "#f2f2f2",
|
|
205
|
+
text: {
|
|
206
|
+
color: "#454545",
|
|
207
|
+
fontFamily,
|
|
208
|
+
fontSize: "18px",
|
|
209
|
+
fontStyle: "normal",
|
|
210
|
+
fontWeight: "normal",
|
|
211
|
+
},
|
|
212
|
+
},
|
|
213
|
+
others: {
|
|
214
|
+
bubbleColor: "#e1e2e1",
|
|
215
|
+
text: {
|
|
216
|
+
color: "#262726",
|
|
217
|
+
fontFamily,
|
|
218
|
+
fontSize: "18px",
|
|
219
|
+
fontStyle: "normal",
|
|
220
|
+
fontWeight: "normal",
|
|
221
|
+
},
|
|
222
|
+
},
|
|
223
|
+
padding: {
|
|
224
|
+
bottom: "0px",
|
|
225
|
+
left: "20px",
|
|
226
|
+
right: "16px",
|
|
227
|
+
top: "16px",
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
refreshButton: {
|
|
231
|
+
color: secondaryColor,
|
|
232
|
+
},
|
|
233
|
+
minimizeButton: {
|
|
234
|
+
color: secondaryColor,
|
|
235
|
+
},
|
|
236
|
+
cancelButton: {
|
|
237
|
+
color: secondaryColor,
|
|
238
|
+
},
|
|
239
|
+
primaryColor: primaryColor,
|
|
240
|
+
sendButton: {
|
|
241
|
+
color: "#505050",
|
|
242
|
+
width: "20px",
|
|
243
|
+
},
|
|
244
|
+
size: {
|
|
245
|
+
width: "500px",
|
|
246
|
+
height: "700px",
|
|
247
|
+
},
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=__clientTheme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"__clientTheme.js","sourceRoot":"","sources":["../src/__clientTheme.ts"],"names":[],"mappings":";;AAGA,4BAwBC;AACD,wCAaC;AAED,wCAyBC;AAED,kCAEC;AACD,sDAoLC;AA3PD,SAAS,OAAO,CAAC,GAAW,EAAE,GAAG,GAAG,CAAC,IAAY,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,GAAG,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAC5H,SAAgB,QAAQ,CAAC,WAAmB;IACxC,MAAM,SAAS,GAAG,gDAAgD,CAAC;IACnE,MAAM,QAAQ,GAAG,mCAAmC,CAAC;IAErD,IAAI,KAAsB,CAAC;IAE3B,0CAA0C;IAC1C,IAAI,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAE/B,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;QACtB,0CAA0C;IAC9C,CAAC;SAAM,IAAI,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7C,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7B,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACvB,CAAC;SAAM,CAAC;QACJ,OAAO,IAAI,CAAC;IAChB,CAAC;AACL,CAAC;AACD,SAAgB,cAAc,CAAC,GAAW,EAAE,EAAY;IACpD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC3B,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,OAAO,GAAG,CAAC;IACf,CAAC;IAED,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC;IACzB,IAAI,EAAE,EAAE,CAAC;QACL,4CAA4C;QAC5C,OAAO,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,wBAAwB,CAAC;IACnG,CAAC;IAED,OAAO,QAAQ,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,MAAM,CAAC;AACzD,CAAC;AAED,SAAgB,cAAc,CAAC,GAAW,EAAE,EAAY;IACpD,IAAI,CAAC,GAAG,EAAE,CAAC;QACP,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,mCAAmC;IACnC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnB,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;IAC1C,CAAC;IACD,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxC,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAExC,IAAI,EAAE,EAAE,CAAC;QACL,4CAA4C;QAC5C,OAAO,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IAC3E,CAAC;IACD,iCAAiC;IACjC,OAAO,GAAG,GAAG,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;AACrH,CAAC;AAED,SAAgB,WAAW,CAAC,KAAa,EAAE,EAAY;IACnD,OAAO,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACzF,CAAC;AACD,SAAgB,qBAAqB,CAAC,YAAoB,EAAE,cAAuB;IAC/E,MAAM,UAAU,GAAG,eAAe,CAAC;IAEnC,IAAI,CAAC,cAAc,EAAE,CAAC;QAClB,cAAc,GAAG,WAAW,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACrD,CAAC;IAED,OAAO;QACH,MAAM,EAAE,OAAO;QACf,MAAM,EAAE;YACJ,KAAK,EAAE,YAAY;YACnB,MAAM,EAAE,MAAM;SACjB;QACD,QAAQ,EAAE;YACN,MAAM,EAAE;gBACJ,KAAK,EAAE,YAAY;aACtB;YACD,QAAQ,EAAE;gBACN,KAAK,EAAE,SAAS;gBAChB,UAAU;gBACV,QAAQ,EAAE,MAAM;gBAChB,SAAS,EAAE,QAAQ;gBACnB,UAAU,EAAE,QAAQ;aACvB;YACD,KAAK,EAAE;gBACH,KAAK,EAAE,MAAM;gBACb,UAAU;gBACV,QAAQ,EAAE,MAAM;gBAChB,SAAS,EAAE,QAAQ;gBACnB,UAAU,EAAE,MAAM;aACrB;SACJ;QACD,UAAU,EAAE;YACR,UAAU,EAAE,YAAY;YACxB,MAAM,EAAE;gBACJ,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,MAAM;gBACb,GAAG,EAAE,MAAM;aACd;SACJ;QACD,OAAO,EAAE;YACL,UAAU,EAAE,SAAS;SACxB;QACD,GAAG,EAAE;YACD,UAAU,EAAE,SAAS;YACrB,IAAI,EAAE;gBACF,sEAAsE;gBACtE,iEAAiE;gBACjE,KAAK,EAAE,SAAS;gBAChB,UAAU;gBACV,QAAQ,EAAE,MAAM;aACnB;SACJ;QACD,MAAM,EAAE;YACJ,UAAU,EAAE,YAAY;YACxB,MAAM,EAAE;gBACJ,KAAK,EAAE,YAAY;gBACnB,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,KAAK;aACf;YACD,QAAQ,EAAE;gBACN,IAAI,EAAE;oBACF,KAAK,EAAE,SAAS;oBAChB,UAAU;oBACV,QAAQ,EAAE,MAAM;oBAChB,UAAU,EAAE,QAAQ;oBACpB,SAAS,EAAE,QAAQ;iBACtB;aACJ;SACJ;QACD,MAAM,EAAE;YACJ,UAAU,EAAE,YAAY;YACxB,gBAAgB,EAAE,aAAa;YAC/B,MAAM,EAAE;gBACJ,KAAK,EAAE,YAAY;gBACnB,MAAM,EAAE,KAAK;gBACb,KAAK,EAAE,KAAK;aACf;YACD,IAAI,EAAE;gBACF,KAAK,EAAE,cAAc;gBACrB,UAAU;gBACV,QAAQ,EAAE,MAAM;gBAChB,UAAU,EAAE,QAAQ;gBACpB,SAAS,EAAE,QAAQ;aACtB;YACD,QAAQ,EAAE;gBACN,KAAK,EAAE,cAAc;gBACrB,UAAU;gBACV,QAAQ,EAAE,MAAM;gBAChB,UAAU,EAAE,QAAQ;gBACpB,SAAS,EAAE,QAAQ;aACtB;SACJ;QACD,KAAK,EAAE;YACH,UAAU,EAAE,SAAS;YACrB,MAAM,EAAE;gBACJ,MAAM,EAAE,MAAM;aACjB;YACD,IAAI,EAAE;gBACF,KAAK,EAAE,SAAS;gBAChB,UAAU;gBACV,QAAQ,EAAE,MAAM;aACnB;YACD,WAAW,EAAE;gBACT,KAAK,EAAE,SAAS;gBAChB,UAAU;gBACV,QAAQ,EAAE,MAAM;gBAChB,UAAU,EAAE,QAAQ;gBACpB,SAAS,EAAE,QAAQ;aACtB;SACJ;QACD,gBAAgB,EAAE;YACd,IAAI,EAAE;gBACF,KAAK,EAAE,SAAS;gBAChB,UAAU;gBACV,QAAQ,EAAE,MAAM;gBAChB,UAAU,EAAE,QAAQ;gBACpB,SAAS,EAAE,QAAQ;aACtB;SACJ;QACD,IAAI,EAAE;YACF,IAAI,EAAE;gBACF,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE;oBACF,QAAQ,EAAE,MAAM;iBACnB;aACJ;SACJ;QACD,UAAU,EAAE;YACR,KAAK,EAAE,SAAS;SACnB;QACD,QAAQ,EAAE;YACN,QAAQ,EAAE,OAAO;YACjB,IAAI,EAAE;gBACF,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE;oBACF,KAAK,EAAE,SAAS;oBAChB,UAAU;oBACV,QAAQ,EAAE,MAAM;oBAChB,SAAS,EAAE,QAAQ;oBACnB,UAAU,EAAE,QAAQ;iBACvB;aACJ;YACD,MAAM,EAAE;gBACJ,WAAW,EAAE,SAAS;gBACtB,IAAI,EAAE;oBACF,KAAK,EAAE,SAAS;oBAChB,UAAU;oBACV,QAAQ,EAAE,MAAM;oBAChB,SAAS,EAAE,QAAQ;oBACnB,UAAU,EAAE,QAAQ;iBACvB;aACJ;YACD,OAAO,EAAE;gBACL,MAAM,EAAE,KAAK;gBACb,IAAI,EAAE,MAAM;gBACZ,KAAK,EAAE,MAAM;gBACb,GAAG,EAAE,MAAM;aACd;SACJ;QACD,aAAa,EAAE;YACX,KAAK,EAAE,cAAc;SACxB;QACD,cAAc,EAAE;YACZ,KAAK,EAAE,cAAc;SACxB;QACD,YAAY,EAAE;YACV,KAAK,EAAE,cAAc;SACxB;QACD,YAAY,EAAE,YAAY;QAC1B,UAAU,EAAE;YACR,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,MAAM;SAChB;QACD,IAAI,EAAE;YACF,KAAK,EAAE,OAAO;YACd,MAAM,EAAE,OAAO;SAClB;KACJ,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const buildChatWidgetChannel_1 = require("../buildChatWidgetChannel");
|
|
4
|
+
/**
|
|
5
|
+
* The chat widget a new app starts with.
|
|
6
|
+
*
|
|
7
|
+
* Built here rather than in stentor-client so Studio can create the same widget
|
|
8
|
+
* server-side for a get.xapp.ai signup. Two builders would mean onboarding and
|
|
9
|
+
* the funnel producing subtly different widgets from the same inputs.
|
|
10
|
+
*/
|
|
11
|
+
const BASE = {
|
|
12
|
+
appId: "buehler-air",
|
|
13
|
+
apiUrl: "https://api.xapp.ai",
|
|
14
|
+
mcpUrl: "https://agent.xapp.ai"
|
|
15
|
+
};
|
|
16
|
+
describe("buildChatWidgetChannel", () => {
|
|
17
|
+
it("connects over MCP by default", () => {
|
|
18
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(BASE);
|
|
19
|
+
expect(channel.connection.type).toEqual("mcp");
|
|
20
|
+
expect(channel.connection.serverUrl).toEqual("https://agent.xapp.ai/buehler-air");
|
|
21
|
+
});
|
|
22
|
+
it("uses homeowner mode, which needs no auth token", () => {
|
|
23
|
+
var _a;
|
|
24
|
+
// The widget runs on a public page. business_owner mode requires a
|
|
25
|
+
// token, and a token on a public page is not a token.
|
|
26
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(BASE);
|
|
27
|
+
expect((_a = channel.connection.mcp) === null || _a === void 0 ? void 0 : _a.mode).toEqual("homeowner");
|
|
28
|
+
expect(JSON.stringify(channel)).not.toContain("authToken");
|
|
29
|
+
});
|
|
30
|
+
it("turns the action bar on", () => {
|
|
31
|
+
var _a;
|
|
32
|
+
// Chat is not on the default tier, but the action bar is how people
|
|
33
|
+
// reach booking and the phone, so it ships enabled.
|
|
34
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(BASE);
|
|
35
|
+
expect((_a = channel.actionBar) === null || _a === void 0 ? void 0 : _a.enabled).toEqual(true);
|
|
36
|
+
});
|
|
37
|
+
it("offers booking first, ahead of calling and chat", () => {
|
|
38
|
+
// Booking is what the business is paying for. Calling is the fallback
|
|
39
|
+
// for people who will not use a form, and chat is last because it is
|
|
40
|
+
// the least likely to be enabled on their tier.
|
|
41
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(Object.assign(Object.assign({}, BASE), { formWidgetKey: "fw-1", phoneNumber: "+19042338831" }));
|
|
42
|
+
expect(channel.actionBar.buttons.map((b) => b.type)).toEqual(["schedule", "phone", "chat"]);
|
|
43
|
+
expect(channel.actionBar.buttons[0].label).toBeDefined();
|
|
44
|
+
});
|
|
45
|
+
it("carries the form widget's key so booking opens our form", () => {
|
|
46
|
+
var _a, _b, _c, _d;
|
|
47
|
+
// The button opens the form widget, which is a separate channel with
|
|
48
|
+
// its own key. Without it the button has nothing to open.
|
|
49
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(Object.assign(Object.assign({}, BASE), { formWidgetKey: "fw-key-123" }));
|
|
50
|
+
const book = channel.actionBar.buttons.find((b) => b.type === "schedule");
|
|
51
|
+
expect((_b = (_a = book.formConfig) === null || _a === void 0 ? void 0 : _a.api) === null || _b === void 0 ? void 0 : _b.key).toEqual("fw-key-123");
|
|
52
|
+
expect((_d = (_c = book.formConfig) === null || _c === void 0 ? void 0 : _c.api) === null || _d === void 0 ? void 0 : _d.url).toEqual("https://api.xapp.ai");
|
|
53
|
+
});
|
|
54
|
+
it("omits the booking button until the form widget exists", () => {
|
|
55
|
+
// The form widget is created first and its key read back. A booking
|
|
56
|
+
// button with no form behind it is a button that does nothing.
|
|
57
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(BASE);
|
|
58
|
+
expect(channel.actionBar.buttons.some((b) => b.type === "schedule")).toEqual(false);
|
|
59
|
+
});
|
|
60
|
+
it("adds click-to-call when the crawl found a number", () => {
|
|
61
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(Object.assign(Object.assign({}, BASE), { phoneNumber: "+19042338831" }));
|
|
62
|
+
const phone = channel.actionBar.buttons.find((b) => b.type === "phone");
|
|
63
|
+
expect(phone.phoneNumber).toEqual("+19042338831");
|
|
64
|
+
});
|
|
65
|
+
it("leaves the phone button out when there is no number", () => {
|
|
66
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(BASE);
|
|
67
|
+
expect(channel.actionBar.buttons.some((b) => b.type === "phone")).toEqual(false);
|
|
68
|
+
});
|
|
69
|
+
it("always offers chat itself", () => {
|
|
70
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(BASE);
|
|
71
|
+
expect(channel.actionBar.buttons.some((b) => b.type === "chat")).toEqual(true);
|
|
72
|
+
});
|
|
73
|
+
it("themes from the business's own colour", () => {
|
|
74
|
+
var _a, _b;
|
|
75
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(Object.assign(Object.assign({}, BASE), { primaryColor: "#f47c4c" }));
|
|
76
|
+
expect((_b = (_a = channel.theme) === null || _a === void 0 ? void 0 : _a.chatButton) === null || _b === void 0 ? void 0 : _b.background).toEqual("#f47c4c");
|
|
77
|
+
});
|
|
78
|
+
it("picks header text that reads on that colour rather than assuming dark", () => {
|
|
79
|
+
var _a, _b, _c;
|
|
80
|
+
// #f47c4c scores 154 for perceived brightness against a threshold of
|
|
81
|
+
// 186, so it takes white text. Assuming dark here is how a widget ships
|
|
82
|
+
// unreadable. The chat button carries no text of its own — it is an
|
|
83
|
+
// icon on a background — so the header is where this shows.
|
|
84
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(Object.assign(Object.assign({}, BASE), { primaryColor: "#f47c4c" }));
|
|
85
|
+
expect((_c = (_b = (_a = channel.theme) === null || _a === void 0 ? void 0 : _a.header) === null || _b === void 0 ? void 0 : _b.text) === null || _c === void 0 ? void 0 : _c.color).toEqual("#FFFFFF");
|
|
86
|
+
});
|
|
87
|
+
it("ignores a colour whose contrast cannot be computed", () => {
|
|
88
|
+
var _a, _b, _c, _d, _e;
|
|
89
|
+
// A scraped `orange` is valid CSS and unusable here: we cannot work out
|
|
90
|
+
// what text reads on it. Theming the header with it and guessing the
|
|
91
|
+
// text colour is how you ship invisible text, so the neutral default is
|
|
92
|
+
// used for both instead — background and foreground always a computed
|
|
93
|
+
// pair.
|
|
94
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(Object.assign(Object.assign({}, BASE), { primaryColor: "orange" }));
|
|
95
|
+
expect((_b = (_a = channel.theme) === null || _a === void 0 ? void 0 : _a.header) === null || _b === void 0 ? void 0 : _b.background).not.toEqual("orange");
|
|
96
|
+
expect(["#000000", "#FFFFFF"]).toContain((_e = (_d = (_c = channel.theme) === null || _c === void 0 ? void 0 : _c.header) === null || _d === void 0 ? void 0 : _d.text) === null || _e === void 0 ? void 0 : _e.color);
|
|
97
|
+
});
|
|
98
|
+
it("keeps a colour it can compute against", () => {
|
|
99
|
+
var _a, _b, _c, _d, _e;
|
|
100
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(Object.assign(Object.assign({}, BASE), { primaryColor: "rgb(20, 52, 204)" }));
|
|
101
|
+
expect((_b = (_a = channel.theme) === null || _a === void 0 ? void 0 : _a.header) === null || _b === void 0 ? void 0 : _b.background).toEqual("rgb(20, 52, 204)");
|
|
102
|
+
expect((_e = (_d = (_c = channel.theme) === null || _c === void 0 ? void 0 : _c.header) === null || _d === void 0 ? void 0 : _d.text) === null || _e === void 0 ? void 0 : _e.color).toEqual("#FFFFFF");
|
|
103
|
+
});
|
|
104
|
+
it("still builds a widget when the crawl found no colour", () => {
|
|
105
|
+
const channel = (0, buildChatWidgetChannel_1.buildChatWidgetChannel)(BASE);
|
|
106
|
+
expect(channel.theme).toBeDefined();
|
|
107
|
+
expect(channel.type).toEqual("chat-widget");
|
|
108
|
+
});
|
|
109
|
+
it("does not invent an id", () => {
|
|
110
|
+
// The id is assigned when the channel is written. A builder that made
|
|
111
|
+
// one up would be creating a second source of truth for it.
|
|
112
|
+
expect((0, buildChatWidgetChannel_1.buildChatWidgetChannel)(BASE).id).toBeUndefined();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
//# sourceMappingURL=buildChatWidgetChannel.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buildChatWidgetChannel.test.js","sourceRoot":"","sources":["../../src/__tests__/buildChatWidgetChannel.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const color_1 = require("../color");
|
|
4
|
+
/**
|
|
5
|
+
* These decide whether a widget's text is legible on the colour we scraped off
|
|
6
|
+
* a customer's website, so the contrast rule matters more than the inversion.
|
|
7
|
+
*/
|
|
8
|
+
describe("invertColorHEX", () => {
|
|
9
|
+
it("inverts a colour", () => {
|
|
10
|
+
expect((0, color_1.invertColorHEX)("#ffffff")).toEqual("#000000");
|
|
11
|
+
expect((0, color_1.invertColorHEX)("#000000")).toEqual("#ffffff");
|
|
12
|
+
});
|
|
13
|
+
it("expands three-digit hex", () => {
|
|
14
|
+
expect((0, color_1.invertColorHEX)("#fff")).toEqual((0, color_1.invertColorHEX)("#ffffff"));
|
|
15
|
+
});
|
|
16
|
+
it("accepts a colour with no leading hash", () => {
|
|
17
|
+
expect((0, color_1.invertColorHEX)("ffffff")).toEqual("#000000");
|
|
18
|
+
});
|
|
19
|
+
it("returns black or white when asked for contrast rather than inversion", () => {
|
|
20
|
+
// A mid-tone inverts to another mid-tone, which is unreadable behind
|
|
21
|
+
// text. bw picks whichever of black or white actually reads.
|
|
22
|
+
//
|
|
23
|
+
// Buehler's orange looks light and is not: weighted for perceived
|
|
24
|
+
// brightness it scores 154 against a threshold of 186, so it takes
|
|
25
|
+
// white text. Eyeballing this is how you ship an unreadable widget.
|
|
26
|
+
expect((0, color_1.invertColorHEX)("#f47c4c", true)).toEqual("#FFFFFF");
|
|
27
|
+
expect((0, color_1.invertColorHEX)("#0b83b3", true)).toEqual("#FFFFFF");
|
|
28
|
+
expect((0, color_1.invertColorHEX)("#c1bdb2", true)).toEqual("#000000");
|
|
29
|
+
});
|
|
30
|
+
it("has no answer for a missing colour", () => {
|
|
31
|
+
expect((0, color_1.invertColorHEX)(undefined)).toBeUndefined();
|
|
32
|
+
expect((0, color_1.invertColorHEX)("")).toBeUndefined();
|
|
33
|
+
});
|
|
34
|
+
it("refuses a value that is not a colour", () => {
|
|
35
|
+
expect(() => (0, color_1.invertColorHEX)("#12345")).toThrow(/Invalid HEX/);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
describe("readableTextOn", () => {
|
|
39
|
+
it("picks the text colour that reads on the background", () => {
|
|
40
|
+
// From real crawls: Buehler's orange (154), Affordable Pest's grey
|
|
41
|
+
// (189) and XAPP's blue (60), against the 186 threshold.
|
|
42
|
+
expect((0, color_1.readableTextOn)("#f47c4c")).toEqual("#FFFFFF");
|
|
43
|
+
expect((0, color_1.readableTextOn)("#c1bdb2")).toEqual("#000000");
|
|
44
|
+
expect((0, color_1.readableTextOn)("#1434cc")).toEqual("#FFFFFF");
|
|
45
|
+
});
|
|
46
|
+
it("falls back to dark text when there is no background colour", () => {
|
|
47
|
+
// Better a readable default than a widget with white-on-white text
|
|
48
|
+
// because a crawl came back without a colour.
|
|
49
|
+
expect((0, color_1.readableTextOn)(undefined)).toEqual("#000000");
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe("invertColor", () => {
|
|
53
|
+
it("handles rgb as well as hex", () => {
|
|
54
|
+
// rgb input answers in rgb notation, as it always has. readableTextOn
|
|
55
|
+
// is the one that normalises, because a theme wants one shape.
|
|
56
|
+
expect((0, color_1.invertColor)("#ffffff", true)).toEqual("#000000");
|
|
57
|
+
expect((0, color_1.invertColor)("rgb(255, 255, 255)", true)).toEqual("rgba(0, 0, 0, 1)");
|
|
58
|
+
});
|
|
59
|
+
it("normalises rgb through readableTextOn", () => {
|
|
60
|
+
expect((0, color_1.readableTextOn)("rgb(255, 255, 255)")).toEqual("#000000");
|
|
61
|
+
expect((0, color_1.readableTextOn)("rgb(20, 52, 204)")).toEqual("#FFFFFF");
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe("readableTextOn with colours we cannot parse", () => {
|
|
65
|
+
it("never answers with the background it was given", () => {
|
|
66
|
+
// A CSS named colour is entirely plausible from a scrape — hand-written
|
|
67
|
+
// stylesheets are full of `orange`, `tomato`, `steelblue`. Returning it
|
|
68
|
+
// unchanged put the header text at exactly the header background.
|
|
69
|
+
expect((0, color_1.readableTextOn)("orange")).not.toEqual("orange");
|
|
70
|
+
expect((0, color_1.readableTextOn)("navy")).not.toEqual("navy");
|
|
71
|
+
});
|
|
72
|
+
it("only ever answers black or white", () => {
|
|
73
|
+
const answers = ["orange", "navy", "rgb( 255, 0, 0)", "RGB(255,0,0)", "hsl(9, 100%, 64%)", "#f47c4c", "not a colour"]
|
|
74
|
+
.map(color_1.readableTextOn);
|
|
75
|
+
answers.forEach((answer) => {
|
|
76
|
+
expect(["#000000", "#FFFFFF"]).toContain(answer);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe("isSupportedColor", () => {
|
|
81
|
+
it("recognises the notations we can compute contrast for", () => {
|
|
82
|
+
expect((0, color_1.isSupportedColor)("#f47c4c")).toEqual(true);
|
|
83
|
+
expect((0, color_1.isSupportedColor)("#fff")).toEqual(true);
|
|
84
|
+
expect((0, color_1.isSupportedColor)("rgb(255, 0, 0)")).toEqual(true);
|
|
85
|
+
expect((0, color_1.isSupportedColor)("rgba(255, 0, 0, 0.5)")).toEqual(true);
|
|
86
|
+
});
|
|
87
|
+
it("rejects everything else, including named colours", () => {
|
|
88
|
+
// Not "these are invalid" — they are perfectly good CSS. We just
|
|
89
|
+
// cannot work out what text reads on them, and a background whose
|
|
90
|
+
// contrast we cannot compute is one we must not use.
|
|
91
|
+
expect((0, color_1.isSupportedColor)("orange")).toEqual(false);
|
|
92
|
+
expect((0, color_1.isSupportedColor)("hsl(9, 100%, 64%)")).toEqual(false);
|
|
93
|
+
expect((0, color_1.isSupportedColor)("#12345")).toEqual(false);
|
|
94
|
+
expect((0, color_1.isSupportedColor)(undefined)).toEqual(false);
|
|
95
|
+
expect((0, color_1.isSupportedColor)("")).toEqual(false);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe("usableColorOr", () => {
|
|
99
|
+
it("keeps a colour we can compute contrast against", () => {
|
|
100
|
+
expect((0, color_1.usableColorOr)("#f47c4c", "#1AA7DC")).toEqual("#f47c4c");
|
|
101
|
+
expect((0, color_1.usableColorOr)("rgb(20, 52, 204)", "#1AA7DC")).toEqual("rgb(20, 52, 204)");
|
|
102
|
+
});
|
|
103
|
+
it("substitutes the fallback for anything else", () => {
|
|
104
|
+
// Including colours that are perfectly valid CSS. If we cannot work out
|
|
105
|
+
// what text reads on it, we must not use it as a background — the text
|
|
106
|
+
// colour would be a guess paired with an unknown.
|
|
107
|
+
expect((0, color_1.usableColorOr)("orange", "#1AA7DC")).toEqual("#1AA7DC");
|
|
108
|
+
expect((0, color_1.usableColorOr)("hsl(9, 100%, 64%)", "#1AA7DC")).toEqual("#1AA7DC");
|
|
109
|
+
expect((0, color_1.usableColorOr)(undefined, "#1AA7DC")).toEqual("#1AA7DC");
|
|
110
|
+
expect((0, color_1.usableColorOr)("", "#1AA7DC")).toEqual("#1AA7DC");
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
describe("darkenColor", () => {
|
|
114
|
+
it("darkens hex", () => {
|
|
115
|
+
expect((0, color_1.darkenColor)("#1434cc", 20)).toEqual("#0020b8");
|
|
116
|
+
});
|
|
117
|
+
it("darkens rgb without an alpha", () => {
|
|
118
|
+
expect((0, color_1.darkenColor)("rgb(20, 52, 204)", 20)).toEqual("#0020b8");
|
|
119
|
+
});
|
|
120
|
+
it("has no opinion about a missing colour", () => {
|
|
121
|
+
expect((0, color_1.darkenColor)(undefined, 20)).toBeUndefined();
|
|
122
|
+
});
|
|
123
|
+
it("returns unsupported input unchanged", () => {
|
|
124
|
+
expect((0, color_1.darkenColor)("orange", 20)).toEqual("orange");
|
|
125
|
+
});
|
|
126
|
+
/**
|
|
127
|
+
* Fixed here, and therefore the one place this package deliberately does
|
|
128
|
+
* not match stentor-client.
|
|
129
|
+
*
|
|
130
|
+
* The alpha branch computed luminance on the 0-255 scale the channels use
|
|
131
|
+
* and then clamped it to 0-1, so it collapsed to 1 for every real colour
|
|
132
|
+
* and the ratio crushed the result to near-black: rgba(20, 52, 204, 0.8)
|
|
133
|
+
* darkened by 20% came back rgba(0, 1, 3, 1). Clamping on the right scale
|
|
134
|
+
* makes it do what it says — scale each channel by 1 - amount/100.
|
|
135
|
+
*
|
|
136
|
+
* The client still has the old behaviour, so a form themed from an rgba
|
|
137
|
+
* colour will change appearance when it migrates onto this. That is the
|
|
138
|
+
* intended outcome rather than a regression: near-black was never what
|
|
139
|
+
* anyone asked for, and consolidating these builders is what makes one fix
|
|
140
|
+
* enough.
|
|
141
|
+
*
|
|
142
|
+
* Neither version is reachable from the funnel — Arachne reports
|
|
143
|
+
* site.primaryColor as hex.
|
|
144
|
+
*/
|
|
145
|
+
it("darkens rgba proportionally rather than crushing it", () => {
|
|
146
|
+
// 80% of each channel, which is what "20% darker" should mean.
|
|
147
|
+
expect((0, color_1.darkenColor)("rgba(20, 52, 204, 0.8)", 20)).toEqual("rgba(16, 42, 163, 1)");
|
|
148
|
+
expect((0, color_1.darkenColor)("rgba(255, 0, 0, 0.5)", 20)).toEqual("rgba(204, 0, 0, 0.7)");
|
|
149
|
+
});
|
|
150
|
+
it("leaves the hex and rgb paths exactly as they were", () => {
|
|
151
|
+
// Those branches were correct and are untouched, so the parity tests
|
|
152
|
+
// over hex colours still hold.
|
|
153
|
+
expect((0, color_1.darkenColor)("#1434cc", 20)).toEqual("#0020b8");
|
|
154
|
+
expect((0, color_1.darkenColor)("rgb(20, 52, 204)", 20)).toEqual("#0020b8");
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
//# sourceMappingURL=color.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"color.test.js","sourceRoot":"","sources":["../../src/__tests__/color.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const __clientTheme_1 = require("../__clientTheme");
|
|
4
|
+
const buildChatWidgetChannel_1 = require("../buildChatWidgetChannel");
|
|
5
|
+
/**
|
|
6
|
+
* The port has to be faithful, or migrating stentor-client to it restyles every
|
|
7
|
+
* widget created afterwards. This compares the two directly rather than
|
|
8
|
+
* trusting that it looks right.
|
|
9
|
+
*
|
|
10
|
+
* `__clientTheme.ts` is stentor-client's function, extracted verbatim with its
|
|
11
|
+
* colour helpers inlined so it can run here. It goes away once the client is
|
|
12
|
+
* migrated and there is only one of these left.
|
|
13
|
+
*/
|
|
14
|
+
describe("parity with stentor-client's buildDefaultChatTheme", () => {
|
|
15
|
+
// Hex is what a crawl actually yields — Arachne reports site.primaryColor
|
|
16
|
+
// as hex — so these are the cases that matter, and they are byte-identical.
|
|
17
|
+
const HEX = ["#f47c4c", "#c1bdb2", "#1434cc", "#1AA7DC", "#000000", "#ffffff"];
|
|
18
|
+
HEX.forEach((primaryColor) => {
|
|
19
|
+
it(`produces the same theme for ${primaryColor}`, () => {
|
|
20
|
+
expect((0, buildChatWidgetChannel_1.buildChatTheme)(primaryColor)).toEqual((0, __clientTheme_1.buildDefaultChatTheme)(primaryColor));
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
it("differs from the client only in notation for rgb input", () => {
|
|
24
|
+
// The one intentional difference. Given rgb, the client's contrast
|
|
25
|
+
// helper answers "rgba(255, 255, 255, 1)" while readableTextOn
|
|
26
|
+
// normalises to "#FFFFFF". Same colour, one shape instead of two — and
|
|
27
|
+
// not reachable from a crawl, which reports hex.
|
|
28
|
+
const mine = JSON.stringify((0, buildChatWidgetChannel_1.buildChatTheme)("rgb(20, 52, 204)"));
|
|
29
|
+
const theirs = JSON.stringify((0, __clientTheme_1.buildDefaultChatTheme)("rgb(20, 52, 204)"));
|
|
30
|
+
expect(mine.replace(/#FFFFFF/g, "rgba(255, 255, 255, 1)")).toEqual(theirs);
|
|
31
|
+
});
|
|
32
|
+
it("produces the same theme when a secondary colour is supplied", () => {
|
|
33
|
+
expect((0, buildChatWidgetChannel_1.buildChatTheme)("#f47c4c", "#ffffff")).toEqual((0, __clientTheme_1.buildDefaultChatTheme)("#f47c4c", "#ffffff"));
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
//# sourceMappingURL=themeParity.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"themeParity.test.js","sourceRoot":"","sources":["../../src/__tests__/themeParity.test.ts"],"names":[],"mappings":";;AAAA,oDAAyD;AACzD,sEAA2D;AAE3D;;;;;;;;GAQG;AACH,QAAQ,CAAC,oDAAoD,EAAE,GAAG,EAAE;IAEhE,0EAA0E;IAC1E,4EAA4E;IAC5E,MAAM,GAAG,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;IAE/E,GAAG,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE;QACzB,EAAE,CAAC,+BAA+B,YAAY,EAAE,EAAE,GAAG,EAAE;YACnD,MAAM,CAAC,IAAA,uCAAc,EAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,IAAA,qCAAqB,EAAC,YAAY,CAAC,CAAC,CAAC;QACtF,CAAC,CAAC,CAAC;IACP,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wDAAwD,EAAE,GAAG,EAAE;QAC9D,mEAAmE;QACnE,+DAA+D;QAC/D,uEAAuE;QACvE,iDAAiD;QACjD,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,uCAAc,EAAC,kBAAkB,CAAC,CAAC,CAAC;QAChE,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,IAAA,qCAAqB,EAAC,kBAAkB,CAAC,CAAC,CAAC;QAEzE,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,wBAAwB,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACnE,MAAM,CAAC,IAAA,uCAAc,EAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,IAAA,qCAAqB,EAAC,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;IACtG,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
|