aboutsummaryrefslogtreecommitdiffstats
path: root/packages/instant/src/components/ui
diff options
context:
space:
mode:
authorRemco Bloemen <remco@wicked.ventures>2018-11-09 01:32:40 +0800
committerRemco Bloemen <remco@wicked.ventures>2018-11-09 01:32:40 +0800
commitd71362af993d3797dbdbfcac245ad57f0086bce3 (patch)
tree888826fe23c2d06d6c9191fb3a238e14f9fe4aac /packages/instant/src/components/ui
parenta5665a68756c905637c551fc48c9b7011a55c237 (diff)
parentf6abc007ffb249e4bbf85b8a7a77309d43e0a147 (diff)
downloaddexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.gz
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.bz2
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.lz
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.xz
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.tar.zst
dexon-sol-tools-d71362af993d3797dbdbfcac245ad57f0086bce3.zip
Merge remote-tracking branch 'origin/development' into feature/utils/prettybignum
Diffstat (limited to 'packages/instant/src/components/ui')
-rw-r--r--packages/instant/src/components/ui/button.tsx61
-rw-r--r--packages/instant/src/components/ui/circle.tsx22
-rw-r--r--packages/instant/src/components/ui/container.tsx87
-rw-r--r--packages/instant/src/components/ui/flex.tsx39
-rw-r--r--packages/instant/src/components/ui/icon.tsx120
-rw-r--r--packages/instant/src/components/ui/input.tsx39
-rw-r--r--packages/instant/src/components/ui/overlay.tsx40
-rw-r--r--packages/instant/src/components/ui/spinner.tsx30
-rw-r--r--packages/instant/src/components/ui/text.tsx74
9 files changed, 512 insertions, 0 deletions
diff --git a/packages/instant/src/components/ui/button.tsx b/packages/instant/src/components/ui/button.tsx
new file mode 100644
index 000000000..5274d835b
--- /dev/null
+++ b/packages/instant/src/components/ui/button.tsx
@@ -0,0 +1,61 @@
+import { darken, saturate } from 'polished';
+import * as React from 'react';
+
+import { ColorOption, styled } from '../../style/theme';
+
+export interface ButtonProps {
+ backgroundColor?: ColorOption;
+ borderColor?: ColorOption;
+ width?: string;
+ padding?: string;
+ type?: string;
+ isDisabled?: boolean;
+ onClick?: (event: React.MouseEvent<HTMLElement>) => void;
+ className?: string;
+}
+
+const PlainButton: React.StatelessComponent<ButtonProps> = ({ children, isDisabled, onClick, type, className }) => (
+ <button type={type} className={className} onClick={isDisabled ? undefined : onClick} disabled={isDisabled}>
+ {children}
+ </button>
+);
+
+const darkenOnHoverAmount = 0.1;
+const darkenOnActiveAmount = 0.2;
+const saturateOnFocusAmount = 0.2;
+export const Button = styled(PlainButton)`
+ cursor: ${props => (props.isDisabled ? 'default' : 'pointer')};
+ transition: background-color, opacity 0.5s ease;
+ padding: ${props => props.padding};
+ border-radius: 3px;
+ outline: none;
+ width: ${props => props.width};
+ background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
+ border: ${props => (props.borderColor ? `1px solid ${props.theme[props.borderColor]}` : 'none')};
+ &:hover {
+ background-color: ${props =>
+ !props.isDisabled
+ ? darken(darkenOnHoverAmount, props.theme[props.backgroundColor || 'white'])
+ : ''} !important;
+ }
+ &:active {
+ background-color: ${props =>
+ !props.isDisabled ? darken(darkenOnActiveAmount, props.theme[props.backgroundColor || 'white']) : ''};
+ }
+ &:disabled {
+ opacity: 0.5;
+ }
+ &:focus {
+ background-color: ${props => saturate(saturateOnFocusAmount, props.theme[props.backgroundColor || 'white'])};
+ }
+`;
+
+Button.defaultProps = {
+ backgroundColor: ColorOption.primaryColor,
+ borderColor: ColorOption.primaryColor,
+ width: 'auto',
+ isDisabled: false,
+ padding: '1em 2.2em',
+};
+
+Button.displayName = 'Button';
diff --git a/packages/instant/src/components/ui/circle.tsx b/packages/instant/src/components/ui/circle.tsx
new file mode 100644
index 000000000..eec2777d2
--- /dev/null
+++ b/packages/instant/src/components/ui/circle.tsx
@@ -0,0 +1,22 @@
+import { styled } from '../../style/theme';
+
+export interface CircleProps {
+ diameter: number;
+ fillColor?: string;
+}
+
+export const Circle =
+ styled.div <
+ CircleProps >
+ `
+ width: ${props => props.diameter}px;
+ height: ${props => props.diameter}px;
+ background-color: ${props => props.fillColor};
+ border-radius: 50%;
+`;
+
+Circle.displayName = 'Circle';
+
+Circle.defaultProps = {
+ fillColor: 'white',
+};
diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx
new file mode 100644
index 000000000..403751210
--- /dev/null
+++ b/packages/instant/src/components/ui/container.tsx
@@ -0,0 +1,87 @@
+import { darken } from 'polished';
+
+import { MediaChoice, stylesForMedia } from '../../style/media';
+import { ColorOption, styled } from '../../style/theme';
+import { cssRuleIfExists } from '../../style/util';
+
+export interface ContainerProps {
+ display?: MediaChoice;
+ position?: string;
+ top?: string;
+ right?: string;
+ bottom?: string;
+ left?: string;
+ width?: MediaChoice;
+ height?: MediaChoice;
+ maxWidth?: string;
+ margin?: string;
+ marginTop?: string;
+ marginRight?: string;
+ marginBottom?: string;
+ marginLeft?: string;
+ padding?: string;
+ borderRadius?: string;
+ border?: string;
+ borderColor?: ColorOption;
+ borderTop?: string;
+ borderBottom?: string;
+ className?: string;
+ backgroundColor?: ColorOption;
+ hasBoxShadow?: boolean;
+ zIndex?: number;
+ whiteSpace?: string;
+ opacity?: number;
+ cursor?: string;
+ overflow?: string;
+ darkenOnHover?: boolean;
+ flexGrow?: string | number;
+}
+
+export const Container =
+ styled.div <
+ ContainerProps >
+ `
+ box-sizing: border-box;
+ ${props => cssRuleIfExists(props, 'flex-grow')}
+ ${props => cssRuleIfExists(props, 'position')}
+ ${props => cssRuleIfExists(props, 'top')}
+ ${props => cssRuleIfExists(props, 'right')}
+ ${props => cssRuleIfExists(props, 'bottom')}
+ ${props => cssRuleIfExists(props, 'left')}
+ ${props => cssRuleIfExists(props, 'max-width')}
+ ${props => cssRuleIfExists(props, 'margin')}
+ ${props => cssRuleIfExists(props, 'margin-top')}
+ ${props => cssRuleIfExists(props, 'margin-right')}
+ ${props => cssRuleIfExists(props, 'margin-bottom')}
+ ${props => cssRuleIfExists(props, 'margin-left')}
+ ${props => cssRuleIfExists(props, 'padding')}
+ ${props => cssRuleIfExists(props, 'border-radius')}
+ ${props => cssRuleIfExists(props, 'border')}
+ ${props => cssRuleIfExists(props, 'border-top')}
+ ${props => cssRuleIfExists(props, 'border-bottom')}
+ ${props => cssRuleIfExists(props, 'z-index')}
+ ${props => cssRuleIfExists(props, 'white-space')}
+ ${props => cssRuleIfExists(props, 'opacity')}
+ ${props => cssRuleIfExists(props, 'cursor')}
+ ${props => cssRuleIfExists(props, 'overflow')}
+ ${props => (props.hasBoxShadow ? `box-shadow: 0px 2px 10px rgba(0, 0, 0, 0.1)` : '')};
+ ${props => props.display && stylesForMedia('display', props.display)}
+ ${props => stylesForMedia('width', props.width || 'auto')}
+ ${props => stylesForMedia('height', props.height || 'auto')}
+ background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
+ border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')};
+ &:hover {
+ ${props =>
+ props.darkenOnHover
+ ? `background-color: ${
+ props.backgroundColor ? darken(0.05, props.theme[props.backgroundColor]) : 'none'
+ }`
+ : ''};
+ }
+`;
+
+Container.defaultProps = {
+ display: 'block',
+};
+
+Container.displayName = 'Container';
diff --git a/packages/instant/src/components/ui/flex.tsx b/packages/instant/src/components/ui/flex.tsx
new file mode 100644
index 000000000..fd218b0cd
--- /dev/null
+++ b/packages/instant/src/components/ui/flex.tsx
@@ -0,0 +1,39 @@
+import { MediaChoice, stylesForMedia } from '../../style/media';
+import { ColorOption, styled } from '../../style/theme';
+import { cssRuleIfExists } from '../../style/util';
+
+export interface FlexProps {
+ direction?: 'row' | 'column';
+ flexWrap?: 'wrap' | 'nowrap';
+ justify?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
+ align?: 'flex-start' | 'center' | 'space-around' | 'space-between' | 'space-evenly' | 'flex-end';
+ width?: MediaChoice;
+ height?: MediaChoice;
+ backgroundColor?: ColorOption;
+ inline?: boolean;
+ flexGrow?: number | string;
+}
+
+export const Flex =
+ styled.div <
+ FlexProps >
+ `
+ display: ${props => (props.inline ? 'inline-flex' : 'flex')};
+ flex-direction: ${props => props.direction};
+ flex-wrap: ${props => props.flexWrap};
+ ${props => cssRuleIfExists(props, 'flexGrow')}
+ justify-content: ${props => props.justify};
+ align-items: ${props => props.align};
+ background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};
+ ${props => stylesForMedia('width', props.width || 'auto')}
+ ${props => stylesForMedia('height', props.height || 'auto')}
+`;
+
+Flex.defaultProps = {
+ direction: 'row',
+ flexWrap: 'nowrap',
+ justify: 'center',
+ align: 'center',
+};
+
+Flex.displayName = 'Flex';
diff --git a/packages/instant/src/components/ui/icon.tsx b/packages/instant/src/components/ui/icon.tsx
new file mode 100644
index 000000000..94ea26900
--- /dev/null
+++ b/packages/instant/src/components/ui/icon.tsx
@@ -0,0 +1,120 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+
+import { ColorOption, styled, Theme, withTheme } from '../../style/theme';
+
+type svgRule = 'evenodd' | 'nonzero' | 'inherit';
+interface IconInfo {
+ viewBox: string;
+ path: string;
+ fillRule?: svgRule;
+ clipRule?: svgRule;
+ stroke?: string;
+ strokeOpacity?: number;
+ strokeWidth?: number;
+ strokeLinecap?: 'butt' | 'round' | 'square' | 'inherit';
+ strokeLinejoin?: 'miter' | 'round' | 'bevel' | 'inherit';
+}
+interface IconInfoMapping {
+ closeX: IconInfo;
+ failed: IconInfo;
+ success: IconInfo;
+ chevron: IconInfo;
+ search: IconInfo;
+}
+const ICONS: IconInfoMapping = {
+ closeX: {
+ viewBox: '0 0 11 11',
+ fillRule: 'evenodd',
+ clipRule: 'evenodd',
+ path:
+ 'M10.45 10.449C10.7539 10.1453 10.7539 9.65282 10.45 9.34909L6.60068 5.49999L10.45 1.65093C10.7538 1.3472 10.7538 0.854765 10.45 0.551038C10.1462 0.24731 9.65378 0.24731 9.34995 0.551038L5.50058 4.40006L1.65024 0.549939C1.34641 0.246212 0.853973 0.246212 0.550262 0.549939C0.246429 0.853667 0.246429 1.34611 0.550262 1.64983L4.40073 5.49995L0.55014 9.35019C0.246307 9.65392 0.246307 10.1464 0.55014 10.4501C0.853851 10.7538 1.34628 10.7538 1.65012 10.4501L5.5007 6.59987L9.35007 10.449C9.6539 10.7527 10.1463 10.7527 10.45 10.449Z',
+ },
+ failed: {
+ viewBox: '0 0 34 34',
+ fillRule: 'evenodd',
+ clipRule: 'evenodd',
+ path:
+ 'M6.65771 26.4362C9.21777 29.2406 12.9033 31 17 31C24.7319 31 31 24.7319 31 17C31 14.4468 30.3164 12.0531 29.1226 9.99219L6.65771 26.4362ZM4.88281 24.0173C3.68555 21.9542 3 19.5571 3 17C3 9.26807 9.26807 3 17 3C21.1006 3 24.7891 4.76294 27.3496 7.57214L4.88281 24.0173ZM0 17C0 26.3888 7.61133 34 17 34C26.3887 34 34 26.3888 34 17C34 7.61121 26.3887 0 17 0C7.61133 0 0 7.61121 0 17Z',
+ },
+ success: {
+ viewBox: '0 0 34 34',
+ fillRule: 'evenodd',
+ clipRule: 'evenodd',
+ path:
+ 'M17 34C26.3887 34 34 26.3888 34 17C34 7.61121 26.3887 0 17 0C7.61133 0 0 7.61121 0 17C0 26.3888 7.61133 34 17 34ZM25.7539 13.0977C26.2969 12.4718 26.2295 11.5244 25.6035 10.9817C24.9775 10.439 24.0303 10.5063 23.4878 11.1323L15.731 20.0771L12.3936 16.7438C11.8071 16.1583 10.8574 16.1589 10.272 16.7451C9.68652 17.3313 9.6875 18.281 10.2734 18.8665L14.75 23.3373L15.8887 24.4746L16.9434 23.2587L25.7539 13.0977Z',
+ },
+ chevron: {
+ viewBox: '0 0 12 7',
+ path: 'M11 1L6 6L1 1',
+ stroke: 'white',
+ strokeOpacity: 0.5,
+ strokeWidth: 1.5,
+ strokeLinecap: 'round',
+ strokeLinejoin: 'round',
+ },
+ search: {
+ viewBox: '0 0 14 14',
+ fillRule: 'evenodd',
+ clipRule: 'evenodd',
+ path:
+ 'M8.39404 5.19727C8.39404 6.96289 6.96265 8.39453 5.19702 8.39453C3.4314 8.39453 2 6.96289 2 5.19727C2 3.43164 3.4314 2 5.19702 2C6.96265 2 8.39404 3.43164 8.39404 5.19727ZM8.09668 9.51074C7.26855 10.0684 6.27075 10.3945 5.19702 10.3945C2.3269 10.3945 0 8.06738 0 5.19727C0 2.32715 2.3269 0 5.19702 0C8.06738 0 10.394 2.32715 10.394 5.19727C10.394 6.27051 10.0686 7.26855 9.51074 8.09668L13.6997 12.2861L12.2854 13.7002L8.09668 9.51074Z',
+ },
+};
+
+export interface IconProps {
+ className?: string;
+ width: number;
+ height?: number;
+ color?: ColorOption;
+ icon: keyof IconInfoMapping;
+ onClick?: (event: React.MouseEvent<HTMLElement>) => void;
+ padding?: string;
+ theme: Theme;
+}
+const PlainIcon: React.StatelessComponent<IconProps> = props => {
+ const iconInfo = ICONS[props.icon];
+ const colorValue = _.isUndefined(props.color) ? undefined : props.theme[props.color];
+ return (
+ <div onClick={props.onClick} className={props.className}>
+ <svg
+ width={props.width}
+ height={props.height}
+ viewBox={iconInfo.viewBox}
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <path
+ d={iconInfo.path}
+ fill={colorValue}
+ fillRule={iconInfo.fillRule || 'nonzero'}
+ clipRule={iconInfo.clipRule || 'nonzero'}
+ stroke={iconInfo.stroke}
+ strokeOpacity={iconInfo.strokeOpacity}
+ strokeWidth={iconInfo.strokeWidth}
+ strokeLinecap={iconInfo.strokeLinecap}
+ strokeLinejoin={iconInfo.strokeLinejoin}
+ />
+ </svg>
+ </div>
+ );
+};
+
+export const Icon = withTheme(styled(PlainIcon)`
+ cursor: ${props => (!_.isUndefined(props.onClick) ? 'pointer' : 'default')};
+ transition: opacity 0.5s ease;
+ padding: ${props => props.padding};
+ opacity: ${props => (!_.isUndefined(props.onClick) ? 0.7 : 1)};
+ &:hover {
+ opacity: 1;
+ }
+ &:active {
+ opacity: 1;
+ }
+`);
+
+Icon.defaultProps = {
+ padding: '0em 0em',
+};
+
+Icon.displayName = 'Icon';
diff --git a/packages/instant/src/components/ui/input.tsx b/packages/instant/src/components/ui/input.tsx
new file mode 100644
index 000000000..a884ff7cb
--- /dev/null
+++ b/packages/instant/src/components/ui/input.tsx
@@ -0,0 +1,39 @@
+import * as React from 'react';
+
+import { ColorOption, styled } from '../../style/theme';
+
+export interface InputProps {
+ className?: string;
+ value?: string;
+ width?: string;
+ fontSize?: string;
+ fontColor?: ColorOption;
+ placeholder?: string;
+ onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
+}
+
+export const Input =
+ styled.input <
+ InputProps >
+ `
+ font-size: ${props => props.fontSize};
+ width: ${props => props.width};
+ padding: 0.1em 0em;
+ font-family: 'Inter UI';
+ color: ${props => props.theme[props.fontColor || 'white']};
+ background: transparent;
+ outline: none;
+ border: none;
+ &::placeholder {
+ color: ${props => props.theme[props.fontColor || 'white']};
+ opacity: 0.5;
+ }
+`;
+
+Input.defaultProps = {
+ width: 'auto',
+ fontColor: ColorOption.white,
+ fontSize: '12px',
+};
+
+Input.displayName = 'Input';
diff --git a/packages/instant/src/components/ui/overlay.tsx b/packages/instant/src/components/ui/overlay.tsx
new file mode 100644
index 000000000..7110ee70f
--- /dev/null
+++ b/packages/instant/src/components/ui/overlay.tsx
@@ -0,0 +1,40 @@
+import * as _ from 'lodash';
+import * as React from 'react';
+
+import { ColorOption, overlayBlack, styled } from '../../style/theme';
+
+import { Container } from './container';
+import { Flex } from './flex';
+import { Icon } from './icon';
+
+export interface OverlayProps {
+ className?: string;
+ onClose?: () => void;
+ zIndex?: number;
+}
+
+const PlainOverlay: React.StatelessComponent<OverlayProps> = ({ children, className, onClose }) => (
+ <Flex height="100vh" className={className}>
+ <Container position="absolute" top="0px" right="0px" display={{ default: 'initial', sm: 'none' }}>
+ <Icon height={18} width={18} color={ColorOption.white} icon="closeX" onClick={onClose} padding="2em 2em" />
+ </Container>
+ <Container width={{ default: 'auto', sm: '100%' }} height={{ default: 'auto', sm: '100%' }}>
+ {children}
+ </Container>
+ </Flex>
+);
+export const Overlay = styled(PlainOverlay)`
+ position: fixed;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ z-index: ${props => props.zIndex}
+ background-color: ${overlayBlack};
+`;
+
+Overlay.defaultProps = {
+ zIndex: 100,
+};
+
+Overlay.displayName = 'Overlay';
diff --git a/packages/instant/src/components/ui/spinner.tsx b/packages/instant/src/components/ui/spinner.tsx
new file mode 100644
index 000000000..28ebc2598
--- /dev/null
+++ b/packages/instant/src/components/ui/spinner.tsx
@@ -0,0 +1,30 @@
+import * as React from 'react';
+
+import { FullRotation } from '../animations/full_rotation';
+
+export interface SpinnerProps {
+ widthPx: number;
+ heightPx: number;
+}
+export const Spinner: React.StatelessComponent<SpinnerProps> = props => {
+ return (
+ <FullRotation width={`${props.widthPx}px`} height={`${props.heightPx}px`}>
+ <svg
+ width={props.widthPx}
+ height={props.heightPx}
+ viewBox="0 0 34 34"
+ fill="none"
+ xmlns="http://www.w3.org/2000/svg"
+ >
+ <circle cx="17" cy="17" r="15" stroke="white" strokeOpacity="0.2" strokeWidth="4" />
+ <path
+ d="M17 32C25.2843 32 32 25.2843 32 17C32 8.71573 25.2843 2 17 2"
+ stroke="white"
+ strokeWidth="4"
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ />
+ </svg>
+ </FullRotation>
+ );
+};
diff --git a/packages/instant/src/components/ui/text.tsx b/packages/instant/src/components/ui/text.tsx
new file mode 100644
index 000000000..cba6e7b20
--- /dev/null
+++ b/packages/instant/src/components/ui/text.tsx
@@ -0,0 +1,74 @@
+import { darken } from 'polished';
+import * as React from 'react';
+
+import { ColorOption, styled } from '../../style/theme';
+
+export interface TextProps {
+ fontColor?: ColorOption;
+ fontFamily?: string;
+ fontStyle?: string;
+ fontSize?: string;
+ opacity?: number;
+ letterSpacing?: string;
+ textTransform?: string;
+ lineHeight?: string;
+ className?: string;
+ minHeight?: string;
+ center?: boolean;
+ fontWeight?: number | string;
+ textDecorationLine?: string;
+ onClick?: (event: React.MouseEvent<HTMLElement>) => void;
+ noWrap?: boolean;
+ display?: string;
+}
+
+const darkenOnHoverAmount = 0.3;
+export const Text =
+ styled.div <
+ TextProps >
+ `
+ font-family: ${props => props.fontFamily};
+ font-style: ${props => props.fontStyle};
+ font-weight: ${props => props.fontWeight};
+ font-size: ${props => props.fontSize};
+ opacity: ${props => props.opacity};
+ text-decoration-line: ${props => props.textDecorationLine};
+ ${props => (props.lineHeight ? `line-height: ${props.lineHeight}` : '')};
+ ${props => (props.center ? 'text-align: center' : '')};
+ color: ${props => props.fontColor && props.theme[props.fontColor]};
+ ${props => (props.minHeight ? `min-height: ${props.minHeight}` : '')};
+ ${props => (props.onClick ? 'cursor: pointer' : '')};
+ transition: color 0.5s ease;
+ ${props => (props.noWrap ? 'white-space: nowrap' : '')};
+ ${props => (props.display ? `display: ${props.display}` : '')};
+ ${props => (props.letterSpacing ? `letter-spacing: ${props.letterSpacing}` : '')};
+ ${props => (props.textTransform ? `text-transform: ${props.textTransform}` : '')};
+ &:hover {
+ ${props =>
+ props.onClick ? `color: ${darken(darkenOnHoverAmount, props.theme[props.fontColor || 'white'])}` : ''};
+ }
+`;
+
+Text.defaultProps = {
+ fontFamily: 'Inter UI',
+ fontStyle: 'normal',
+ fontWeight: 400,
+ fontColor: ColorOption.black,
+ fontSize: '15px',
+ textDecorationLine: 'none',
+ noWrap: false,
+ display: 'inline-block',
+};
+
+Text.displayName = 'Text';
+
+export const Title: React.StatelessComponent<TextProps> = props => <Text {...props} />;
+
+Title.defaultProps = {
+ fontSize: '20px',
+ fontWeight: 600,
+ opacity: 1,
+ fontColor: ColorOption.primaryColor,
+};
+
+Title.displayName = 'Title';