1import React from 'react';
 2import { withStyles } from '@material-ui/core/styles';
 3import {
 4  getContrastRatio,
 5  darken,
 6} from '@material-ui/core/styles/colorManipulator';
 7import * as allColors from '@material-ui/core/colors';
 8import { common } from '@material-ui/core/colors';
 9
10// JS's modulo returns negative numbers sometimes.
11// This ensures the result is positive.
12const mod = (n, m) => ((n % m) + m) % m;
13
14// Minimum contrast between the background and the text color
15const contrastThreshold = 2.5;
16
17// Filter out the "common" color
18const labelColors = Object.entries(allColors)
19  .filter(([key, value]) => value !== common)
20  .map(([key, value]) => value);
21
22// Generate a hash (number) from a string
23const hash = string =>
24  string.split('').reduce((a, b) => ((a << 5) - a + b.charCodeAt(0)) | 0, 0);
25
26// Get the background color from the label
27const getColor = label =>
28  labelColors[mod(hash(label), labelColors.length)][500];
29
30// Guess the text color based on the background color
31const getTextColor = background =>
32  getContrastRatio(background, common.white) >= contrastThreshold
33    ? common.white // White on dark backgrounds
34    : common.black; // And black on light ones
35
36const _genStyle = background => ({
37  backgroundColor: background,
38  color: getTextColor(background),
39  borderBottomColor: darken(background, 0.2),
40});
41
42// Generate a style object (text, background and border colors) from the label
43const genStyle = label => _genStyle(getColor(label));
44
45const styles = theme => ({
46  label: {
47    ...theme.typography.body2,
48    padding: '0 6px',
49    fontSize: '0.9em',
50    margin: '0 1px',
51    borderRadius: '3px',
52    display: 'inline-block',
53    borderBottom: 'solid 1.5px',
54    verticalAlign: 'bottom',
55  },
56});
57
58const Label = ({ label, classes }) => (
59  <span className={classes.label} style={genStyle(label)}>
60    {label}
61  </span>
62);
63
64export default withStyles(styles)(Label);