Skip to content

Commit

Permalink
add ColorIndicator component
Browse files Browse the repository at this point in the history
  • Loading branch information
brad-decker committed Jan 19, 2021
1 parent 8fd5b63 commit a90b44c
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 1 deletion.
1 change: 0 additions & 1 deletion .storybook/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ module.exports = {
url: false,
},
},
'resolve-url-loader',
{
loader: 'sass-loader',
options: {
Expand Down
44 changes: 44 additions & 0 deletions ui/app/components/ui/color-indicator/color-indicator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react'
import classnames from 'classnames'
import PropTypes from 'prop-types'
import { COLORS } from '../../../helpers/constants/design-system'

export default function ColorIndicator({
size = 'small',
type = 'outlined',
color = COLORS.UI4,
borderColor,
iconClassName,
}) {
const colorIndicatorClassName = classnames('color-indicator', {
'color-indicator--filled': type === 'filled' || Boolean(iconClassName),
'color-indicator--partial-filled': type === 'partial-filled',
[`color-indicator--border-color-${borderColor}`]: Boolean(borderColor),
[`color-indicator--color-${color}`]: true,
[`color-indicator--size-${size}`]: true,
})

return (
<div className={colorIndicatorClassName}>
{iconClassName ? (
<i className={classnames('color-indicator__icon', iconClassName)} />
) : (
<span className="color-indicator__inner-circle" />
)}
</div>
)
}

ColorIndicator.propTypes = {
color: PropTypes.oneOf(Object.values(COLORS)),
borderColor: PropTypes.oneOf(Object.values(COLORS)),
size: PropTypes.oneOf(['small', 'medium', 'large']),
iconClassName: PropTypes.string,
type: PropTypes.oneOf(['filled', 'partial-filled', 'outline']),
}

ColorIndicator.TYPES = {
FILLED: 'filled',
PARTIAL: 'partial-filled',
OUTLINE: 'outline',
}
61 changes: 61 additions & 0 deletions ui/app/components/ui/color-indicator/color-indicator.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
@use "../../../css/utilities";
@use "../../../css/design-system/colors";

$sizes: (
'large': 6,
'medium': 5,
'small': 4,
);

.color-indicator {
$self: &;

border: 1px solid transparent;
display: flex;
align-items: center;
justify-content: center;

&__inner-circle {
background-color: transparent;
}

@each $variant, $size in $sizes {
&--size-#{$variant} {
height: #{2 * $size}px;
width: #{2 * $size}px;
border-radius: #{$size}px;

#{$self}__inner-circle {
border-radius: #{$size}px;
height: #{$size}px;
width: #{$size}px;
}

#{$self}__icon {
font-size: #{1.25 * $size}px;
}
}
}

@each $variant, $color in colors.$color-map {
&--color-#{$variant} {
border-color: $color;
&#{$self}--partial-filled #{$self}__inner-circle {
background-color: $color;
}
&#{$self}--filled {
background-color: $color;
}
& #{$self}__icon {
color: #{utilities.choose-contrast-color($color)};
}
}
}

// separate iterator to ensure borderColor takes precedence
@each $variant, $color in colors.$color-map {
&--border-color-#{$variant} {
border-color: $color;
}
}
}
35 changes: 35 additions & 0 deletions ui/app/components/ui/color-indicator/color-indicator.stories.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React from 'react'
import { select } from '@storybook/addon-knobs'
import { COLORS } from '../../../helpers/constants/design-system'
import ColorIndicator from './color-indicator'

export default {
title: 'ColorIndicator',
}

export const colorIndicator = () => (
<ColorIndicator
size={select(
'size',
{ large: 'large', medium: 'medium', small: 'small' },
'large',
)}
type={select('type', ColorIndicator.TYPES, ColorIndicator.TYPES.FILLED)}
color={select('color', COLORS, COLORS.PRIMARY1)}
borderColor={select('borderColor', { NONE: undefined, ...COLORS })}
/>
)

export const withIcon = () => (
<ColorIndicator
size={select(
'size',
{ large: 'large', medium: 'medium', small: 'small' },
'large',
)}
type={select('type', ColorIndicator.TYPES, ColorIndicator.TYPES.FILLED)}
color={select('color', COLORS, COLORS.PRIMARY1)}
iconClassName="fa fa-question"
borderColor={select('borderColor', { NONE: undefined, ...COLORS })}
/>
)
1 change: 1 addition & 0 deletions ui/app/components/ui/color-indicator/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './color-indicator'
1 change: 1 addition & 0 deletions ui/app/components/ui/ui-components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
@import 'card/index';
@import 'check-box/index';
@import 'circle-icon/index';
@import 'color-indicator/color-indicator';
@import 'currency-display/index';
@import 'currency-input/index';
@import 'dialog/dialog';
Expand Down
65 changes: 65 additions & 0 deletions ui/app/css/utilities/_colors.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
@use "sass:math";
@use "sass:map";

/**
* Calculate the luminance for a color.
* See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
*/
@function luminance($color) {
$channels: (
'red': red($color),
'green': green($color),
'blue': blue($color),
);

$values: (
'red': map.get($channels, 'red') / 255,
'blue': map.get($channels, 'red') / 255,
'green': map.get($channels, 'red') / 255,
);

@each $name, $value in $values {
@if $value < 0.03928 {
$value: $value / 12.92;
}

@else {
$value: ($value + 0.055) / 1.055;
$value: math.pow($value, 2.4);
}

$values: map.merge($values, ($name: $value));
}

@return (0.2126 * map.get($values, 'red'))
+ (0.7152 * map.get($values, 'green'))
+ (0.0722 * map.get($values, 'blue'));
}

/**
* Calculate the contrast ratio between two colors.
* See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
*/
@function contrast($back, $front) {
$backLum: luminance($back) + 0.05;
$foreLum: luminance($front) + 0.05;

@return max($backLum, $foreLum) / min($backLum, $foreLum);
}

/**
* Determine whether to use dark or light text on top of given color.
* Returns black for dark text and white for light text.
*/
@function choose-contrast-color($color) {
$lightContrast: contrast($color, white);
$darkContrast: contrast($color, black);

@if ($lightContrast > $darkContrast) {
@return white;
}

@else {
@return black;
}
}
1 change: 1 addition & 0 deletions ui/app/css/utilities/index.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@forward 'colors';

0 comments on commit a90b44c

Please sign in to comment.