Skip to content

Commit 660fdd0

Browse files
committed
Merge branch 'master' into features/TO-master/generic-bug-fix-3
2 parents 90d43a6 + 7edd901 commit 660fdd0

File tree

6 files changed

+133
-8
lines changed

6 files changed

+133
-8
lines changed

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@
66
### **Copyrigth**:
77
*Tiledesk SRL*
88

9-
# changes in the branch
9+
# 5.1.13
1010
- **bug-fixed**: set default widget size
1111
- **changed**: Updated the translations of the tooltips in the footer-component
1212
- **changed**: Refactored the network-offline component and made it generic for displaying errors (now error-alert.component)
13+
- **bug-fixed**: set the color of the buttons with visibility control to the font color (setButtonColors function)
1314

1415
# 5.1.12
1516
- **bug-fixed**: check showEmojiFooterButton to enable/disable emojii
1617
- **bug-fixed**: markdown is fired as an emojii and blocked by isEmojii check fn
1718

19+
1820
# 5.1.7-rc5
1921
- **bug-fixed**: bug fixed BUTTON STYLES
2022

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@chat21/chat21-web-widget",
33
"author": "Tiledesk SRL",
4-
"version": "5.1.12",
4+
"version": "5.1.13",
55
"license": "MIT",
66
"homepage": "https://www.tiledesk.com",
77
"repository": {

src/app/component/message/buttons/action-button/action-button.component.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Component, ElementRef, EventEmitter, Input, OnInit, Output, SimpleChanges } from '@angular/core';
2+
import { getColorBck } from 'src/chat21-core/utils/utils-user';
23

34
@Component({
45
selector: 'chat-action-button-attachment',
@@ -26,9 +27,10 @@ export class ActionButtonComponent implements OnInit {
2627
//decomment if element should have same color of themeColor and fregroundColor
2728
if(this.fontSize) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--buttonFontSize', this.fontSize);
2829
if(this.backgroundColor) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--buttonBackgroundColor', this.backgroundColor);
29-
if(this.textColor) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--textColor', this.textColor);
30+
if(this.textColor) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--buttonTextColor', this.textColor);
3031
if(this.hoverBackgroundColor) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--hoverBackgroundColor', this.hoverBackgroundColor);
3132
if(this.hoverTextColor) this.elementRef.nativeElement.querySelector('.action').style.setProperty('--hoverTextColor', this.hoverTextColor);
33+
3234
}
3335

3436
onMouseOver(event){

src/app/providers/global-settings.service.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { TemplateBindingParseResult } from '@angular/compiler';
1010
import { AppStorageService } from '../../chat21-core/providers/abstract/app-storage.service';
1111
import { LoggerService } from '../../chat21-core/providers/abstract/logger.service';
1212
import { LoggerInstance } from '../../chat21-core/providers/logger/loggerInstance';
13-
import { invertColor, isAllowedUrlInText, isJsonArray } from '../../chat21-core/utils/utils';
13+
import { ensureAccessibleTextColor, invertColor, isAllowedUrlInText, isJsonArray, normalizeColorToHex } from '../../chat21-core/utils/utils';
1414
import { AppConfigService } from './app-config.service';
1515

1616

@@ -322,22 +322,34 @@ export class GlobalSettingsService {
322322
if (response !== null) {
323323
this.setVariablesFromService(this.globals, response);
324324
}
325+
/** set button colors */
326+
this.setButtonColors();
327+
325328
this.setVariableFromStorage(this.globals);
326329
this.setVariablesFromSettings(this.globals);
327330
this.setVariablesFromAttributeHtml(this.globals, this.el);
328331
this.setVariablesFromUrlParameters(this.globals);
332+
329333
this.setDepartmentFromExternal();
330334
/** set color with gradient from theme's colors */
331335
this.globals.setColorWithGradient();
332336
/** set css iframe from parameters */
333337
this.setCssIframe();
334338
/** set main style */
335339
this.setStyle();
336-
337-
this.logger.debug('[GLOBAL-SET] ***** END SET PARAMETERS *****');
338340
this.obsSettingsService.next(true);
339341
}
340342

343+
private setButtonColors() {
344+
this.logger.debug('[GLOBAL-SET] ***** END SET PARAMETERS *****', this.globals);
345+
const bubbleSentBackground = this.globals?.bubbleSentBackground;
346+
const buttonBackgroundColor = this.globals?.buttonBackgroundColor;
347+
348+
this.globals.buttonTextColor = ensureAccessibleTextColor(buttonBackgroundColor, bubbleSentBackground);
349+
this.globals.buttonHoverTextColor = ensureAccessibleTextColor(bubbleSentBackground, buttonBackgroundColor);
350+
351+
}
352+
341353
/**
342354
*
343355
*/

src/chat21-core/utils/utils.ts

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,115 @@ export function convertColorToRGBA(color, opacity) {
389389
return result;
390390
}
391391

392+
export function normalizeColorToHex(input?: string): string | null {
393+
if (!input) {
394+
return null;
395+
}
396+
let color = input.trim();
397+
if (color.toLowerCase().includes('gradient')) {
398+
const match = color.match(/(#[0-9a-fA-F]{3,8}|rgba?\([^)]*\))/);
399+
if (!match) {
400+
return null;
401+
}
402+
color = match[0];
403+
}
404+
if (color.startsWith('#')) {
405+
const hex = color.slice(1);
406+
if (hex.length === 3) {
407+
return (
408+
'#' +
409+
hex
410+
.split('')
411+
.map((char) => char + char)
412+
.join('')
413+
.toLowerCase()
414+
);
415+
}
416+
if (hex.length === 4) {
417+
return (
418+
'#' +
419+
hex
420+
.slice(0, 3)
421+
.split('')
422+
.map((char) => char + char)
423+
.join('')
424+
.toLowerCase()
425+
);
426+
}
427+
if (hex.length === 6 || hex.length === 8) {
428+
return '#' + hex.slice(0, 6).toLowerCase();
429+
}
430+
return null;
431+
}
432+
const rgbaMatch = color.match(/rgba?\s*\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)(?:\s*,\s*([\d.]+))?\s*\)/i);
433+
if (rgbaMatch) {
434+
const [, r, g, b] = rgbaMatch;
435+
const toHex = (value: number) => {
436+
const clamped = Math.max(0, Math.min(255, Math.round(value)));
437+
return clamped.toString(16).padStart(2, '0');
438+
};
439+
return `#${toHex(parseFloat(r))}${toHex(parseFloat(g))}${toHex(parseFloat(b))}`;
440+
}
441+
return null;
442+
}
443+
444+
export function ensureAccessibleTextColor(backgroundColor?: string, fontColor?: string, minContrast = 4.5): string | null {
445+
const bgHex = normalizeColorToHex(backgroundColor);
446+
if (!bgHex) {
447+
return normalizeColorToHex(fontColor);
448+
}
449+
450+
const fontHex = normalizeColorToHex(fontColor);
451+
if (fontHex && getContrastRatio(bgHex, fontHex) >= minContrast) {
452+
return fontHex;
453+
}
454+
455+
const blackContrast = getContrastRatio(bgHex, '#000000');
456+
const whiteContrast = getContrastRatio(bgHex, '#ffffff');
457+
return blackContrast >= whiteContrast ? '#000000' : '#ffffff';
458+
}
459+
460+
function getContrastRatio(backgroundHex: string, foregroundHex: string): number {
461+
const bg = hexToRgb(backgroundHex);
462+
const fg = hexToRgb(foregroundHex);
463+
if (!bg || !fg) {
464+
return 1;
465+
}
466+
const l1 = relativeLuminance(bg);
467+
const l2 = relativeLuminance(fg);
468+
const lighter = Math.max(l1, l2);
469+
const darker = Math.min(l1, l2);
470+
return (lighter + 0.05) / (darker + 0.05);
471+
}
472+
473+
function relativeLuminance({ r, g, b }: { r: number; g: number; b: number }): number {
474+
const srgb = [r, g, b].map((value) => {
475+
const channel = value / 255;
476+
return channel <= 0.03928 ? channel / 12.92 : Math.pow((channel + 0.055) / 1.055, 2.4);
477+
});
478+
return 0.2126 * srgb[0] + 0.7152 * srgb[1] + 0.0722 * srgb[2];
479+
}
480+
481+
function hexToRgb(hex: string): { r: number; g: number; b: number } | null {
482+
let value = hex.replace('#', '');
483+
if (value.length === 3) {
484+
value = value
485+
.split('')
486+
.map((char) => char + char)
487+
.join('');
488+
}
489+
if (value.length !== 6) {
490+
return null;
491+
}
492+
const r = parseInt(value.slice(0, 2), 16);
493+
const g = parseInt(value.slice(2, 4), 16);
494+
const b = parseInt(value.slice(4, 6), 16);
495+
if ([r, g, b].some((channel) => Number.isNaN(channel))) {
496+
return null;
497+
}
498+
return { r, g, b };
499+
}
500+
392501

393502
// export function setLanguage(windowContext, translatorService) {
394503
// if (translatorService.getBrowserLanguage(windowContext)) {

0 commit comments

Comments
 (0)