diff --git a/README.md b/README.md index 40102b2..ed107d8 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,17 @@ # Material AutoRotatingCarousel -[![Build Status](https://travis-ci.org/TeamWertarbyte/material-auto-rotating-carousel.svg?branch=master)](https://travis-ci.org/TeamWertarbyte/material-auto-rotating-carousel) -[![Greenkeeper badge](https://badges.greenkeeper.io/TeamWertarbyte/material-auto-rotating-carousel.svg)](https://greenkeeper.io/) +[![Build Status](https://travis-ci.org/TeamWertarbyte/material-auto-rotating-carousel.svg?branch=next)](https://travis-ci.org/TeamWertarbyte/material-auto-rotating-carousel) [![Standard - JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com) -[![NPM](https://nodei.co/npm/material-auto-rotating-carousel.png?downloads=true&stars=true)](https://nodei.co/npm/material-auto-rotating-carousel/) - So you wrote a great app and deployed it and everything. But how do you introduce new users to your app? Well, the Material design guidelines have a solution: Displaying the top benefits in a beautiful [auto-rotating carousel](https://material.google.com/growth-communications/onboarding.html#onboarding-top-user-benefits)! -This project implements such a carousel for [material-ui](https://material-ui.com). See [the storybook](https://teamwertarbyte.github.io/material-auto-rotating-carousel) for an interactive demo. +This project implements such a carousel for [material-ui](https://material-ui-next.com). Visit [the styleguide](https://next.mui.wertarbyte.com/#material-auto-rotating-carousel) for an interactive demo. ![Demo](demo.gif) ## Installation ```shell -npm i --save material-auto-rotating-carousel +npm i --save material-auto-rotating-carousel@next npm i --save react-swipeable-views ``` @@ -39,21 +36,21 @@ render() { } mediaBackgroundStyle={{ backgroundColor: red400 }} - contentStyle={{ backgroundColor: red600 }} + style={{ backgroundColor: red600 }} title="This is a very cool feature" subtitle="Just using this will blow your mind." /> } mediaBackgroundStyle={{ backgroundColor: blue400 }} - contentStyle={{ backgroundColor: blue600 }} + style={{ backgroundColor: blue600 }} title="Ever wanted to be popular?" subtitle="Well just mix two colors and your are good to go!" /> } mediaBackgroundStyle={{ backgroundColor: green400 }} - contentStyle={{ backgroundColor: green600 }} + style={{ backgroundColor: green600 }} title="May the force be with you" subtitle="The Force is a metaphysical and ubiquitous power in the Star Wars universe." /> @@ -68,30 +65,24 @@ render() { |Name |Type |Default |Description |----------------|------------|------------|-------------------------------- |autoplay | `bool` | `true` | If `false`, the auto play behavior is disabled. -|contentStyle | `object` | | Override the inline-styles of the content container. |interval | `integer` | `3000` | Delay between auto play transitions (in ms). |label | `string` | | Button text. If not supplied, the button will be hidden. |landscape | `bool` | | If `true`, slide will adjust content for wide mobile screens. |mobile | `bool` | `false` | If `true`, the screen width and height is filled. |open | `bool` | `false` | Controls whether the AutoRotatingCarousel is opened or not. |onChange | `function` | | Fired when the index changed. Returns current index. -|onRequestClose | `function` | | Fired when the gray background of the popup is pressed when it is open. +|onClose | `function` | | Fired when the gray background of the popup is pressed when it is open. |onStart | `function` | | Fired when the user clicks the getting started button. -|style | `object` | | Override the inline-styles of the root component. ### Slide Properties |Name |Type |Default |Description |-----------------------|-----------|-------------|-------------------------------- -|contentStyle | `object` | | Override the inline-styles of the content. |media* | `node` | | Object to display in the upper half. |mediaBackgroundStyle | `object` | | Override the inline-styles of the media container. -|mediaStyle | `object` | | Override the inline-styles of the media. +|style | `object` | | Override the inline-styles of the slide. |subtitle* | `string` | | Subtitle for the slide. -|subtitleStyle | `object` | | Override the inline-styles of the subtitle. -|textStyle | `object` | | Override the inline-styles of the text container. |title* | `string` | | Title for the slide. -|titleStyle | `object` | | Override the inline-styles of the title. \* required property diff --git a/src/AutoRotatingCarousel.js b/src/AutoRotatingCarousel.js index 2df4bd9..c451d8f 100644 --- a/src/AutoRotatingCarousel.js +++ b/src/AutoRotatingCarousel.js @@ -2,27 +2,57 @@ import React, { Component } from 'react' import PropTypes from 'prop-types' import { Button, Paper } from 'material-ui' import { grey } from 'material-ui/colors' +import withStyles from 'material-ui/styles/withStyles' +import { duration } from 'material-ui/styles/transitions' import ArrowBackIcon from 'material-ui-icons/ArrowBack' import ArrowForwardIcon from 'material-ui-icons/ArrowForward' +import Modal from 'material-ui/Modal' +import Fade from 'material-ui/transitions/Fade' import Dots from 'material-ui-dots' +import classNames from 'classnames' import Carousel from './SwipableCarouselView' import { modulo } from './util' -const desktopStyles = { - arrowLeft: { +const styles = { + root: { + '& > *:focus': { + outline: 'none' + } + }, + content: { + width: '60%', + maxWidth: 700, + height: 'calc(100% - 96px)', + maxHeight: 600, + margin: '-16px auto 0', + position: 'relative', + top: '50%', + transform: 'translateY(-50%)' + }, + contentMobile: { + width: '100%', + height: '100%', + maxWidth: 'initial', + maxHeight: 'initial', + margin: 0, + top: 0, + transform: 'none' + }, + arrow: { width: 48, height: 48, position: 'absolute', - top: 'calc((100% - 96px) / 2 + 24px)', + top: 'calc((100% - 96px) / 2 + 24px)' + }, + arrowLeft: { left: -96 }, arrowRight: { - width: 48, - height: 48, - position: 'absolute', - top: 'calc((100% - 96px) / 2 + 24px)', right: -96 }, + arrowIcon: { + color: grey[700] + }, carouselWrapper: { overflow: 'hidden', borderRadius: 14, @@ -30,94 +60,55 @@ const desktopStyles = { background: 'transparent', height: '100%' }, - arrowIcon: { - color: grey[700] - }, - root: { - height: '100%', - width: '100%', - position: 'fixed', - zIndex: 1400, - left: 0, - top: 0, - backgroundColor: 'rgba(0,0,0,0.5)', - transition: 'opacity 400ms cubic-bezier(0.4, 0, 0.2, 1)' - }, - content: { - width: '60%', - maxWidth: 700, - height: 'calc(100% - 96px)', - maxHeight: 600, - margin: '-16px auto 0', - position: 'relative', - top: '50%', - transform: 'translateY(-50%)' - }, dots: { paddingTop: 36, margin: '0 auto' }, + dotsMobile: { + paddingTop: 0 + }, + dotsMobileLandscape: { + paddingTop: 20 + }, footer: { marginTop: -72, width: '100%', position: 'relative', textAlign: 'center' }, + footerMobile: { + marginTop: -92 + }, + footerMobileLandscape: { + marginTop: -3, + transform: 'translateY(-50vh)', + display: 'inline-block', + width: 'auto' + }, slide: { width: '100%', height: '100%' }, + slideMobile: { + width: '100%', + height: '100%' + }, carousel: { height: '100%' }, carouselContainer: { height: '100%' - } -} - -const mobileStyles = { - root: { - height: '100%', - width: '100%', - position: 'fixed', - zIndex: 1400, - left: 0, - top: 0 - }, - content: {}, - dots: { - margin: '0 auto' - }, - dotsLandscape: { - paddingTop: 20, - margin: '0 auto' - }, - footer: { - marginTop: -92, - width: '100%', - position: 'relative', - textAlign: 'center' - }, - footerLandscape: { - marginTop: -3, - transform: 'translateY(-50vh)', - textAlign: 'center', - display: 'inline-block' }, - slide: { - width: '100%', - height: '100vh' - } + closed: {} } -export default class AutoRotatingCarousel extends Component { - constructor (props) { - super(props) - this.state = { - slideIndex: 0 - } +class AutoRotatingCarousel extends Component { + state = { + slideIndex: 0 } + handleContentClick = (e) => e.stopPropagation() || e.preventDefault() + handleChange = (slideIndex) => { this.setState({ slideIndex @@ -145,76 +136,110 @@ export default class AutoRotatingCarousel extends Component { } render () { - const style = this.props.mobile ? mobileStyles : desktopStyles - const landscape = this.props.mobile && this.props.landscape + const { + autoplay, + children, + classes, + hideArrows, + interval, + label, + landscape: landscapeProp, + mobile, + open, + onClose, + onStart + } = this.props + const landscape = mobile && landscapeProp + const transitionDuration = { enter: duration.enteringScreen, exit: duration.leavingScreen } + + const carousel = ( + + {children.map((c, i) => React.cloneElement(c, { + mobile, + landscape, + key: i + }))} + + ) return ( -
-
evt.stopPropagation() || evt.preventDefault()}> - - - {this.props.children.map((c, i) => React.cloneElement(c, { - mobile: this.props.mobile, - landscape: this.props.landscape, - key: i - }))} - - -
-
- {this.props.label && } - + {label && } + +
+ {!mobile && !hideArrows && ( +
+ + +
+ )}
- {!this.props.mobile && !this.props.hideArrows ?
- - -
: null - } -
- + + ) } } @@ -230,8 +255,8 @@ AutoRotatingCarousel.defaultProps = { AutoRotatingCarousel.propTypes = { /** If `false`, the auto play behavior is disabled. */ autoplay: PropTypes.bool, - /** Override the inline-styles of the content container. */ - contentStyle: PropTypes.object, + /** Object for customizing the CSS classes. */ + classes: PropTypes.object.isRequired, /** Delay between auto play transitions (in ms). */ interval: PropTypes.number, /** Button text. If not supplied, the button will be hidden. */ @@ -243,15 +268,13 @@ AutoRotatingCarousel.propTypes = { /** Fired when the index changed. Returns current index. */ onChange: PropTypes.func, /** Fired when the gray background of the popup is pressed when it is open. */ - onRequestClose: PropTypes.func, + onClose: PropTypes.func, /** Fired when the user clicks the getting started button. */ onStart: PropTypes.func, /** Controls whether the AutoRotatingCarousel is opened or not. */ open: PropTypes.bool, - /** Override the inline-styles of the root component. */ - style: PropTypes.object, /** If `true`, the left and right arrows are hidden in the desktop version. */ - hideArrows: PropTypes.bool, - /** Color of the dots used */ - dotColor: PropTypes.string + hideArrows: PropTypes.bool } + +export default withStyles(styles)(AutoRotatingCarousel) diff --git a/src/AutoRotatingCarousel.md b/src/AutoRotatingCarousel.md index b254e07..6d71f5b 100644 --- a/src/AutoRotatingCarousel.md +++ b/src/AutoRotatingCarousel.md @@ -3,34 +3,37 @@ ``` const Slide = require('./Slide').default; const { red, blue, green } = require('material-ui/colors'); +const Button = require('material-ui/Button').default;
- - } - mediaBackgroundStyle={{backgroundColor: red[400]}} - contentStyle={{backgroundColor: red[600]}} - title='This is a very cool feature' - subtitle='Just using this will blow your mind.' - /> - } - mediaBackgroundStyle={{backgroundColor: blue[400]}} - contentStyle={{backgroundColor: blue[600]}} - title='Ever wanted to be popular?' - subtitle='Well just mix two colors and your are good to go!' - /> - } - mediaBackgroundStyle={{backgroundColor: green[400]}} - contentStyle={{backgroundColor: green[600]}} - title='May the force be with you' - subtitle='The Force is a metaphysical and ubiquitous power in the Star Wars fictional universe.' - /> - + + setState({ open: false })} + style={{ position: 'absolute' }} + > + } + mediaBackgroundStyle={{ backgroundColor: red[400] }} + style={{ backgroundColor: red[600] }} + title='This is a very cool feature' + subtitle='Just using this will blow your mind.' + /> + } + mediaBackgroundStyle={{ backgroundColor: blue[400] }} + style={{ backgroundColor: blue[600] }} + title='Ever wanted to be popular?' + subtitle='Well just mix two colors and your are good to go!' + /> + } + mediaBackgroundStyle={{ backgroundColor: green[400] }} + style={{ backgroundColor: green[600] }} + title='May the force be with you' + subtitle='The Force is a metaphysical and ubiquitous power in the Star Wars fictional universe.' + /> +
``` diff --git a/src/Slide.js b/src/Slide.js index 005c16b..f518a70 100644 --- a/src/Slide.js +++ b/src/Slide.js @@ -1,12 +1,12 @@ import React from 'react' import PropTypes from 'prop-types' +import Typography from 'material-ui/Typography' import { blue } from 'material-ui/colors' import withStyles from 'material-ui/styles/withStyles' import classNames from 'classnames' const styles = { root: { - color: 'white', backgroundColor: blue[500], height: '100%' }, @@ -61,7 +61,8 @@ const styles = { padding: '24px 24px 128px', flex: '0 1', alignSelf: 'center', - textAlign: 'left' + textAlign: 'left', + margin: 0 }, title: { fontSize: '24px', @@ -70,13 +71,15 @@ const styles = { marginBottom: 12, textOverflow: 'ellipsis', whiteSpace: 'nowrap', - overflow: 'hidden' + overflow: 'hidden', + color: '#fff' }, subtitle: { fontSize: '15px', fontWeight: 400, lineHeight: '18px', - margin: 0 + margin: 0, + color: '#fff' } } @@ -84,23 +87,31 @@ function Slide (props) { const { classes, media, + mediaBackgroundStyle, subtitle, title, mobile, - landscape: landscapeProp + landscape, + ...other } = props - const mobileLandscape = mobile && landscapeProp + const mobileLandscape = mobile && landscape return ( -
-
+
+
-
-
+
+ {title} -
-

+ + {subtitle} -

+
) @@ -132,13 +145,17 @@ Slide.propTypes = { * Object to display in the upper half. */ media: PropTypes.node.isRequired, + /** + * Override the inline-styles of the media container. + */ + mediaBackgroundStyle: PropTypes.object, /** * Subtitle of the slide. - **/ + */ subtitle: PropTypes.string.isRequired, /** * Title of the slide. - **/ + */ title: PropTypes.string.isRequired, /** * If `true`, the screen width and height is filled.