import React from 'react'; import styled, { keyframes } from 'styled-components'; const SHOW_ANIMATION_NEXT_DURATION = 3000; const NEXT_ANIMATION_DURATION = 600; const Box = styled.div` position: relative; width: 100%; height: 100%; overflow: hidden; `; const Item = styled.div` display: flex; width: 100%; height: 100%; position: absolute; top: 100%; left: 0; backfaceVisibility: hidden; perspective: 0; flex-direction: row; alignItems: center; overflow: hidden; &.showingStatic { top: 0; } &.showing { animation-name: ${ keyframes` 0% { top: 100%; } 100% { top: 0; } ` }; animation-duration: ${NEXT_ANIMATION_DURATION}ms; animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); animation-fill-mode: forwards; } &.hiding { animation-name: ${ keyframes` 0% { top: 0; } 100% { top: -100%; } ` }; animation-duration: ${NEXT_ANIMATION_DURATION}ms; animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1); animation-fill-mode: forwards; } ` export class Announcement extends React.Component<{ announcements: any[] }> { state = { showingIndex: 0, prevIndex: -1 } componentDidMount() { setTimeout(() => { this.showNext(); }, SHOW_ANIMATION_NEXT_DURATION) } componentWillUnmount(): void { this.stopShowNext(); } render () { const { showingIndex, prevIndex } = this.state; const { announcements } = this.props; return ( { announcements.map((announcement, index) => ( {announcement} )) } ) } __destroyed = false; stopShowNext () { this.__destroyed = true; } showNext () { if (this.__destroyed) { return; } const { showingIndex } = this.state; const { announcements } = this.props; const max = announcements.length; let targetIndex = showingIndex + 1; if (targetIndex >= max) { targetIndex = 0; } if (targetIndex !== showingIndex) { this.setState({ showingIndex: targetIndex, prevIndex: showingIndex }) } if (!this.__destroyed) { setTimeout(() => { this.showNext(); }, SHOW_ANIMATION_NEXT_DURATION) } } }