diff options
| author | Steve Klebanoff <steve@0xproject.com> | 2018-11-09 07:37:56 +0800 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-11-09 07:37:56 +0800 | 
| commit | 117e2f583ff44bdb63340a2134edea0f3ecb77b3 (patch) | |
| tree | 9d7552953145bb784c4f6ef32c525b11081e603c | |
| parent | c448a409c1dd7411208aeb577b64ba1246fc03d1 (diff) | |
| download | dexon-sol-tools-117e2f583ff44bdb63340a2134edea0f3ecb77b3.tar.gz dexon-sol-tools-117e2f583ff44bdb63340a2134edea0f3ecb77b3.tar.zst dexon-sol-tools-117e2f583ff44bdb63340a2134edea0f3ecb77b3.zip | |
[instant] Viewport specific errors (#1228)
feat(instant): Shows different error animation based on viewport
8 files changed, 118 insertions, 49 deletions
| diff --git a/packages/instant/src/components/animations/position_animation.tsx b/packages/instant/src/components/animations/position_animation.tsx index 4bb21befb..576d29c07 100644 --- a/packages/instant/src/components/animations/position_animation.tsx +++ b/packages/instant/src/components/animations/position_animation.tsx @@ -1,5 +1,6 @@ -import { Keyframes } from 'styled-components'; +import { InterpolationValue } from 'styled-components'; +import { media, OptionallyScreenSpecific, stylesForMedia } from '../../style/media';  import { css, keyframes, styled } from '../../style/theme';  export interface TransitionInfo { @@ -51,30 +52,57 @@ export interface PositionAnimationSettings {      right?: TransitionInfo;      timingFunction: string;      duration?: string; +    position?: string;  } -export interface PositionAnimationProps extends PositionAnimationSettings { -    position: string; +const generatePositionAnimationCss = (positionSettings: PositionAnimationSettings) => { +    return css` +        animation-name: ${slideKeyframeGenerator( +            positionSettings.position || 'relative', +            positionSettings.top, +            positionSettings.bottom, +            positionSettings.left, +            positionSettings.right, +        )}; +        animation-duration: ${positionSettings.duration || '0.3s'}; +        animation-timing-function: ${positionSettings.timingFunction}; +        animation-delay: 0s; +        animation-iteration-count: 1; +        animation-fill-mode: forwards; +        position: ${positionSettings.position || 'relative'}; +        width: 100%; +    `; +}; + +export interface PositionAnimationProps { +    positionSettings: OptionallyScreenSpecific<PositionAnimationSettings>; +    zIndex?: OptionallyScreenSpecific<number>;  } +const defaultAnimation = (positionSettings: OptionallyScreenSpecific<PositionAnimationSettings>) => { +    const bestDefault = 'default' in positionSettings ? positionSettings.default : positionSettings; +    return generatePositionAnimationCss(bestDefault); +}; +const animationForSize = ( +    positionSettings: OptionallyScreenSpecific<PositionAnimationSettings>, +    sizeKey: 'sm' | 'md' | 'lg', +    mediaFn: (...args: any[]) => InterpolationValue[], +) => { +    // checking default makes sure we have a PositionAnimationSettings object +    // and then we check to see if we have a setting for the specific `sizeKey` +    const animationSettingsForSize = 'default' in positionSettings && positionSettings[sizeKey]; +    return animationSettingsForSize && mediaFn`${generatePositionAnimationCss(animationSettingsForSize)}`; +}; +  export const PositionAnimation =      styled.div <      PositionAnimationProps >      ` -    animation-name: ${props => -        css` -            ${slideKeyframeGenerator(props.position, props.top, props.bottom, props.left, props.right)}; -        `}; -    animation-duration: ${props => props.duration || '0.3s'}; -    animation-timing-function: ${props => props.timingFunction}; -    animation-delay: 0s; -    animation-iteration-count: 1; -    animation-fill-mode: forwards; -    position: ${props => props.position}; -    height: 100%; -    width: 100%; +    && { +        ${props => props.zIndex && stylesForMedia<number>('z-index', props.zIndex)} +        ${props => defaultAnimation(props.positionSettings)} +        ${props => animationForSize(props.positionSettings, 'sm', media.small)} +        ${props => animationForSize(props.positionSettings, 'md', media.medium)} +        ${props => animationForSize(props.positionSettings, 'lg', media.large)} +    }  `; - -PositionAnimation.defaultProps = { -    position: 'relative', -}; diff --git a/packages/instant/src/components/animations/slide_animation.tsx b/packages/instant/src/components/animations/slide_animation.tsx index 66a314c7f..122229dee 100644 --- a/packages/instant/src/components/animations/slide_animation.tsx +++ b/packages/instant/src/components/animations/slide_animation.tsx @@ -1,22 +1,24 @@  import * as React from 'react'; +import { OptionallyScreenSpecific } from '../../style/media'; +  import { PositionAnimation, PositionAnimationSettings } from './position_animation';  export type SlideAnimationState = 'slidIn' | 'slidOut' | 'none';  export interface SlideAnimationProps { -    position: string;      animationState: SlideAnimationState; -    slideInSettings: PositionAnimationSettings; -    slideOutSettings: PositionAnimationSettings; +    slideInSettings: OptionallyScreenSpecific<PositionAnimationSettings>; +    slideOutSettings: OptionallyScreenSpecific<PositionAnimationSettings>; +    zIndex?: OptionallyScreenSpecific<number>;  }  export const SlideAnimation: React.StatelessComponent<SlideAnimationProps> = props => {      if (props.animationState === 'none') {          return <React.Fragment>{props.children}</React.Fragment>;      } -    const propsToUse = props.animationState === 'slidIn' ? props.slideInSettings : props.slideOutSettings; +    const positionSettings = props.animationState === 'slidIn' ? props.slideInSettings : props.slideOutSettings;      return ( -        <PositionAnimation position={props.position} {...propsToUse}> +        <PositionAnimation positionSettings={positionSettings} zIndex={props.zIndex}>              {props.children}          </PositionAnimation>      ); diff --git a/packages/instant/src/components/sliding_error.tsx b/packages/instant/src/components/sliding_error.tsx index a923b9932..462199d78 100644 --- a/packages/instant/src/components/sliding_error.tsx +++ b/packages/instant/src/components/sliding_error.tsx @@ -1,6 +1,8 @@  import * as React from 'react'; +import { ScreenSpecification } from '../style/media';  import { ColorOption } from '../style/theme'; +import { zIndex } from '../style/z_index';  import { PositionAnimationSettings } from './animations/position_animation';  import { SlideAnimation, SlideAnimationState } from './animations/slide_animation'; @@ -21,6 +23,7 @@ export const Error: React.StatelessComponent<ErrorProps> = props => (          backgroundColor={ColorOption.lightOrange}          width="100%"          borderRadius="6px" +        marginTop="10px"          marginBottom="10px"      >          <Flex justify="flex-start"> @@ -39,25 +42,51 @@ export interface SlidingErrorProps extends ErrorProps {  }  export const SlidingError: React.StatelessComponent<SlidingErrorProps> = props => {      const slideAmount = '120px'; -    const slideUpSettings: PositionAnimationSettings = { + +    const desktopSlideIn: PositionAnimationSettings = {          timingFunction: 'ease-in',          top: {              from: slideAmount,              to: '0px',          }, +        position: 'relative',      }; -    const slideDownSettings: PositionAnimationSettings = { +    const desktopSlideOut: PositionAnimationSettings = {          timingFunction: 'cubic-bezier(0.25, 0.1, 0.25, 1)',          top: {              from: '0px',              to: slideAmount,          }, +        position: 'relative', +    }; + +    const mobileSlideIn: PositionAnimationSettings = { +        duration: '0.5s', +        timingFunction: 'ease-in', +        top: { from: '-120px', to: '0px' }, +        position: 'fixed', +    }; +    const moblieSlideOut: PositionAnimationSettings = { +        duration: '0.5s', +        timingFunction: 'ease-in', +        top: { from: '0px', to: '-120px' }, +        position: 'fixed', +    }; + +    const slideUpSettings: ScreenSpecification<PositionAnimationSettings> = { +        default: desktopSlideIn, +        sm: mobileSlideIn,      }; +    const slideOutSettings: ScreenSpecification<PositionAnimationSettings> = { +        default: desktopSlideOut, +        sm: moblieSlideOut, +    }; +      return (          <SlideAnimation -            position="relative"              slideInSettings={slideUpSettings} -            slideOutSettings={slideDownSettings} +            slideOutSettings={slideOutSettings} +            zIndex={{ sm: zIndex.errorPopUp, default: zIndex.errorPopBehind }}              animationState={props.animationState}          >              <Error icon={props.icon} message={props.message} /> diff --git a/packages/instant/src/components/sliding_panel.tsx b/packages/instant/src/components/sliding_panel.tsx index 7ef28e09c..a5d15c401 100644 --- a/packages/instant/src/components/sliding_panel.tsx +++ b/packages/instant/src/components/sliding_panel.tsx @@ -51,6 +51,7 @@ export const SlidingPanel: React.StatelessComponent<SlidingPanelProps> = props =              from: slideAmount,              to: '0px',          }, +        position: 'absolute',      };      const slideDownSettings: PositionAnimationSettings = {          duration: '0.3s', @@ -59,10 +60,10 @@ export const SlidingPanel: React.StatelessComponent<SlidingPanelProps> = props =              from: '0px',              to: slideAmount,          }, +        position: 'absolute',      };      return (          <SlideAnimation -            position="absolute"              slideInSettings={slideUpSettings}              slideOutSettings={slideDownSettings}              animationState={animationState} diff --git a/packages/instant/src/components/ui/container.tsx b/packages/instant/src/components/ui/container.tsx index bffa1d7d4..c42082ed5 100644 --- a/packages/instant/src/components/ui/container.tsx +++ b/packages/instant/src/components/ui/container.tsx @@ -67,9 +67,9 @@ export const Container =          ${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 => (props.width ? stylesForMedia('width', props.width) : '')} -        ${props => (props.height ? stylesForMedia('height', props.height) : '')} +        ${props => props.display && stylesForMedia<string>('display', props.display)} +        ${props => props.width && stylesForMedia<string>('width', props.width)} +        ${props => props.height && stylesForMedia<string>('height', props.height)}          background-color: ${props => (props.backgroundColor ? props.theme[props.backgroundColor] : 'none')};          border-color: ${props => (props.borderColor ? props.theme[props.borderColor] : 'none')};          &:hover { diff --git a/packages/instant/src/components/zero_ex_instant_container.tsx b/packages/instant/src/components/zero_ex_instant_container.tsx index f5f8adefe..d2216b54f 100644 --- a/packages/instant/src/components/zero_ex_instant_container.tsx +++ b/packages/instant/src/components/zero_ex_instant_container.tsx @@ -35,7 +35,7 @@ export class ZeroExInstantContainer extends React.Component<ZeroExInstantContain                      height={{ default: 'auto', sm: '100%' }}                      position="relative"                  > -                    <Container zIndex={zIndex.errorPopup} position="relative"> +                    <Container position="relative">                          <LatestError />                      </Container>                      <Container diff --git a/packages/instant/src/style/media.ts b/packages/instant/src/style/media.ts index beabbac46..5e7aaba37 100644 --- a/packages/instant/src/style/media.ts +++ b/packages/instant/src/style/media.ts @@ -14,30 +14,38 @@ const generateMediaWrapper = (screenWidth: ScreenWidths) => (...args: any[]) =>      }  `; -const media = { +export const media = {      small: generateMediaWrapper(ScreenWidths.Sm),      medium: generateMediaWrapper(ScreenWidths.Md),      large: generateMediaWrapper(ScreenWidths.Lg),  }; -export interface ScreenSpecifications { -    default: string; -    sm?: string; -    md?: string; -    lg?: string; +export interface ScreenSpecification<T> { +    default: T; +    sm?: T; +    md?: T; +    lg?: T;  } -export type MediaChoice = string | ScreenSpecifications; -export const stylesForMedia = (cssPropertyName: string, choice: MediaChoice): InterpolationValue[] => { -    if (typeof choice === 'string') { +export type OptionallyScreenSpecific<T> = T | ScreenSpecification<T>; +export type MediaChoice = OptionallyScreenSpecific<string>; +/** + * Given a css property name and a OptionallyScreenSpecific value, + * generates css properties with screen-specific viewport styling + */ +export function stylesForMedia<T extends string | number>( +    cssPropertyName: string, +    choice: OptionallyScreenSpecific<T>, +): InterpolationValue[] { +    if (typeof choice === 'object') {          return css` -            ${cssPropertyName}: ${choice}; -        `; -    } - -    return css`          ${cssPropertyName}: ${choice.default};          ${choice.lg && media.large`${cssPropertyName}: ${choice.lg}`}          ${choice.md && media.medium`${cssPropertyName}: ${choice.md}`}          ${choice.sm && media.small`${cssPropertyName}: ${choice.sm}`}      `; -}; +    } else { +        return css` +            ${cssPropertyName}: ${choice}; +        `; +    } +} diff --git a/packages/instant/src/style/z_index.ts b/packages/instant/src/style/z_index.ts index 727a5189d..03623f044 100644 --- a/packages/instant/src/style/z_index.ts +++ b/packages/instant/src/style/z_index.ts @@ -1,5 +1,6 @@  export const zIndex = { -    errorPopup: 1, +    errorPopBehind: 1,      mainContainer: 2,      panel: 3, +    errorPopUp: 4,  }; | 
