Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

364 строки
12 KiB

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