UNPKG

13.1 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
4
5var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
6
7exports.__esModule = true;
8exports.default = void 0;
9
10var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
11
12var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
13
14var _useEventCallback = _interopRequireDefault(require("@restart/hooks/useEventCallback"));
15
16var _useUpdateEffect = _interopRequireDefault(require("@restart/hooks/useUpdateEffect"));
17
18var _useTimeout = _interopRequireDefault(require("@restart/hooks/useTimeout"));
19
20var _classnames = _interopRequireDefault(require("classnames"));
21
22var _transitionEnd = _interopRequireDefault(require("dom-helpers/transitionEnd"));
23
24var _Transition = _interopRequireDefault(require("react-transition-group/Transition"));
25
26var _react = _interopRequireWildcard(require("react"));
27
28var _uncontrollable = require("uncontrollable");
29
30var _CarouselCaption = _interopRequireDefault(require("./CarouselCaption"));
31
32var _CarouselItem = _interopRequireDefault(require("./CarouselItem"));
33
34var _ElementChildren = require("./ElementChildren");
35
36var _SafeAnchor = _interopRequireDefault(require("./SafeAnchor"));
37
38var _ThemeProvider = require("./ThemeProvider");
39
40var _triggerBrowserReflow = _interopRequireDefault(require("./triggerBrowserReflow"));
41
42var SWIPE_THRESHOLD = 40;
43var defaultProps = {
44 slide: true,
45 fade: false,
46 controls: true,
47 indicators: true,
48 defaultActiveIndex: 0,
49 interval: 5000,
50 keyboard: true,
51 pause: 'hover',
52 wrap: true,
53 touch: true,
54 prevIcon: _react.default.createElement("span", {
55 "aria-hidden": "true",
56 className: "carousel-control-prev-icon"
57 }),
58 prevLabel: 'Previous',
59 nextIcon: _react.default.createElement("span", {
60 "aria-hidden": "true",
61 className: "carousel-control-next-icon"
62 }),
63 nextLabel: 'Next'
64};
65
66function isVisible(element) {
67 if (!element || !element.style || !element.parentNode || !element.parentNode.style) {
68 return false;
69 }
70
71 var elementStyle = getComputedStyle(element);
72 return elementStyle.display !== 'none' && elementStyle.visibility !== 'hidden' && getComputedStyle(element.parentNode).display !== 'none';
73}
74
75var Carousel = _react.default.forwardRef(function (uncontrolledProps, ref) {
76 var _useUncontrolled = (0, _uncontrollable.useUncontrolled)(uncontrolledProps, {
77 activeIndex: 'onSelect'
78 }),
79 _useUncontrolled$as = _useUncontrolled.as,
80 Component = _useUncontrolled$as === void 0 ? 'div' : _useUncontrolled$as,
81 bsPrefix = _useUncontrolled.bsPrefix,
82 slide = _useUncontrolled.slide,
83 fade = _useUncontrolled.fade,
84 controls = _useUncontrolled.controls,
85 indicators = _useUncontrolled.indicators,
86 activeIndex = _useUncontrolled.activeIndex,
87 onSelect = _useUncontrolled.onSelect,
88 onSlide = _useUncontrolled.onSlide,
89 onSlid = _useUncontrolled.onSlid,
90 interval = _useUncontrolled.interval,
91 keyboard = _useUncontrolled.keyboard,
92 onKeyDown = _useUncontrolled.onKeyDown,
93 pause = _useUncontrolled.pause,
94 onMouseOver = _useUncontrolled.onMouseOver,
95 onMouseOut = _useUncontrolled.onMouseOut,
96 wrap = _useUncontrolled.wrap,
97 touch = _useUncontrolled.touch,
98 onTouchStart = _useUncontrolled.onTouchStart,
99 onTouchMove = _useUncontrolled.onTouchMove,
100 onTouchEnd = _useUncontrolled.onTouchEnd,
101 prevIcon = _useUncontrolled.prevIcon,
102 prevLabel = _useUncontrolled.prevLabel,
103 nextIcon = _useUncontrolled.nextIcon,
104 nextLabel = _useUncontrolled.nextLabel,
105 className = _useUncontrolled.className,
106 children = _useUncontrolled.children,
107 props = (0, _objectWithoutPropertiesLoose2.default)(_useUncontrolled, ["as", "bsPrefix", "slide", "fade", "controls", "indicators", "activeIndex", "onSelect", "onSlide", "onSlid", "interval", "keyboard", "onKeyDown", "pause", "onMouseOver", "onMouseOut", "wrap", "touch", "onTouchStart", "onTouchMove", "onTouchEnd", "prevIcon", "prevLabel", "nextIcon", "nextLabel", "className", "children"]);
108
109 var prefix = (0, _ThemeProvider.useBootstrapPrefix)(bsPrefix, 'carousel');
110 var nextDirectionRef = (0, _react.useRef)(null);
111
112 var _useState = (0, _react.useState)('next'),
113 direction = _useState[0],
114 setDirection = _useState[1];
115
116 var _useState2 = (0, _react.useState)(false),
117 isSliding = _useState2[0],
118 setIsSliding = _useState2[1];
119
120 var _useState3 = (0, _react.useState)(activeIndex),
121 renderedActiveIndex = _useState3[0],
122 setRenderedActiveIndex = _useState3[1];
123
124 if (!isSliding && activeIndex !== renderedActiveIndex) {
125 if (nextDirectionRef.current) {
126 setDirection(nextDirectionRef.current);
127 nextDirectionRef.current = null;
128 } else {
129 setDirection(activeIndex > renderedActiveIndex ? 'next' : 'prev');
130 }
131
132 if (slide) {
133 setIsSliding(true);
134 }
135
136 setRenderedActiveIndex(activeIndex);
137 }
138
139 var numChildren = _react.default.Children.toArray(children).filter(_react.default.isValidElement).length;
140
141 var prev = (0, _react.useCallback)(function (event) {
142 if (isSliding) {
143 return;
144 }
145
146 var nextActiveIndex = renderedActiveIndex - 1;
147
148 if (nextActiveIndex < 0) {
149 if (!wrap) {
150 return;
151 }
152
153 nextActiveIndex = numChildren - 1;
154 }
155
156 nextDirectionRef.current = 'prev';
157 onSelect(nextActiveIndex, event);
158 }, [isSliding, renderedActiveIndex, onSelect, wrap, numChildren]); // This is used in the setInterval, so it should not invalidate.
159
160 var next = (0, _useEventCallback.default)(function (event) {
161 if (isSliding) {
162 return;
163 }
164
165 var nextActiveIndex = renderedActiveIndex + 1;
166
167 if (nextActiveIndex >= numChildren) {
168 if (!wrap) {
169 return;
170 }
171
172 nextActiveIndex = 0;
173 }
174
175 nextDirectionRef.current = 'next';
176 onSelect(nextActiveIndex, event);
177 });
178 var elementRef = (0, _react.useRef)();
179 (0, _react.useImperativeHandle)(ref, function () {
180 return {
181 element: elementRef.current,
182 prev: prev,
183 next: next
184 };
185 }); // This is used in the setInterval, so it should not invalidate.
186
187 var nextWhenVisible = (0, _useEventCallback.default)(function () {
188 if (!document.hidden && isVisible(elementRef.current)) {
189 next();
190 }
191 });
192 var slideDirection = direction === 'next' ? 'left' : 'right';
193 (0, _useUpdateEffect.default)(function () {
194 if (slide) {
195 // These callbacks will be handled by the <Transition> callbacks.
196 return;
197 }
198
199 if (onSlide) {
200 onSlide(renderedActiveIndex, slideDirection);
201 }
202
203 if (onSlid) {
204 onSlid(renderedActiveIndex, slideDirection);
205 }
206 }, [renderedActiveIndex]);
207 var orderClassName = prefix + "-item-" + direction;
208 var directionalClassName = prefix + "-item-" + slideDirection;
209 var handleEnter = (0, _react.useCallback)(function (node) {
210 (0, _triggerBrowserReflow.default)(node);
211
212 if (onSlide) {
213 onSlide(renderedActiveIndex, slideDirection);
214 }
215 }, [onSlide, renderedActiveIndex, slideDirection]);
216 var handleEntered = (0, _react.useCallback)(function () {
217 setIsSliding(false);
218
219 if (onSlid) {
220 onSlid(renderedActiveIndex, slideDirection);
221 }
222 }, [onSlid, renderedActiveIndex, slideDirection]);
223 var handleKeyDown = (0, _react.useCallback)(function (event) {
224 if (keyboard && !/input|textarea/i.test(event.target.tagName)) {
225 switch (event.key) {
226 case 'ArrowLeft':
227 event.preventDefault();
228 prev(event);
229 return;
230
231 case 'ArrowRight':
232 event.preventDefault();
233 next(event);
234 return;
235
236 default:
237 }
238 }
239
240 if (onKeyDown) {
241 onKeyDown(event);
242 }
243 }, [keyboard, onKeyDown, prev, next]);
244
245 var _useState4 = (0, _react.useState)(false),
246 pausedOnHover = _useState4[0],
247 setPausedOnHover = _useState4[1];
248
249 var handleMouseOver = (0, _react.useCallback)(function (event) {
250 if (pause === 'hover') {
251 setPausedOnHover(true);
252 }
253
254 if (onMouseOver) {
255 onMouseOver(event);
256 }
257 }, [pause, onMouseOver]);
258 var handleMouseOut = (0, _react.useCallback)(function (event) {
259 setPausedOnHover(false);
260
261 if (onMouseOut) {
262 onMouseOut(event);
263 }
264 }, [onMouseOut]);
265 var touchStartXRef = (0, _react.useRef)(0);
266 var touchDeltaXRef = (0, _react.useRef)(0);
267
268 var _useState5 = (0, _react.useState)(false),
269 pausedOnTouch = _useState5[0],
270 setPausedOnTouch = _useState5[1];
271
272 var touchUnpauseTimeout = (0, _useTimeout.default)();
273 var handleTouchStart = (0, _react.useCallback)(function (event) {
274 touchStartXRef.current = event.touches[0].clientX;
275 touchDeltaXRef.current = 0;
276
277 if (touch) {
278 setPausedOnTouch(true);
279 }
280
281 if (onTouchStart) {
282 onTouchStart(event);
283 }
284 }, [touch, onTouchStart]);
285 var handleTouchMove = (0, _react.useCallback)(function (event) {
286 if (event.touches && event.touches.length > 1) {
287 touchDeltaXRef.current = 0;
288 } else {
289 touchDeltaXRef.current = event.touches[0].clientX - touchStartXRef.current;
290 }
291
292 if (onTouchMove) {
293 onTouchMove(event);
294 }
295 }, [onTouchMove]);
296 var handleTouchEnd = (0, _react.useCallback)(function (event) {
297 if (touch) {
298 var touchDeltaX = touchDeltaXRef.current;
299
300 if (Math.abs(touchDeltaX) <= SWIPE_THRESHOLD) {
301 return;
302 }
303
304 if (touchDeltaX > 0) {
305 prev(event);
306 } else {
307 next(event);
308 }
309 }
310
311 touchUnpauseTimeout.set(function () {
312 setPausedOnTouch(false);
313 }, interval);
314
315 if (onTouchEnd) {
316 onTouchEnd(event);
317 }
318 }, [touch, prev, next, touchUnpauseTimeout, interval, onTouchEnd]);
319 var shouldPlay = interval != null && !pausedOnHover && !pausedOnTouch && !isSliding;
320 var intervalHandleRef = (0, _react.useRef)();
321 (0, _react.useEffect)(function () {
322 if (!shouldPlay) {
323 return undefined;
324 }
325
326 intervalHandleRef.current = setInterval(document.visibilityState ? nextWhenVisible : next, interval);
327 return function () {
328 clearInterval(intervalHandleRef.current);
329 };
330 }, [shouldPlay, next, interval, nextWhenVisible]);
331 var indicatorOnClicks = (0, _react.useMemo)(function () {
332 return indicators && Array.from({
333 length: numChildren
334 }, function (_, index) {
335 return function (event) {
336 onSelect(index, event);
337 };
338 });
339 }, [indicators, numChildren, onSelect]);
340 return _react.default.createElement(Component, (0, _extends2.default)({
341 ref: elementRef
342 }, props, {
343 onKeyDown: handleKeyDown,
344 onMouseOver: handleMouseOver,
345 onMouseOut: handleMouseOut,
346 onTouchStart: handleTouchStart,
347 onTouchMove: handleTouchMove,
348 onTouchEnd: handleTouchEnd,
349 className: (0, _classnames.default)(className, prefix, slide && 'slide', fade && prefix + "-fade")
350 }), indicators && _react.default.createElement("ol", {
351 className: prefix + "-indicators"
352 }, (0, _ElementChildren.map)(children, function (child, index) {
353 return _react.default.createElement("li", {
354 key: index,
355 className: index === renderedActiveIndex ? 'active' : null,
356 onClick: indicatorOnClicks[index]
357 });
358 })), _react.default.createElement("div", {
359 className: prefix + "-inner"
360 }, (0, _ElementChildren.map)(children, function (child, index) {
361 var isActive = index === renderedActiveIndex;
362 return slide ? _react.default.createElement(_Transition.default, {
363 in: isActive,
364 onEnter: isActive ? handleEnter : null,
365 onEntered: isActive ? handleEntered : null,
366 addEndListener: _transitionEnd.default
367 }, function (status) {
368 return _react.default.cloneElement(child, {
369 className: (0, _classnames.default)(child.props.className, isActive && status !== 'entered' && orderClassName, (status === 'entered' || status === 'exiting') && 'active', (status === 'entering' || status === 'exiting') && directionalClassName)
370 });
371 }) : _react.default.cloneElement(child, {
372 className: (0, _classnames.default)(child.props.className, isActive && 'active')
373 });
374 })), controls && _react.default.createElement(_react.default.Fragment, null, (wrap || activeIndex !== 0) && _react.default.createElement(_SafeAnchor.default, {
375 className: prefix + "-control-prev",
376 onClick: prev
377 }, prevIcon, prevLabel && _react.default.createElement("span", {
378 className: "sr-only"
379 }, prevLabel)), (wrap || activeIndex !== numChildren - 1) && _react.default.createElement(_SafeAnchor.default, {
380 className: prefix + "-control-next",
381 onClick: next
382 }, nextIcon, nextLabel && _react.default.createElement("span", {
383 className: "sr-only"
384 }, nextLabel))));
385});
386
387Carousel.displayName = 'Carousel';
388Carousel.defaultProps = defaultProps;
389Carousel.Caption = _CarouselCaption.default;
390Carousel.Item = _CarouselItem.default;
391var _default = Carousel;
392exports.default = _default;
393module.exports = exports["default"];
\No newline at end of file