Pure React Carousel
Created By
一个高度公正的 React 组件套件,可以由消费者组装以创建一个响应式和 aria 兼容的轮播,对 DOM 结构或 CSS 样式几乎没有限制。
[**See Live Examples**](https://express-labs.github.io/pure-react-carousel/) |
[See Example Code](src/App/examples)
Motivation
我的目标是创建一个 100% ReactJS 轮播,它不会尝试强加需要的结构或样式为了符合您网站的设计标准而被击败。 您是否厌倦了与其他开发人员的 CSS 或 DOM 结构作斗争? 如果是这样,这个旋转木马就是为你准备的。
旋转木马:爱他们或恨他们。 但是,如果您是 React 开发人员,并且必须使用旋转木马,为什么不使用曾经的旋转木马呢……
- Developed from the ground-up in React.
- Is not a wrapper or port of some non-react carousel like Slick or Flickity.
- Fully supports touch events.
- Is aria compliant.
- Is responsive by default.
- Lets you assemble the carousel components in the DOM in any order you desire so long as they are all children of a single <CarouselProvider /> component.
- Lets you put any class names, properties, attributes, or styles on any of the components that you need.
- Supports ES6 and commonjs.
- Has 100% test coverage. Solid!
Table of contents
Tutorial
让我们制作一个简单的旋转木马,其中包含三个幻灯片、一个下一步按钮和一个后退按钮。
将模块添加到您的项目中。
npm i -S pure-react-carousel
仅将所需的组件导入您的项目。
import React from 'react';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
- Using Webpack or Rollup? Does your Webpack config have a loader for "css" files? If so, import the css as well.
import React from 'react';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
import 'pure-react-carousel/dist/react-carousel.es.css';
- Put a CarouselProvider component in your code. This allows the other carousel components to communicate with each other. The only required properties are the orientation, naturalSlideWidth, and naturalSlideHeight. The naturalSlideWidth and naturalSlideHeight are used to create an aspect ratio for each slide. Since the carousel is responsive by default, it will stretch to fill in the width of it's parent container. The CarouselProvider must also have children. We'll add the children in the next step.
import React from 'react';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
import 'pure-react-carousel/dist/react-carousel.es.css';
export default class extends React.Component {
render() {
return (
<CarouselProvider
naturalSlideWidth={100}
naturalSlideHeight={125}
totalSlides={3}
></CarouselProvider>
);
}
}
- Place the components in any order you wish as long as they are children of a single CarouselProvider component. Some components have ancestor/descendant relationships but they don't have to be direct relatives. For example: Slides need to go inside of a Slider. Slides also require a sequentially numbered index prop starting at zero. Chances are, a lot of the time, you're going to be populating the slides from data and looping through the data, so it would be easy to add an index in your loop.
import React from 'react';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
import 'pure-react-carousel/dist/react-carousel.es.css';
export default class extends React.Component {
render() {
return (
<CarouselProvider
naturalSlideWidth={100}
naturalSlideHeight={125}
totalSlides={3}
>
<Slider>
<Slide index={0}>I am the first Slide.</Slide>
<Slide index={1}>I am the second Slide.</Slide>
<Slide index={2}>I am the third Slide.</Slide>
</Slider>
</CarouselProvider>
);
}
}
- Add some buttons so the user can navigate forward and backwards.
import React from 'react';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
import 'pure-react-carousel/dist/react-carousel.es.css';
export default class extends React.Component {
render() {
return (
<CarouselProvider
naturalSlideWidth={100}
naturalSlideHeight={125}
totalSlides={3}
>
<Slider>
<Slide index={0}>I am the first Slide.</Slide>
<Slide index={1}>I am the second Slide.</Slide>
<Slide index={2}>I am the third Slide.</Slide>
</Slider>
<ButtonBack>Back</ButtonBack>
<ButtonNext>Next</ButtonNext>
</CarouselProvider>
);
}
}
就是这样。 你有一个超级基本的旋转木马。
您还可以添加其他组件,例如 ButtonFirst、ButtonLast、Image 组件,甚至是在鼠标悬停或手指点击时缩放的 ImageWithZoom 组件。
显然,您可以自定义布局。 如果您需要将 Slider 组件埋在 18 个父 div 中,那就去做吧。 它仍然会做它的工作。 随意将 className 属性添加到任何组件以进一步自定义您的轮播。 或者,挂接到轮播组件中内置的许多 BEM 命名的默认 CSS 类名称。
一些组件具有祖先/后代关系,但它们不一定是父组件的直接后代。 例如,Slide 需要是 Slider 的后代,但如果需要,您可以在 slide 周围放置一堆 div 包装器。 一个很好的类比是 html 标签 table
和 tr
。 tr
标签需要是 table
的后代,但不一定是直接后代。 在树中它们之间可以有一个 tbody
。
Component Properties (props)
classname
您可以将自己的 className 属性附加到此库中的每个组件,它将附加到类列表中。 它被附加以便它在关系中具有更多的特异性,允许您的 CSS 更轻松地覆盖任何内部样式,而无需使用 !important。
styles
您可以将自己的样式属性附加到此库中的每个组件,但是,组件生成的任何样式都优先于您提供的任何样式。 某些组件,如
,需要其内部样式才能正常运行。
event props (onClick, onFocus, onBlur, etc)
您可以向任何组件提供自己的事件回调。 您的事件回调在组件的内部事件处理之后被调用。 基本上,您的回调成为对我们回调的回调。 快说 10 倍。 :-)
all other props
任何未被组件使用的剩余道具将直接传递给组件的根元素,除非该组件的文档中另有说明。 这使得该库中的所有组件都具有高度可配置性。 例如,您可以添加自己的事件处理程序,或更改 aria 标签等。
Components
<CarouselProvider />
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the CarouselProvider needs to wrap other Carousel components and JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string |
currentSlide |
number |
0 |
No |
<Slide > to display ONLY when CarouselProvider mounts. The indexing of <Slide /> components starts with 0. This is a poorly named variable and will be deprecated in a future version. |
hasMasterSpinner |
bool |
false |
No |
When true, a spinner will cover <Slider /> component until all <Image > and <ImageWithZoom > are done loading images. If there are no <Image /> or <ImageWithZoom> components, the spinner will spin until this property is set to false |
interval |
number |
5000 |
No |
Number of milliseconds to wait when the auto slideshow is active |
isPlaying |
bool |
false |
No |
Setting this to true starts an auto slideshow. After "interval" milliseconds, the slider will move by "step" slides either forward or backwards depending on the value of "playDirection". |
lockOnWindowScroll |
bool |
false |
No |
When set to true, scrolling of the carousel slides are disabled while the browser window is scrolling |
naturalSlideHeight |
number |
|
Yes |
The natural height of each <\Slide > component. ** |
naturalSlideWidth |
number |
|
Yes |
The natural width of each <\Slide > component. ** |
orientation |
string |
"horizontal" |
No |
Possible values are "horizontal" and "vertical". Let's you have a horizontal or vertical carousel. |
playDirection |
['forward'|'backward' ] |
'forward' |
No |
The direction for the auto slideshow |
step |
number |
1 |
No |
The number of slides to move when pressing the <ButtonBack /> and <ButtonNext /> buttons. |
dragStep |
number |
1 |
No |
The number of slides to move when performing a short touch drag. |
tag |
string |
'div' |
No |
The HTML element to use for the provider. |
totalSlides |
number |
|
Yes |
Always set this to match the total number of <Slide > components in your carousel |
touchEnabled |
boolean |
true |
No |
Set to true to enable touch events |
dragEnabled |
boolean |
true |
No |
Set to true to enable mouse dragging events |
visibleSlides |
number |
1 |
No |
The number of slides to show at once. This number should be <= totalSlides |
infinite |
boolean |
false |
No |
Should the carousel continue or stop at the beginning or end of the slides |
isIntrinsicHeight |
boolean |
false |
No |
Disables the enforced height ratio, and instead uses the intrinsic height of the slides. This option can only be active in horizontal orientation, it will throw an error in vertical orientation. |
The CarouselProvider component creates the following pseudo HTML by default:
<props.tag|div class="carousel [props.className]" ...props>
[props.children]
</props.tag|div>
有关 naturalSlideWidth 和 naturalSlideHeight 的更多信息
旋转木马是响应式的,默认情况下会弯曲到 父容器的整个宽度。 您可以通过 css 包含轮播宽度。 每张幻灯片的高宽比都相同(固有比例)。 CarouselProvider 需要知道每个 的默认大小。 注意:您可以通过将 的宽度设置为固定的 css 单位(如像素)来使轮播不响应。 还有许多其他方法可以使轮播不响应。
<Slider />
滑块是遮盖幻灯片的视口。 Slider 组件必须包裹一个或多个 Slide 组件。
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the Slider needs to wrap other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
classNameAnimation |
[string|null] |
null |
No |
Optional className string. The slider uses the css transform property, applying translateX to move the slider tray east and west for a horizontal slider, and translateY to move the slider north and south for a vertical slider. The actual animation is the result of applying a CSS3 transition effect. If you supply your own classNameAnimation class, the default transition is disabled and ONLY the transitions specified by the classNameAnimation class are applied. Learn more about CSS3 transitions. |
classNameTray |
[string|null] |
null |
No |
Optional className string that is applied to the Slider's tray. The "tray" is the DOM element that contains the slides. The type of DOM element is specified by the trayTag property |
classNameTrayWrap |
[string|null] |
null |
No |
Optional className string that is applied to a div that surrounds the Slider's tray |
moveThreshold |
number |
0.1 |
No |
Threshold to control the drag distance that triggers a scroll to the next or previous slide. (slide width or height * moveThreshold = drag pixel distance required to scroll) |
onMasterSpinner |
[function|null] |
null |
No |
Optional callback function that is called when the Master Spinner is visible. Requires that <CarouselProvider /> set hasMasterSpinner to true |
spinner |
function |
null |
No |
Optional inline JSX (aka "render props") to render your own custom spinner. Example () => <MyCustomSpinnerComponent /> If left blank, the default spinner is used. |
style |
object |
{} |
No |
Optional css styles to add to the Slider. Note: internal css properties take precedence over any styles specified in the styles object |
trayProps |
object |
{} |
No |
Any props you want to attach to the slider tray with the exception of className and style. The className prop is handled via classNameTray prop above. Style is used internally. Any event handlers like onMouseDown or others are called after any of our internal event handlers. |
trayTag |
string |
'ul' |
No |
The HTML tag to used for the tray (the thing that holds all the slides and moves the slides back and forth.) |
The Slider component creates the following pseudo HTML by default.
<div class="carousel__slider [carousel__slider--vertical|carousel__slider--horizontal] [props.className]" aria-live="polite" style="[props.style]" ...props>
<div class="carousel__slider-tray-wrapper [carousel__slider-tray-wrap--vertical|carousel__slider-tray-wrap--horizontal][props.classNameTrayWrap]">
<props.trayTag|ul class="carousel__slider-tray [props.classNameAnimation] [carousel__slider-tray--vertical|carousel__slider-tray--horizontal] [props.classNameTray]">
[props.children]
</props.trayTag|ul>
<div class="carousel__master-spinner-container">
<div class="carousel__spinner" />
</div>
</div>
</div>
How to Change the Default Transition Animation
- Read the documentation for the classNameAnimation property on the Slider component.
- Read about CSS3 transitions.
- Create your own CSS class that uses a CSS3 transition.
- Pass the CSS class you create to the classNameAnimation property of Slider.
<Slide />
Slide 组件是一个容器,其固有比率由 CarouselProvider naturalSlideWidth 和 naturalSlideHeight 属性计算得出。 默认情况下,滑块中一次只能显示一张幻灯片。 您可以通过更改 CarouselProvider 的 visibleSlides 属性来更改此设置。 幻灯片组件还包含一个 div,当幻灯片通过使用键盘选项卡、鼠标单击或触摸接收焦点时,它充当 aria 兼容的焦点环。
property |
type |
default |
required |
purpose |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
classNameHidden |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string when the slide is not visible. |
classNameVisible |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string when the slide is visible. |
index |
number |
|
Yes |
You must consecutively number the <Slide > components in order starting with zero. |
innerClassName |
[string|null] |
null |
No |
Optional className string that will be appended to an internal HTML element created by the Component. Best to just use Chrome Dev Tools to inspect the demo app or check the source code for <Slide /> |
innerTag |
string |
'div' |
No |
The inner HTML element for each Slide. |
onBlur |
[function|null] |
null |
No |
Optional callback function that is called after the internal onBlur function is called. It is passed the React synthetic event |
onFocus |
[function|null] |
null |
No |
Optional callback function that is called after the internal onFocus function is called. It is passed the React synthetic event |
tabIndex |
[number|null] |
null |
No |
When null, the Carousel will set this automatically. 99.9% of the time, you're going to want to leave this alone and let the carousel handle tabIndex automatically. |
tag |
string |
'li' |
No |
The root HTML element for each Slide. |
The Slide component creates the following pseudo HTML by default:
<props.tag|li class="carousel__slide [carousel__slide--focused] [props.className] [props.classNameVisible|props.classNameHidden] [carousel__slide--hidden|carousel__slide--visible]" tabIndex="[props.tabIndex]" aria-hidden="[computed internally]" onFocus="[props.onFocus]" onBlur="[props.onBlur]" style="[props.style]" ...props>
<props.innerTag|div class="carousel__inner-slide [props.innerClassName]">
[props.children]
<div class="carousel__slide-focus-ring" />
<props.innerTag|div>
</props.tag|li>
<Dot />
Dot 组件是一个 HTML 按钮。 点与幻灯片直接相关。 单击一个点会导致它的相关幻灯片滚动到滑块最左侧的可见槽中。 当前可见幻灯片的点被禁用。 您可以通过将 disabled 设置为 false 来覆盖自动禁用功能(见下表)
property |
type |
default |
required |
purpose |
children |
[string|null|node] |
null |
No |
Children is a special React property. Basically, the Dot component wraps other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means Dot will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
slide |
number |
|
Yes |
There must be a matching <Slide /> component with a matching index property. Example: <Dot slide={0} /> will match <Slide index={0} /> |
The Dot component creates the following pseudo HTML by default:
<button class="carousel__dot carousel__dot--[slide] [carousel__dot--selected] [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.children]
</button>
<DotGroup />
一个自动为您创建一堆 Dot 的复合组件。
property |
type |
default |
required |
purpose |
children |
[string|node|null] |
null |
No |
Any JSX wrapped by this component will appear AFTER the dots. |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
dotNumbers |
boolean |
false |
No |
Setting to true automatically adds text numbers the dot buttons starting at 1. |
disableActiveDots |
boolean |
true |
No |
Setting to true make all dots, including active dots, enabled. |
showAsSelectedForCurrentSlideOnly |
boolean |
false |
No |
Setting to true show only the current slide dot as selected. |
renderDots |
function |
null |
No |
It accepts props and overrides renderDots() in . |
The DotGroup component creates the following pseudo HTML by default:
<div class="carousel__dot-group [props.className]" ...props>
<!-- button repeats for each slide -->
<button class="carousel__dot carousel__dot--[slide] [carousel__dot--selected]">
[numbers or blank]
</button>
[props.children]
</div>
<Image />
property |
type |
default |
required |
purpose |
alt |
string |
"" |
No |
Specifies an alternate text for an image, if the image cannot be displayed. |
children |
[string|node|null] |
null |
Yes |
Any optional JSX wrapped by the Image component |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
hasMasterSpinner |
bool |
|
Yes |
**If set to true, a spinner will cover the entire slider viewport until all Image components with hasMasterSpinner set to true are finished loading images. It only takes one Image component with hasMasterSpinner to enable the master spinner. ** |
isBgImage |
bool |
false |
No |
Setting this to true makes the image load as a background image. Any child JSX (see children property) will appear on top of the image. If set to false, no image will appear unless your child JSX displays the image via an image tag or some other means. |
onError |
[func|null] |
null |
No |
Callback function called if the image defined by the src property fails to load. This Callback is fired after the Image component's internal handleImageError method. |
onLoad |
[func|null] |
null |
No |
Callback function called if the image defined by the src property loads successfully. This Callback is fired after the Image component's internal renderSuccess method. |
renderError |
[func|null] |
null |
No |
When defined, if an image fails to load, this function is called. It must return JSX which will be rendered instead of the broken image. |
renderLoading |
[func|null] |
null |
No |
When defined, this function is called while the image is loading. It must return JSX which will be rendered instead of the loading image. |
src |
string |
|
Yes |
URL of the image |
tag |
string |
"img" |
No |
The element that will receive the image. Another option might be to set this to "div". Any tag besides "img" will result in the image being loaded as the css background-image for that tag. |
用于向后移动滑块的按钮。 在水平旋转木马上向后意味着“向左移动”。 在垂直旋转木马上向后意味着“移动到顶部”。 滑块将遍历由 CarouselProvider 的 step 属性确定的幻灯片数量。
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the ButtonBack component needs to wrap other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means ButtonBack will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
<button class="carousel__back-button [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.children]
</button>
用于向前移动滑块的按钮。 水平旋转木马上的前进意味着“向右移动”。 在垂直旋转木马上向后意味着“移至底部”。 滑块将遍历由 CarouselProvider 的 step 属性确定的幻灯片数量。
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the ButtonNext component needs to wrap other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means ButtonNext will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
<button class="carousel__next-button [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.children]
</button>
将滑块移动到幻灯片的开头。
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the ButtonFirst component needs to wrap other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means ButtonFirst will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
<button class="carousel__first-button [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.children]
</button>
将滑块移动到幻灯片的末尾 (totalSlides - visibleSlides)。
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the ButtonLast component needs to wrap other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means ButtonLast will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
<button class="carousel__last-button [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.children]
</button>
按下此按钮会导致幻灯片在 CarouselProvider 的 interval 属性确定的间隔后自动前进 CarouselProvider 的 step 属性。
property |
type |
default |
required |
purpose |
children |
[string|node] |
null |
No |
Children is a special React property. Content wrapped by ButtonPlay will appear AFTER the content of childrenPaused and childrenPlaying |
childrenPaused |
[string|node] |
null |
No |
Content to display when the slide show is paused. |
childrenPlaying |
[string|node] |
null |
No |
Content to display when the slide show is playing |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means ButtonPlay will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
<button class="carousel__play-button [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.childrenPaused]
[props.childrenPlaying]
[props.children]
</button>
WithStore() Higher Order Component
注意:仅限高级用途。
使用此 HOC 将 CarouselProvider 状态属性作为道具传递给组件。 基本上,您的自定义组件必须是
的后代。 它不必是直系后代,它只需要在某处的一些开始和结束 CarouselProvider 标签之间。 例如……
// pseudocode example
<CarouselProvider>
<YourComponentHere />
</CarouselProvider>
WithStore 有两个参数:
WithStore([component], [mapstateToProps])
第一个参数是要包装的组件(例如:YourComponentHere),它是必需的。
第二个参数是可选的。 这是您必须创建的“将状态映射到道具”功能。 此函数将 CarouselProvider 的状态映射到您的组件使用的道具。 您的“将状态映射到道具”函数将接收一个参数:一个具有当前 CarouselProvider 状态的对象。 您的函数必须返回一个对象,其中的键是要传递给您的组件的 props 名称,值映射到 CarouselProvider 状态的属性。
这是更多的伪代码。 我列出了 CarouselProvider 中存在的一系列属性。
import React from 'react';
import { WithStore } from 'pure-react-carousel';
class YourComponentHere extends React.Component {
// ... stuff
}
export default WithStore(YourComponentHere, state => ({
// these are read only properties. we use the "deepFreeze"
// npm package to make these properties immutable. You don't have to use
// all of these, just pick the ones you need.
currentSlide: state.currentSlide,
disableAnimation: state.disableAnimation,
hasMasterSpinner: state.hasMasterSpinner,
imageErrorCount: state.imageErrorCount,
imageSuccessCount: state.imageSuccessCount,
lockOnWindowScroll: state.lockOnWindowScroll,
masterSpinnerThreshold: state.masterSpinnerThreshold,
naturalSlideHeight: state.naturalSlideHeight,
naturalSlideWidth: state.naturalSlideWidth,
orientation: state.orientation,
slideSize: state.slideSize,
slideTraySize: state.slideTraySize,
step: state.step,
dragStep: state.dragStep,
totalSlides: state.totalSlides,
touchEnabled: state.touchEnabled,
dragEnabled: state.dragEnabled,
visibleSlides: state.visibleSlides,
}));
任何使用 WithStore 包装的组件也会收到一个名为 carouselStore
的道具,其中包含方法 setStoreState,您可以使用该方法“安全地”(使用风险自负)改变 CarouselProvider 的状态。 carouselStore 中还有其他方法。 不要使用它们。
setStoreState: ??? ??? 使用它来改变上面 WithStore 示例中列出的任何属性。 例如,如果您想跳到幻灯片 2,您可以将 this.props.carouselStore.setStoreState({ currentSlide: 2 })
放在组件的类方法中。
更多伪代码。
import React from 'react';
import { WithStore } from 'pure-react-carousel';
class YourComponentHere extends React.Component {
// ... stuff
handleClick() {
this.props.carouselStore.setStoreState({ currentSlide: 2 });
}
}
export default WithStore(YourComponentHere);
有趣的事实:您可以向 CarouselProvider 的状态添加任何您想要的任意值。 因此,如果您有多个需要共享数据的自定义组件,那就试试吧。
masterSpinnerError: 不要使用这个。
masterSpinnerSuccess:⚠️ 不要使用它。
subscribeMasterSpinner: 不要使用这个。
取消订阅MasterSpinner: 不要使用这个。
unsubscribeAllMasterSpinner:除非您有某种超级定制的旋转木马,否则不要手动调用它。 一旦所有
和所有
组件完成加载它们的图像,就会在内部调用此方法。 直接调用它会强制进入“成功”状态,主微调器(加载时覆盖整个轮播的微调器)将关闭。
Hooks and useContext
如果您想通过挂钩而不是使用上述 HoC 方法来使用上下文,则上下文将导出为 CarouselContext
。
请注意,您可能需要订阅/取消订阅更改才能利用上下文。
示例:
import React, { useContext, useEffect, useState } from 'react';
import { CarouselContext } from 'pure-react-carousel';
export function MyComponentUsingContext() {
const carouselContext = useContext(CarouselContext);
const [currentSlide, setCurrentSlide] = useState(carouselContext.state.currentSlide);
useEffect(() => {
function onChange() {
setCurrentSlide(carouselContext.state.currentSlide);
}
carouselContext.subscribe(onChange);
return () => carouselContext.unsubscribe(onChange);
}, [carouselContext]);
return `The current slide is: ${currentSlide}`;
}
TypeScript usage
当前捆绑的 Typescript 定义大部分是完整的。 某些边缘情况可能没有被考虑在内! 欢迎并赞赏改进它们的拉取请求。
如果您以前从未为开源做出过贡献,那么您可能会发现 这个免费视频课程很有帮助。
对于提供的组件,它非常简单。 只需导入它们并传递必要的道具。 目前,类型不会阻止您错误地使用该库(例如在 CarouselProvider 之外渲染 Slider),因此如果出现问题,请检查文档。
WithStore() Higher Order Component
按照上面的文档,只公开了可以安全使用的道具:
interface CarouselState {
readonly currentSlide: number
readonly disableAnimation: boolean
readonly disableKeyboard: boolean
readonly hasMasterSpinner: boolean
readonly imageErrorCount: number
readonly imageSuccessCount: number
readonly lockOnWindowScroll: boolean
readonly masterSpinnerThreshold: number
readonly naturalSlideHeight: number
readonly naturalSlideWidth: number
readonly orientation: 'horizontal' | 'vertical'
readonly slideSize: number
readonly slideTraySize: number
readonly step: number
readonly dragStep: number
readonly totalSlides: number
readonly touchEnabled: boolean
readonly dragEnabled: boolean
readonly visibleSlides: number
}
export interface CarouselInjectedProps {
readonly carouselStore: {
readonly setStoreState: (state: CarouselState) => void
readonly unsubscribeAllMasterSpinner: () => void
}
}
也是要包装的组件的第一个参数,需要是 React.ComponentClass
才能正确呈现,因此无状态组件不是可能。
Examples:
- Both with MapStateToProps and custom props
import {
CarouselInjectedProps,
WithStore,
} from 'pure-react-carousel'
interface UpdateCheckProps extends CarouselInjectedProps {
readonly name: string,
}
interface UpdateCheckCarouselState {
readonly currentSlide: number,
readonly disableAnimation: boolean,
}
class InjectedComponent extends Component<
UpdateCheckProps & UpdateCheckCarouselState
> {
public render() {
console.log(this.props)
return <div>I am a fancy class</div>
}
}
const DecoratedComponent = WithStore<UpdateCheckProps, UpdateCheckCarouselState>(
InjectedComponent,
state => ({
currentSlide: state.currentSlide,
disableAnimation: state.disableAnimation,
}),
)
<CarouselProvider>
<DecoratedComponent name="NewName" />
</CarouselProvider>
interface UpdateCheckProps extends CarouselInjectedProps {
readonly name: string,
}
class InjectedComponent extends Component<UpdateCheckProps> {
public render() {
console.log(this.props)
return <div>I am a fancy class</div>
}
}
const DecoratedComponent = WithStore<UpdateCheckProps>(InjectedComponent)
// This will work too, with or without custom props
const DecoratedComponent = WithStore(InjectedComponent)
More Documentation to Come
我保证为每个组件添加文档。 同时,请随时下载并运行演示应用程序。 查看代码可能会对您有所帮助。
Dev Workflow
npm start
starts a local development server, opens the dev page with your default browser, and watches for changes via livereload
npm run build
compiles commonjs and ES modules and places them in the dist directory
npm test
runs unit and integration tests using Jest + Enzyme. Also does coverage reporting.
npm lint
runs linting tests using eslint & airbnb linting.
npm test:watch
same as npm test
but it will watch for updates and auto-run tests. Does not do coverage reporting.
Contributors
感谢这些优秀的人 (emoji key):
这个项目遵循 all-contributors 规范。 欢迎任何形式的贡献!
Pure React Carousel
Created By
A highly impartial suite of React components that can be assembled by the consumer to create a responsive and aria compliant carousel with almost no limits on DOM structure or CSS styles.
[**See Live Examples**](https://express-labs.github.io/pure-react-carousel/) |
[See Example Code](src/App/examples)
Motivation
My goal was to create a 100% ReactJS carousel that doesn't try to impose structure or styles that need to be defeated in order to match your site's design standards. Are you tired of fighting some other developer's CSS or DOM structure? If so, this carousel is for you.
Carousels: Love them or hate them. However, if you are a React developer, and you have to use a carousel, why not use one that was…
- Developed from the ground-up in React.
- Is not a wrapper or port of some non-react carousel like Slick or Flickity.
- Fully supports touch events.
- Is aria compliant.
- Is responsive by default.
- Lets you assemble the carousel components in the DOM in any order you desire so long as they are all children of a single <CarouselProvider /> component.
- Lets you put any class names, properties, attributes, or styles on any of the components that you need.
- Supports ES6 and commonjs.
- Has 100% test coverage. Solid!
Table of contents
???? Tutorial
Let's make a simple carousel with three slides, a next button, and a back button.
Add the module to your project.
npm i -S pure-react-carousel
Import only the required components into your project.
import React from 'react';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
- Using Webpack or Rollup? Does your Webpack config have a loader for "css" files? If so, import the css as well.
import React from 'react';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
import 'pure-react-carousel/dist/react-carousel.es.css';
- Put a CarouselProvider component in your code. This allows the other carousel components to communicate with each other. The only required properties are the orientation, naturalSlideWidth, and naturalSlideHeight. The naturalSlideWidth and naturalSlideHeight are used to create an aspect ratio for each slide. Since the carousel is responsive by default, it will stretch to fill in the width of it's parent container. The CarouselProvider must also have children. We'll add the children in the next step.
import React from 'react';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
import 'pure-react-carousel/dist/react-carousel.es.css';
export default class extends React.Component {
render() {
return (
<CarouselProvider
naturalSlideWidth={100}
naturalSlideHeight={125}
totalSlides={3}
></CarouselProvider>
);
}
}
- Place the components in any order you wish as long as they are children of a single CarouselProvider component. Some components have ancestor/descendant relationships but they don't have to be direct relatives. For example: Slides need to go inside of a Slider. Slides also require a sequentially numbered index prop starting at zero. Chances are, a lot of the time, you're going to be populating the slides from data and looping through the data, so it would be easy to add an index in your loop.
import React from 'react';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
import 'pure-react-carousel/dist/react-carousel.es.css';
export default class extends React.Component {
render() {
return (
<CarouselProvider
naturalSlideWidth={100}
naturalSlideHeight={125}
totalSlides={3}
>
<Slider>
<Slide index={0}>I am the first Slide.</Slide>
<Slide index={1}>I am the second Slide.</Slide>
<Slide index={2}>I am the third Slide.</Slide>
</Slider>
</CarouselProvider>
);
}
}
- Add some buttons so the user can navigate forward and backwards.
import React from 'react';
import { CarouselProvider, Slider, Slide, ButtonBack, ButtonNext } from 'pure-react-carousel';
import 'pure-react-carousel/dist/react-carousel.es.css';
export default class extends React.Component {
render() {
return (
<CarouselProvider
naturalSlideWidth={100}
naturalSlideHeight={125}
totalSlides={3}
>
<Slider>
<Slide index={0}>I am the first Slide.</Slide>
<Slide index={1}>I am the second Slide.</Slide>
<Slide index={2}>I am the third Slide.</Slide>
</Slider>
<ButtonBack>Back</ButtonBack>
<ButtonNext>Next</ButtonNext>
</CarouselProvider>
);
}
}
That's it. You have a super basic Carousel.
There are other components you can add, like ButtonFirst, ButtonLast, an Image component, and even an ImageWithZoom component that zooms on mouse hover or finger tap.
Obviously, you can customize the heck out of the layout. If you need to bury your Slider component in 18 parent divs, go for it. It will still do it's job. Feel free to add the className property to any of the Components to further customize your carousel. Or, hook into the many BEM named default CSS class names built into the carousel components.
Some components have a ancestor / descendant relationship but they don't have to be direct descendants of the parent. For example, Slide needs to be a descendant of Slider, but you can put a bunch of div wrappers around slide if you need to. A good analogy are the html tags table
and tr
. The tr
tag needs to be a descendant of table
, but it doesn't have to be a direct descendant. You can have a tbody
between them in the tree.
Component Properties (props)
classname
You can attach your own className property to each and every component in this library and it will be appended to the list of classes. It's appended so that it has more specificity in a tie, allowing your CSS to more easily override any internal styles without resorting to using !important.
styles
You can attach your own styles property to each component in this library, however, any styles generated by the component take precedence over any styles you provide. Some components, like the <Slider />
, need their internal styles to function correctly.
event props (onClick, onFocus, onBlur, etc)
You can supply your own event callbacks to any component. Your event callbacks are called after a component's internal event handling. Basically, your callback becomes a callback to our callback. Say that 10 times fast. :-)
all other props
Any remaining props not consumed by the component are passed directly to the root element of a component unless otherwise noted in that component's documentation. This makes all the components in this library HIGHLY configurable. You can, for example, add your own event handlers, or change aria tags, etc.
Components
<CarouselProvider />
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the CarouselProvider needs to wrap other Carousel components and JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string |
currentSlide |
number |
0 |
No |
<Slide > to display ONLY when CarouselProvider mounts. The indexing of <Slide /> components starts with 0. This is a poorly named variable and will be deprecated in a future version. |
hasMasterSpinner |
bool |
false |
No |
When true, a spinner will cover <Slider /> component until all <Image > and <ImageWithZoom > are done loading images. If there are no <Image /> or <ImageWithZoom> components, the spinner will spin until this property is set to false |
interval |
number |
5000 |
No |
Number of milliseconds to wait when the auto slideshow is active |
isPlaying |
bool |
false |
No |
Setting this to true starts an auto slideshow. After "interval" milliseconds, the slider will move by "step" slides either forward or backwards depending on the value of "playDirection". |
lockOnWindowScroll |
bool |
false |
No |
When set to true, scrolling of the carousel slides are disabled while the browser window is scrolling |
naturalSlideHeight |
number |
|
Yes |
The natural height of each <\Slide > component. ** |
naturalSlideWidth |
number |
|
Yes |
The natural width of each <\Slide > component. ** |
orientation |
string |
"horizontal" |
No |
Possible values are "horizontal" and "vertical". Let's you have a horizontal or vertical carousel. |
playDirection |
['forward'|'backward' ] |
'forward' |
No |
The direction for the auto slideshow |
step |
number |
1 |
No |
The number of slides to move when pressing the <ButtonBack /> and <ButtonNext /> buttons. |
dragStep |
number |
1 |
No |
The number of slides to move when performing a short touch drag. |
tag |
string |
'div' |
No |
The HTML element to use for the provider. |
totalSlides |
number |
|
Yes |
Always set this to match the total number of <Slide > components in your carousel |
touchEnabled |
boolean |
true |
No |
Set to true to enable touch events |
dragEnabled |
boolean |
true |
No |
Set to true to enable mouse dragging events |
visibleSlides |
number |
1 |
No |
The number of slides to show at once. This number should be <= totalSlides |
infinite |
boolean |
false |
No |
Should the carousel continue or stop at the beginning or end of the slides |
isIntrinsicHeight |
boolean |
false |
No |
Disables the enforced height ratio, and instead uses the intrinsic height of the slides. This option can only be active in horizontal orientation, it will throw an error in vertical orientation. |
The CarouselProvider component creates the following pseudo HTML by default:
<props.tag|div class="carousel [props.className]" ...props>
[props.children]
</props.tag|div>
More about naturalSlideWidth and naturalSlideHeight
The carousel is responsive and by default will flex to the full width of the parent container. It's up to you to contain the carousel width via css. Each slide will be the same height to width ratio (intrinsic ratio). CarouselProvider needs to know the default size of each <Slide />. Note: you can make the carousel non-responsive by setting the width of to a fixed css unit, like pixels. There are many other ways to make the carousel non-responsive.
<Slider />
A Slider is a viewport that masks slides. The Slider component must wrap one or more Slide components.
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the Slider needs to wrap other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
classNameAnimation |
[string|null] |
null |
No |
Optional className string. The slider uses the css transform property, applying translateX to move the slider tray east and west for a horizontal slider, and translateY to move the slider north and south for a vertical slider. The actual animation is the result of applying a CSS3 transition effect. If you supply your own classNameAnimation class, the default transition is disabled and ONLY the transitions specified by the classNameAnimation class are applied. Learn more about CSS3 transitions. |
classNameTray |
[string|null] |
null |
No |
Optional className string that is applied to the Slider's tray. The "tray" is the DOM element that contains the slides. The type of DOM element is specified by the trayTag property |
classNameTrayWrap |
[string|null] |
null |
No |
Optional className string that is applied to a div that surrounds the Slider's tray |
moveThreshold |
number |
0.1 |
No |
Threshold to control the drag distance that triggers a scroll to the next or previous slide. (slide width or height * moveThreshold = drag pixel distance required to scroll) |
onMasterSpinner |
[function|null] |
null |
No |
Optional callback function that is called when the Master Spinner is visible. Requires that <CarouselProvider /> set hasMasterSpinner to true |
spinner |
function |
null |
No |
Optional inline JSX (aka "render props") to render your own custom spinner. Example () => <MyCustomSpinnerComponent /> If left blank, the default spinner is used. |
style |
object |
{} |
No |
Optional css styles to add to the Slider. Note: internal css properties take precedence over any styles specified in the styles object |
trayProps |
object |
{} |
No |
Any props you want to attach to the slider tray with the exception of className and style. The className prop is handled via classNameTray prop above. Style is used internally. Any event handlers like onMouseDown or others are called after any of our internal event handlers. |
trayTag |
string |
'ul' |
No |
The HTML tag to used for the tray (the thing that holds all the slides and moves the slides back and forth.) |
The Slider component creates the following pseudo HTML by default.
<div class="carousel__slider [carousel__slider--vertical|carousel__slider--horizontal] [props.className]" aria-live="polite" style="[props.style]" ...props>
<div class="carousel__slider-tray-wrapper [carousel__slider-tray-wrap--vertical|carousel__slider-tray-wrap--horizontal][props.classNameTrayWrap]">
<props.trayTag|ul class="carousel__slider-tray [props.classNameAnimation] [carousel__slider-tray--vertical|carousel__slider-tray--horizontal] [props.classNameTray]">
[props.children]
</props.trayTag|ul>
<div class="carousel__master-spinner-container">
<div class="carousel__spinner" />
</div>
</div>
</div>
How to Change the Default Transition Animation
- Read the documentation for the classNameAnimation property on the Slider component.
- Read about CSS3 transitions.
- Create your own CSS class that uses a CSS3 transition.
- Pass the CSS class you create to the classNameAnimation property of Slider.
<Slide />
The Slide component is a container with an intrinsic ratio computed by the CarouselProvider naturalSlideWidth and naturalSlideHeight properties. By default, only one slide is visible in the Slider at a time. You can change this by altering the visibleSlides property of the CarouselProvider. Slide components also contain a div that acts as an aria compliant focus ring when the Slide receives focus either by using a keyboard tab, mouse click, or touch.
property |
type |
default |
required |
purpose |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
classNameHidden |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string when the slide is not visible. |
classNameVisible |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string when the slide is visible. |
index |
number |
|
Yes |
You must consecutively number the <Slide > components in order starting with zero. |
innerClassName |
[string|null] |
null |
No |
Optional className string that will be appended to an internal HTML element created by the Component. Best to just use Chrome Dev Tools to inspect the demo app or check the source code for <Slide /> |
innerTag |
string |
'div' |
No |
The inner HTML element for each Slide. |
onBlur |
[function|null] |
null |
No |
Optional callback function that is called after the internal onBlur function is called. It is passed the React synthetic event |
onFocus |
[function|null] |
null |
No |
Optional callback function that is called after the internal onFocus function is called. It is passed the React synthetic event |
tabIndex |
[number|null] |
null |
No |
When null, the Carousel will set this automatically. 99.9% of the time, you're going to want to leave this alone and let the carousel handle tabIndex automatically. |
tag |
string |
'li' |
No |
The root HTML element for each Slide. |
The Slide component creates the following pseudo HTML by default:
<props.tag|li class="carousel__slide [carousel__slide--focused] [props.className] [props.classNameVisible|props.classNameHidden] [carousel__slide--hidden|carousel__slide--visible]" tabIndex="[props.tabIndex]" aria-hidden="[computed internally]" onFocus="[props.onFocus]" onBlur="[props.onBlur]" style="[props.style]" ...props>
<props.innerTag|div class="carousel__inner-slide [props.innerClassName]">
[props.children]
<div class="carousel__slide-focus-ring" />
<props.innerTag|div>
</props.tag|li>
<Dot />
A Dot component is a HTML button. Dots directly correlate to slides. Clicking on a dot causes it's correlating slide to scroll into the left-most visible slot of slider. The dots for currently visible slides cause are disabled. You can override the auto-disable feature by setting disabled to false (see table below)
property |
type |
default |
required |
purpose |
children |
[string|null|node] |
null |
No |
Children is a special React property. Basically, the Dot component wraps other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means Dot will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
slide |
number |
|
Yes |
There must be a matching <Slide /> component with a matching index property. Example: <Dot slide={0} /> will match <Slide index={0} /> |
The Dot component creates the following pseudo HTML by default:
<button class="carousel__dot carousel__dot--[slide] [carousel__dot--selected] [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.children]
</button>
<DotGroup />
A compound component that creates a bunch of Dot's automatically for you.
property |
type |
default |
required |
purpose |
children |
[string|node|null] |
null |
No |
Any JSX wrapped by this component will appear AFTER the dots. |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
dotNumbers |
boolean |
false |
No |
Setting to true automatically adds text numbers the dot buttons starting at 1. |
disableActiveDots |
boolean |
true |
No |
Setting to true make all dots, including active dots, enabled. |
showAsSelectedForCurrentSlideOnly |
boolean |
false |
No |
Setting to true show only the current slide dot as selected. |
renderDots |
function |
null |
No |
It accepts props and overrides renderDots() in . |
The DotGroup component creates the following pseudo HTML by default:
<div class="carousel__dot-group [props.className]" ...props>
<!-- button repeats for each slide -->
<button class="carousel__dot carousel__dot--[slide] [carousel__dot--selected]">
[numbers or blank]
</button>
[props.children]
</div>
<Image />
property |
type |
default |
required |
purpose |
alt |
string |
"" |
No |
Specifies an alternate text for an image, if the image cannot be displayed. |
children |
[string|node|null] |
null |
Yes |
Any optional JSX wrapped by the Image component |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
hasMasterSpinner |
bool |
|
Yes |
**If set to true, a spinner will cover the entire slider viewport until all Image components with hasMasterSpinner set to true are finished loading images. It only takes one Image component with hasMasterSpinner to enable the master spinner. ** |
isBgImage |
bool |
false |
No |
Setting this to true makes the image load as a background image. Any child JSX (see children property) will appear on top of the image. If set to false, no image will appear unless your child JSX displays the image via an image tag or some other means. |
onError |
[func|null] |
null |
No |
Callback function called if the image defined by the src property fails to load. This Callback is fired after the Image component's internal handleImageError method. |
onLoad |
[func|null] |
null |
No |
Callback function called if the image defined by the src property loads successfully. This Callback is fired after the Image component's internal renderSuccess method. |
renderError |
[func|null] |
null |
No |
When defined, if an image fails to load, this function is called. It must return JSX which will be rendered instead of the broken image. |
renderLoading |
[func|null] |
null |
No |
When defined, this function is called while the image is loading. It must return JSX which will be rendered instead of the loading image. |
src |
string |
|
Yes |
URL of the image |
tag |
string |
"img" |
No |
The element that will receive the image. Another option might be to set this to "div". Any tag besides "img" will result in the image being loaded as the css background-image for that tag. |
A button for moving the slider backwards. Backwards on a horizontal carousel means "move to the left". Backwards on a vertical carousel means "move to the top". The slider will traverse an amount of slides determined by the step property of CarouselProvider.
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the ButtonBack component needs to wrap other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means ButtonBack will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
<button class="carousel__back-button [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.children]
</button>
A button for moving the slider forwards. Forwards on a horizontal carousel means "move to the right". Backwards on a vertical carousel means "move to the bottom". The slider will traverse an amount of slides determined by the step property of CarouselProvider.
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the ButtonNext component needs to wrap other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means ButtonNext will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
<button class="carousel__next-button [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.children]
</button>
Moves the slider to the beginning of the slides.
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the ButtonFirst component needs to wrap other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means ButtonFirst will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
<button class="carousel__first-button [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.children]
</button>
Moves the slider to the end of the slides (totalSlides - visibleSlides).
property |
type |
default |
required |
purpose |
children |
[string|node] |
|
Yes |
Children is a special React property. Basically, the ButtonLast component needs to wrap other components and/or JSX |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means ButtonLast will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
<button class="carousel__last-button [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.children]
</button>
Pressing this button causes the slides to automatically advance by CarouselProvider's step property after an interval determined by CarouselProvider's interval property.
property |
type |
default |
required |
purpose |
children |
[string|node] |
null |
No |
Children is a special React property. Content wrapped by ButtonPlay will appear AFTER the content of childrenPaused and childrenPlaying |
childrenPaused |
[string|node] |
null |
No |
Content to display when the slide show is paused. |
childrenPlaying |
[string|node] |
null |
No |
Content to display when the slide show is playing |
className |
[string|null] |
null |
No |
Optional className string that will be appended to the component's className string. |
disabled |
[boolean|null] |
null |
No |
Null means ButtonPlay will automatically determine if this button is disabled. Setting this to true will force the button to be disabled. Setting this to false will prevent the button from ever being disabled. |
onClick |
[function|null] |
null |
No |
Optional callback function that is called after the internal onClick function is called. It is passed the React synthetic event |
<button class="carousel__play-button [props.className]" onClick="[props.onClick]" disabled="[props.disabled]" ...props>
[props.childrenPaused]
[props.childrenPlaying]
[props.children]
</button>
WithStore() Higher Order Component
NOTE: ADVANCED USE ONLY.
Use this HOC to pass CarouselProvider state properties as props to a component. Basically, Your custom component must be an descendant of <CarouselProvider>
. It doesn't have to be a direct descendant, it just needs to be between some the opening and closing CarouselProvider tags somewhere. For example…
// pseudocode example
<CarouselProvider>
<YourComponentHere />
</CarouselProvider>
WithStore has two arguments:
WithStore([component], [mapstateToProps])
The first argument is the component to wrap (ex: YourComponentHere) and it's required.
The second argument is optional. It is a "map state to props" function that you must create. This function maps the state of the CarouselProvider to props used by your component. Your "map state to props" function will receive one argument: an object with the current CarouselProvider state. Your function must return an object where the keys are names of props to pass to your component and the values map to properties of the CarouselProvider's state.
Here's more pseudocode. I've listed a bunch of properties that exist in the CarouselProvider.
import React from 'react';
import { WithStore } from 'pure-react-carousel';
class YourComponentHere extends React.Component {
// ... stuff
}
export default WithStore(YourComponentHere, state => ({
// these are read only properties. we use the "deepFreeze"
// npm package to make these properties immutable. You don't have to use
// all of these, just pick the ones you need.
currentSlide: state.currentSlide,
disableAnimation: state.disableAnimation,
hasMasterSpinner: state.hasMasterSpinner,
imageErrorCount: state.imageErrorCount,
imageSuccessCount: state.imageSuccessCount,
lockOnWindowScroll: state.lockOnWindowScroll,
masterSpinnerThreshold: state.masterSpinnerThreshold,
naturalSlideHeight: state.naturalSlideHeight,
naturalSlideWidth: state.naturalSlideWidth,
orientation: state.orientation,
slideSize: state.slideSize,
slideTraySize: state.slideTraySize,
step: state.step,
dragStep: state.dragStep,
totalSlides: state.totalSlides,
touchEnabled: state.touchEnabled,
dragEnabled: state.dragEnabled,
visibleSlides: state.visibleSlides,
}));
Any component wrapped with WithStore will also receive a prop called carouselStore
which contains the method setStoreState which you can use to "safely" (use at your own risk) mutate the CarouselProvider's state. There are other methods in carouselStore. Don't use them.
setStoreState: ???? ???? ???? Use this to mutate any of the properties listed in the WithStore example above. For example, if you want to skip to slide 2 you can put this.props.carouselStore.setStoreState({ currentSlide: 2 })
inside a class method in your component.
More pseudocode.
import React from 'react';
import { WithStore } from 'pure-react-carousel';
class YourComponentHere extends React.Component {
// ... stuff
handleClick() {
this.props.carouselStore.setStoreState({ currentSlide: 2 });
}
}
export default WithStore(YourComponentHere);
Fun fact: you can add any arbitrary values that you want to the CarouselProvider's state. So, if you have several custom components that need to share data, have at it.
masterSpinnerError: ???? DON'T USE THIS.
masterSpinnerSuccess: ⚠️ DON'T USE THIS.
subscribeMasterSpinner: ???? DON'T USE THIS.
unsubscribeMasterSpinner: ???? DON'T USE THIS.
unsubscribeAllMasterSpinner: Don't call this manually unless you have some sort of super-customized carousel. This is called internally once all <Image hasMasterSpinner />
and all <ImageWithZoom hasMasterSpinner />
components are finished loading their images. Calling this directly will force a "success" state and the master spinner (the spinner that covers the entire carousel while loading) will turn off.
Hooks and useContext
If you'd like to consume the context via hooks rather than using the HoC approach described above, the context is exported as CarouselContext
.
Note that you will likely need to subscribe/unsubscribe to changes in order to take advantage of the context.
Example:
import React, { useContext, useEffect, useState } from 'react';
import { CarouselContext } from 'pure-react-carousel';
export function MyComponentUsingContext() {
const carouselContext = useContext(CarouselContext);
const [currentSlide, setCurrentSlide] = useState(carouselContext.state.currentSlide);
useEffect(() => {
function onChange() {
setCurrentSlide(carouselContext.state.currentSlide);
}
carouselContext.subscribe(onChange);
return () => carouselContext.unsubscribe(onChange);
}, [carouselContext]);
return `The current slide is: ${currentSlide}`;
}
TypeScript usage
The current bundled Typescript definitions are mostly complete. Certain edge case could have been not accounted for! Pull requests to improve them are welcome and appreciated.
If you've never contributed to open source before, then you may find this free video course helpful.
In case of provided components, it is pretty straightforward. Simply import them and pass necessary props. At the moment types will not prevent you from using the library incorrectly (for example rendering Slider outside CarouselProvider) therefore please check the documentation if something goes wrong.
WithStore() Higher Order Component
Following the documentation above, only props safe to use are exposed:
interface CarouselState {
readonly currentSlide: number
readonly disableAnimation: boolean
readonly disableKeyboard: boolean
readonly hasMasterSpinner: boolean
readonly imageErrorCount: number
readonly imageSuccessCount: number
readonly lockOnWindowScroll: boolean
readonly masterSpinnerThreshold: number
readonly naturalSlideHeight: number
readonly naturalSlideWidth: number
readonly orientation: 'horizontal' | 'vertical'
readonly slideSize: number
readonly slideTraySize: number
readonly step: number
readonly dragStep: number
readonly totalSlides: number
readonly touchEnabled: boolean
readonly dragEnabled: boolean
readonly visibleSlides: number
}
export interface CarouselInjectedProps {
readonly carouselStore: {
readonly setStoreState: (state: CarouselState) => void
readonly unsubscribeAllMasterSpinner: () => void
}
}
Also the first argument which is the component to wrap, needs to be a React.ComponentClass
to render properly and therefore stateless component are not possible.
Examples:
- Both with MapStateToProps and custom props
import {
CarouselInjectedProps,
WithStore,
} from 'pure-react-carousel'
interface UpdateCheckProps extends CarouselInjectedProps {
readonly name: string,
}
interface UpdateCheckCarouselState {
readonly currentSlide: number,
readonly disableAnimation: boolean,
}
class InjectedComponent extends Component<
UpdateCheckProps & UpdateCheckCarouselState
> {
public render() {
console.log(this.props)
return <div>I am a fancy class</div>
}
}
const DecoratedComponent = WithStore<UpdateCheckProps, UpdateCheckCarouselState>(
InjectedComponent,
state => ({
currentSlide: state.currentSlide,
disableAnimation: state.disableAnimation,
}),
)
<CarouselProvider>
<DecoratedComponent name="NewName" />
</CarouselProvider>
interface UpdateCheckProps extends CarouselInjectedProps {
readonly name: string,
}
class InjectedComponent extends Component<UpdateCheckProps> {
public render() {
console.log(this.props)
return <div>I am a fancy class</div>
}
}
const DecoratedComponent = WithStore<UpdateCheckProps>(InjectedComponent)
// This will work too, with or without custom props
const DecoratedComponent = WithStore(InjectedComponent)
More Documentation to Come
I promise to add docs for every component. In the meantime, feel free to download and run the demo app. Looking at the code might help you out.
Dev Workflow
npm start
starts a local development server, opens the dev page with your default browser, and watches for changes via livereload
npm run build
compiles commonjs and ES modules and places them in the dist directory
npm test
runs unit and integration tests using Jest + Enzyme. Also does coverage reporting.
npm lint
runs linting tests using eslint & airbnb linting.
npm test:watch
same as npm test
but it will watch for updates and auto-run tests. Does not do coverage reporting.
Contributors
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!