1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

Add color indicator component (#10209)

Co-authored-by: Mark Stacey <markjstacey@gmail.com>
This commit is contained in:
Brad Decker 2021-01-22 15:45:37 -06:00 committed by GitHub
parent 7f1f68399a
commit a036b0ebcd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 227 additions and 11 deletions

View File

@ -203,7 +203,7 @@
}
&__check-mark-icon {
background-image: url("images/check-white.svg");
background-image: url("/images/check-white.svg");
height: 18px;
width: 18px;
background-repeat: no-repeat;

View File

@ -0,0 +1,50 @@
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.SIZES = {
LARGE: 'large',
MEDIUM: 'medium',
SMALL: 'small,',
}
ColorIndicator.TYPES = {
FILLED: 'filled',
PARTIAL: 'partial-filled',
OUTLINE: 'outline',
}
ColorIndicator.propTypes = {
color: PropTypes.oneOf(Object.values(COLORS)),
borderColor: PropTypes.oneOf(Object.values(COLORS)),
size: PropTypes.oneOf(Object.values(ColorIndicator.SIZES)),
iconClassName: PropTypes.string,
type: PropTypes.oneOf(Object.values(ColorIndicator.TYPES)),
}

View File

@ -0,0 +1,61 @@
@use "utilities";
@use "design-system";
$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 design-system.$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 design-system.$color-map {
&--border-color-#{$variant} {
border-color: $color;
}
}
}

View File

@ -0,0 +1,27 @@
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', ColorIndicator.SIZES, ColorIndicator.SIZES.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', ColorIndicator.SIZES, ColorIndicator.SIZES.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 })}
/>
)

View File

@ -0,0 +1 @@
export { default } from './color-indicator'

View File

@ -9,6 +9,7 @@
@import 'check-box/index';
@import 'chip/chip';
@import 'circle-icon/index';
@import 'color-indicator/color-indicator';
@import 'currency-display/index';
@import 'currency-input/index';
@import 'dialog/dialog';

View File

@ -1,4 +1,4 @@
$fa-font-path: 'fonts/fontawesome';
$fa-font-path: '/fonts/fontawesome';
@import '../../../../node_modules/@fortawesome/fontawesome-free/scss/fontawesome';
@import '../../../../node_modules/@fortawesome/fontawesome-free/scss/solid';
@ -8,63 +8,63 @@ $fa-font-path: 'fonts/fontawesome';
font-family: 'Roboto';
font-style: normal;
font-weight: 100;
src: local('Roboto Thin'), local('Roboto-Thin'), url('fonts/Roboto/Roboto-Thin.ttf') format('truetype');
src: local('Roboto Thin'), local('Roboto-Thin'), url('/fonts/Roboto/Roboto-Thin.ttf') format('truetype');
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 300;
src: local('Roboto Light'), local('Roboto-Light'), url('fonts/Roboto/Roboto-Light.ttf') format('truetype');
src: local('Roboto Light'), local('Roboto-Light'), url('/fonts/Roboto/Roboto-Light.ttf') format('truetype');
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: local('Roboto'), local('Roboto-Regular'), url('fonts/Roboto/Roboto-Regular.ttf') format('truetype');
src: local('Roboto'), local('Roboto-Regular'), url('/fonts/Roboto/Roboto-Regular.ttf') format('truetype');
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 500;
src: local('Roboto Medium'), local('Roboto-Medium'), url('fonts/Roboto/Roboto-Medium.ttf') format('truetype');
src: local('Roboto Medium'), local('Roboto-Medium'), url('/fonts/Roboto/Roboto-Medium.ttf') format('truetype');
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 700;
src: local('Roboto Bold'), local('Roboto-Bold'), url('fonts/Roboto/Roboto-Bold.ttf') format('truetype');
src: local('Roboto Bold'), local('Roboto-Bold'), url('/fonts/Roboto/Roboto-Bold.ttf') format('truetype');
}
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 900;
src: local('Roboto Black'), local('Roboto-Black'), url('fonts/Roboto/Roboto-Black.ttf') format('truetype');
src: local('Roboto Black'), local('Roboto-Black'), url('/fonts/Roboto/Roboto-Black.ttf') format('truetype');
}
@font-face {
font-family: 'Euclid';
font-style: normal;
font-weight: 400;
src: url('fonts/Euclid/EuclidCircularB-Regular-WebXL.ttf') format('truetype');
src: url('/fonts/Euclid/EuclidCircularB-Regular-WebXL.ttf') format('truetype');
}
@font-face {
font-family: 'Euclid';
font-style: italic;
font-weight: 400;
src: url('fonts/Euclid/EuclidCircularB-RegularItalic-WebXL.ttf') format('truetype');
src: url('/fonts/Euclid/EuclidCircularB-RegularItalic-WebXL.ttf') format('truetype');
}
@font-face {
font-family: 'Euclid';
font-style: normal;
font-weight: 700;
src: url('fonts/Euclid/EuclidCircularB-Bold-WebXL.ttf') format('truetype');
src: url('/fonts/Euclid/EuclidCircularB-Bold-WebXL.ttf') format('truetype');
}
$font-family: Euclid, Roboto, Helvetica, Arial, sans-serif;

View File

@ -0,0 +1,75 @@
@use "sass:math";
@use "sass:map";
/**
* Calculate the luminance for a color.
* See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests
*
* Note:
* @Gudahtt and @brad-decker have identified a potential performance concern
* that **might** impact build times if this function becomes widely used. It
* has not been validated, and is predicated on user-land math.pow functions
* prior to dart-sass 1.25.0. However, if the build times of sass raise
* exponentially a lookup table of all possible values for the math.pow call
* can be used to bypass the issue. This will require some logic updates as
* well. For reference, the blog post where the performance concern was
* originally made is here https://bit.ly/3c3qXzq (css-tricks)
*/
@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;
}
}

View File

@ -0,0 +1 @@
@forward 'colors';