|  | 
|  | 1 | +import React from 'react'; | 
|  | 2 | +import PropTypes from 'prop-types'; | 
|  | 3 | + | 
|  | 4 | +import useDeck, { DeckContext } from '../hooks/useDeck'; | 
|  | 5 | +import isComponentType from '../utils/isComponentType.js'; | 
|  | 6 | +import { useTransition, animated } from 'react-spring'; | 
|  | 7 | + | 
|  | 8 | +/** | 
|  | 9 | + * Provides top level state/context provider with useDeck hook | 
|  | 10 | + * Should wrap all the presentation components (slides, etc) | 
|  | 11 | + * | 
|  | 12 | + * Props = { | 
|  | 13 | + *  loop: bool (pass in true if you want slides to loop) | 
|  | 14 | + * transitionEffect: based off of react sprint useTransition | 
|  | 15 | + * } | 
|  | 16 | + * | 
|  | 17 | + * Note: Immediate is a React-Spring property that we pass to the animations | 
|  | 18 | + * essentially it skips animations. | 
|  | 19 | + */ | 
|  | 20 | + | 
|  | 21 | +const initialState = { currentSlide: 0, immediate: false }; | 
|  | 22 | + | 
|  | 23 | +const Deck = ({ children, loop, keyboardControls, ...rest }) => { | 
|  | 24 | +  // Our default effect for transitioning between slides | 
|  | 25 | +  const defaultSlideEffect = { | 
|  | 26 | +    from: { | 
|  | 27 | +      width: '100%', | 
|  | 28 | +      position: 'absolute', | 
|  | 29 | +      transform: 'translate(100%, 0%)' | 
|  | 30 | +    }, | 
|  | 31 | +    enter: { | 
|  | 32 | +      width: '100%', | 
|  | 33 | +      position: 'absolute', | 
|  | 34 | +      transform: 'translate(0, 0%)' | 
|  | 35 | +    }, | 
|  | 36 | +    leave: { | 
|  | 37 | +      width: '100%', | 
|  | 38 | +      position: 'absolute', | 
|  | 39 | +      transform: 'translate(-100%, 0%)' | 
|  | 40 | +    }, | 
|  | 41 | +    config: { precision: 0 } | 
|  | 42 | +  }; | 
|  | 43 | +  // Check for slides and then number slides. | 
|  | 44 | +  const filteredChildren = Array.isArray(children) | 
|  | 45 | +    ? children | 
|  | 46 | +        // filter if is a Slide | 
|  | 47 | +        .filter(x => isComponentType(x, 'Slide')) | 
|  | 48 | +    : console.error('No children passed') || []; | 
|  | 49 | + | 
|  | 50 | +  // return a wrapped slide with the animated.div + style prop curried | 
|  | 51 | +  // and a slideNum prop based on iterator | 
|  | 52 | + | 
|  | 53 | +  const Slides = filteredChildren.map(( | 
|  | 54 | +    x, | 
|  | 55 | +    i // eslint-disable-next-line react/display-name | 
|  | 56 | +  ) => ({ style }) => ( | 
|  | 57 | +    <animated.div style={{ ...style }}> | 
|  | 58 | +      {{ | 
|  | 59 | +        ...x, | 
|  | 60 | +        props: { ...x.props, slideNum: i, keyboardControls } | 
|  | 61 | +      }} | 
|  | 62 | +    </animated.div> | 
|  | 63 | +  )); | 
|  | 64 | + | 
|  | 65 | +  // Initialise useDeck hook and get state and dispatch off of it | 
|  | 66 | +  const [state, dispatch] = useDeck( | 
|  | 67 | +    initialState, | 
|  | 68 | +    Slides.length, | 
|  | 69 | +    loop ? true : false, | 
|  | 70 | +    rest.animationsWhenGoingBack | 
|  | 71 | +  ); | 
|  | 72 | + | 
|  | 73 | +  const transitions = useTransition(state.currentSlide, p => p, { | 
|  | 74 | +    ...(filteredChildren[state.currentSlide].props.transitionEffect || | 
|  | 75 | +      defaultSlideEffect), | 
|  | 76 | +    unique: true, | 
|  | 77 | +    immediate: state.immediate | 
|  | 78 | +  }); | 
|  | 79 | + | 
|  | 80 | +  return ( | 
|  | 81 | +    <div | 
|  | 82 | +      style={{ | 
|  | 83 | +        position: 'relative', | 
|  | 84 | +        height: '50vh', | 
|  | 85 | +        width: '100%', | 
|  | 86 | +        overflowX: 'hidden' | 
|  | 87 | +      }} | 
|  | 88 | +    > | 
|  | 89 | +      <DeckContext.Provider | 
|  | 90 | +        value={[ | 
|  | 91 | +          state, | 
|  | 92 | +          dispatch, | 
|  | 93 | +          Slides.length, | 
|  | 94 | +          keyboardControls, | 
|  | 95 | +          rest.animationsWhenGoingBack | 
|  | 96 | +        ]} | 
|  | 97 | +      > | 
|  | 98 | +        {transitions.map(({ item, props, key }) => { | 
|  | 99 | +          const Slide = Slides[item]; | 
|  | 100 | +          return <Slide key={key} style={props} />; | 
|  | 101 | +        })} | 
|  | 102 | +      </DeckContext.Provider> | 
|  | 103 | +    </div> | 
|  | 104 | +  ); | 
|  | 105 | +}; | 
|  | 106 | + | 
|  | 107 | +Deck.propTypes = { | 
|  | 108 | +  animationsWhenGoingBack: PropTypes.bool.isRequired, | 
|  | 109 | +  children: PropTypes.node.isRequired, | 
|  | 110 | +  keyboardControls: PropTypes.oneOf(['arrows', 'space']), | 
|  | 111 | +  loop: PropTypes.bool.isRequired | 
|  | 112 | +}; | 
|  | 113 | + | 
|  | 114 | +Deck.defaultProps = { | 
|  | 115 | +  loop: false, | 
|  | 116 | +  keyboardControls: 'arrows', | 
|  | 117 | +  animationsWhenGoingBack: false | 
|  | 118 | +}; | 
|  | 119 | + | 
|  | 120 | +export default Deck; | 
0 commit comments