UNPKG

mattermost-redux

Version:

Common code (API client, Redux stores, logic, utility functions) for building a Mattermost client

154 lines (153 loc) 6.13 kB
"use strict"; // 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'; }