mattermost-redux
Version:
Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client
154 lines (153 loc) • 6.13 kB
JavaScript
;
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
Object.defineProperty(exports, "__esModule", { value: true });
exports.blendColors = void 0;
exports.makeStyleFromTheme = makeStyleFromTheme;
exports.getComponents = getComponents;
exports.changeOpacity = changeOpacity;
exports.setThemeDefaults = setThemeDefaults;
exports.getContrastingSimpleColor = getContrastingSimpleColor;
const constants_1 = require("mattermost-redux/constants");
function makeStyleFromTheme(getStyleFromTheme) {
let lastTheme;
let style;
return (theme) => {
if (!style || theme !== lastTheme) {
style = getStyleFromTheme(theme);
lastTheme = theme;
}
return style;
};
}
const rgbPattern = /^rgba?\((\d+),(\d+),(\d+)(?:,([\d.]+))?\)$/;
function getComponents(inColor) {
let color = inColor;
// RGB color
const match = rgbPattern.exec(color);
if (match) {
return {
red: parseInt(match[1], 10),
green: parseInt(match[2], 10),
blue: parseInt(match[3], 10),
alpha: match[4] ? parseFloat(match[4]) : 1,
};
}
// Hex color
if (color[0] === '#') {
color = color.slice(1);
}
if (color.length === 3) {
const tempColor = color;
color = '';
color += tempColor[0] + tempColor[0];
color += tempColor[1] + tempColor[1];
color += tempColor[2] + tempColor[2];
}
return {
red: parseInt(color.substring(0, 2), 16),
green: parseInt(color.substring(2, 4), 16),
blue: parseInt(color.substring(4, 6), 16),
alpha: 1,
};
}
function changeOpacity(oldColor, opacity) {
const { red, green, blue, alpha, } = getComponents(oldColor);
return `rgba(${red},${green},${blue},${alpha * opacity})`;
}
function blendComponent(background, foreground, opacity) {
return ((1 - opacity) * background) + (opacity * foreground);
}
const blendColors = (background, foreground, opacity, hex = false) => {
const backgroundComponents = getComponents(background);
const foregroundComponents = getComponents(foreground);
const red = Math.floor(blendComponent(backgroundComponents.red, foregroundComponents.red, opacity));
const green = Math.floor(blendComponent(backgroundComponents.green, foregroundComponents.green, opacity));
const blue = Math.floor(blendComponent(backgroundComponents.blue, foregroundComponents.blue, opacity));
const alpha = blendComponent(backgroundComponents.alpha, foregroundComponents.alpha, opacity);
if (hex) {
let r = red.toString(16);
let g = green.toString(16);
let b = blue.toString(16);
if (r.length === 1) {
r = '0' + r;
}
if (g.length === 1) {
g = '0' + g;
}
if (b.length === 1) {
b = '0' + b;
}
return `#${r + g + b}`;
}
return `rgba(${red},${green},${blue},${alpha})`;
};
exports.blendColors = blendColors;
// object mapping theme types to their respective keys for retrieving the source themes directly
// - supports mapping old themes to new themes
const themeTypeMap = {
Mattermost: 'denim',
Organization: 'sapphire',
'Mattermost Dark': 'indigo',
'Windows Dark': 'onyx',
Denim: 'denim',
Sapphire: 'sapphire',
Quartz: 'quartz',
Indigo: 'indigo',
Onyx: 'onyx',
};
// setThemeDefaults will set defaults on the theme for any unset properties.
function setThemeDefaults(theme) {
const defaultTheme = constants_1.Preferences.THEMES.denim;
const processedTheme = { ...theme };
// If this is a system theme, return the source theme object matching the theme preference type
if (theme.type && theme.type !== 'custom' && Object.keys(themeTypeMap).includes(theme.type)) {
return constants_1.Preferences.THEMES[themeTypeMap[theme.type]];
}
for (const key of Object.keys(defaultTheme)) {
if (theme[key]) {
// Fix a case where upper case theme colours are rendered as black
processedTheme[key] = theme[key]?.toLowerCase();
}
}
for (const property in defaultTheme) {
if (property === 'type' || (property === 'sidebarTeamBarBg' && theme.sidebarHeaderBg)) {
continue;
}
if (theme[property] == null) {
processedTheme[property] = defaultTheme[property];
}
// Backwards compatability with old name
if (!theme.mentionBg && theme.mentionBj) {
processedTheme.mentionBg = theme.mentionBj;
}
}
if (!theme.sidebarTeamBarBg && theme.sidebarHeaderBg) {
processedTheme.sidebarTeamBarBg = (0, exports.blendColors)(theme.sidebarHeaderBg, '#000000', 0.2, true);
}
return processedTheme;
}
// getContrastingSimpleColor returns a contrasting color - either black or white, depending on the luminance
// of the supplied color. Both input and output colors are in hexadecimal color code.
function getContrastingSimpleColor(colorHexCode) {
const color = colorHexCode.startsWith('#') ? colorHexCode.slice(1) : colorHexCode;
if (color.length !== 6) {
return '';
}
// split red, green and blue components
const red = parseInt(color.substring(0, 2), 16);
const green = parseInt(color.substring(2, 4), 16);
const blue = parseInt(color.substring(4, 6), 16);
// calculate relative luminance of each color channel - https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
const srgb = [red / 255, green / 255, blue / 255];
const [redLuminance, greenLuminance, blueLuminance] = srgb.map((i) => {
if (i <= 0.04045) {
return i / 12.92;
}
return Math.pow((i + 0.055) / 1.055, 2.4);
});
// calculate luminance of the whole color by adding percieved luminance of each channel
const colorLuminance = (0.2126 * redLuminance) + (0.7152 * greenLuminance) + (0.0722 * blueLuminance);
// return black or white based on color's luminance
return colorLuminance > 0.179 ? '#000000' : '#FFFFFF';
}