762806f740cf725bc462bd0018a37c66cf56cd4768ffc2596f8485f9edc5761a34feee230495e2628fbc6e815e886c5525b234c3f62c5734007a7e1c447caf 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. import { getCurrentInstance, useSlots, ref, computed, unref, isVNode, watch, shallowRef, onMounted, onBeforeUnmount, provide } from 'vue';
  2. import { throttle } from 'lodash-unified';
  3. import { useResizeObserver } from '@vueuse/core';
  4. import { CAROUSEL_ITEM_NAME, carouselContextKey } from './constants.mjs';
  5. import { useOrderedChildren } from '../../../hooks/use-ordered-children/index.mjs';
  6. import { isString } from '@vue/shared';
  7. import { flattedChildren } from '../../../utils/vue/vnode.mjs';
  8. import { CHANGE_EVENT } from '../../../constants/event.mjs';
  9. const THROTTLE_TIME = 300;
  10. const useCarousel = (props, emit, componentName) => {
  11. const {
  12. children: items,
  13. addChild: addItem,
  14. removeChild: removeItem,
  15. ChildrenSorter: ItemsSorter
  16. } = useOrderedChildren(getCurrentInstance(), CAROUSEL_ITEM_NAME);
  17. const slots = useSlots();
  18. const activeIndex = ref(-1);
  19. const timer = ref(null);
  20. const hover = ref(false);
  21. const root = ref();
  22. const containerHeight = ref(0);
  23. const isItemsTwoLength = ref(true);
  24. const arrowDisplay = computed(() => props.arrow !== "never" && !unref(isVertical));
  25. const hasLabel = computed(() => {
  26. return items.value.some((item) => item.props.label.toString().length > 0);
  27. });
  28. const isCardType = computed(() => props.type === "card");
  29. const isVertical = computed(() => props.direction === "vertical");
  30. const containerStyle = computed(() => {
  31. if (props.height !== "auto") {
  32. return {
  33. height: props.height
  34. };
  35. }
  36. return {
  37. height: `${containerHeight.value}px`,
  38. overflow: "hidden"
  39. };
  40. });
  41. const throttledArrowClick = throttle((index) => {
  42. setActiveItem(index);
  43. }, THROTTLE_TIME, { trailing: true });
  44. const throttledIndicatorHover = throttle((index) => {
  45. handleIndicatorHover(index);
  46. }, THROTTLE_TIME);
  47. const isTwoLengthShow = (index) => {
  48. if (!isItemsTwoLength.value)
  49. return true;
  50. return activeIndex.value <= 1 ? index <= 1 : index > 1;
  51. };
  52. function pauseTimer() {
  53. if (timer.value) {
  54. clearInterval(timer.value);
  55. timer.value = null;
  56. }
  57. }
  58. function startTimer() {
  59. if (props.interval <= 0 || !props.autoplay || timer.value)
  60. return;
  61. timer.value = setInterval(() => playSlides(), props.interval);
  62. }
  63. const playSlides = () => {
  64. if (activeIndex.value < items.value.length - 1) {
  65. activeIndex.value = activeIndex.value + 1;
  66. } else if (props.loop) {
  67. activeIndex.value = 0;
  68. }
  69. };
  70. function setActiveItem(index) {
  71. if (isString(index)) {
  72. const filteredItems = items.value.filter((item) => item.props.name === index);
  73. if (filteredItems.length > 0) {
  74. index = items.value.indexOf(filteredItems[0]);
  75. }
  76. }
  77. index = Number(index);
  78. if (Number.isNaN(index) || index !== Math.floor(index)) {
  79. return;
  80. }
  81. const itemCount = items.value.length;
  82. const oldIndex = activeIndex.value;
  83. if (index < 0) {
  84. activeIndex.value = props.loop ? itemCount - 1 : 0;
  85. } else if (index >= itemCount) {
  86. activeIndex.value = props.loop ? 0 : itemCount - 1;
  87. } else {
  88. activeIndex.value = index;
  89. }
  90. if (oldIndex === activeIndex.value) {
  91. resetItemPosition(oldIndex);
  92. }
  93. resetTimer();
  94. }
  95. function resetItemPosition(oldIndex) {
  96. items.value.forEach((item, index) => {
  97. item.translateItem(index, activeIndex.value, oldIndex);
  98. });
  99. }
  100. function itemInStage(item, index) {
  101. var _a, _b, _c, _d;
  102. const _items = unref(items);
  103. const itemCount = _items.length;
  104. if (itemCount === 0 || !item.states.inStage)
  105. return false;
  106. const nextItemIndex = index + 1;
  107. const prevItemIndex = index - 1;
  108. const lastItemIndex = itemCount - 1;
  109. const isLastItemActive = _items[lastItemIndex].states.active;
  110. const isFirstItemActive = _items[0].states.active;
  111. const isNextItemActive = (_b = (_a = _items[nextItemIndex]) == null ? void 0 : _a.states) == null ? void 0 : _b.active;
  112. const isPrevItemActive = (_d = (_c = _items[prevItemIndex]) == null ? void 0 : _c.states) == null ? void 0 : _d.active;
  113. if (index === lastItemIndex && isFirstItemActive || isNextItemActive) {
  114. return "left";
  115. } else if (index === 0 && isLastItemActive || isPrevItemActive) {
  116. return "right";
  117. }
  118. return false;
  119. }
  120. function handleMouseEnter() {
  121. hover.value = true;
  122. if (props.pauseOnHover) {
  123. pauseTimer();
  124. }
  125. }
  126. function handleMouseLeave() {
  127. hover.value = false;
  128. startTimer();
  129. }
  130. function handleButtonEnter(arrow) {
  131. if (unref(isVertical))
  132. return;
  133. items.value.forEach((item, index) => {
  134. if (arrow === itemInStage(item, index)) {
  135. item.states.hover = true;
  136. }
  137. });
  138. }
  139. function handleButtonLeave() {
  140. if (unref(isVertical))
  141. return;
  142. items.value.forEach((item) => {
  143. item.states.hover = false;
  144. });
  145. }
  146. function handleIndicatorClick(index) {
  147. activeIndex.value = index;
  148. }
  149. function handleIndicatorHover(index) {
  150. if (props.trigger === "hover" && index !== activeIndex.value) {
  151. activeIndex.value = index;
  152. }
  153. }
  154. function prev() {
  155. setActiveItem(activeIndex.value - 1);
  156. }
  157. function next() {
  158. setActiveItem(activeIndex.value + 1);
  159. }
  160. function resetTimer() {
  161. pauseTimer();
  162. if (!props.pauseOnHover)
  163. startTimer();
  164. }
  165. function setContainerHeight(height) {
  166. if (props.height !== "auto")
  167. return;
  168. containerHeight.value = height;
  169. }
  170. function PlaceholderItem() {
  171. var _a;
  172. const defaultSlots = (_a = slots.default) == null ? void 0 : _a.call(slots);
  173. if (!defaultSlots)
  174. return null;
  175. const flatSlots = flattedChildren(defaultSlots);
  176. const normalizeSlots = flatSlots.filter((slot) => {
  177. return isVNode(slot) && slot.type.name === CAROUSEL_ITEM_NAME;
  178. });
  179. if ((normalizeSlots == null ? void 0 : normalizeSlots.length) === 2 && props.loop && !isCardType.value) {
  180. isItemsTwoLength.value = true;
  181. return normalizeSlots;
  182. }
  183. isItemsTwoLength.value = false;
  184. return null;
  185. }
  186. watch(() => activeIndex.value, (current, prev2) => {
  187. resetItemPosition(prev2);
  188. if (isItemsTwoLength.value) {
  189. current = current % 2;
  190. prev2 = prev2 % 2;
  191. }
  192. if (prev2 > -1) {
  193. emit(CHANGE_EVENT, current, prev2);
  194. }
  195. });
  196. const exposeActiveIndex = computed({
  197. get: () => {
  198. return isItemsTwoLength.value ? activeIndex.value % 2 : activeIndex.value;
  199. },
  200. set: (value) => activeIndex.value = value
  201. });
  202. watch(() => props.autoplay, (autoplay) => {
  203. autoplay ? startTimer() : pauseTimer();
  204. });
  205. watch(() => props.loop, () => {
  206. setActiveItem(activeIndex.value);
  207. });
  208. watch(() => props.interval, () => {
  209. resetTimer();
  210. });
  211. const resizeObserver = shallowRef();
  212. onMounted(() => {
  213. watch(() => items.value, () => {
  214. if (items.value.length > 0)
  215. setActiveItem(props.initialIndex);
  216. }, {
  217. immediate: true
  218. });
  219. resizeObserver.value = useResizeObserver(root.value, () => {
  220. resetItemPosition();
  221. });
  222. startTimer();
  223. });
  224. onBeforeUnmount(() => {
  225. pauseTimer();
  226. if (root.value && resizeObserver.value)
  227. resizeObserver.value.stop();
  228. });
  229. provide(carouselContextKey, {
  230. root,
  231. isCardType,
  232. isVertical,
  233. items,
  234. loop: props.loop,
  235. cardScale: props.cardScale,
  236. addItem,
  237. removeItem,
  238. setActiveItem,
  239. setContainerHeight
  240. });
  241. return {
  242. root,
  243. activeIndex,
  244. exposeActiveIndex,
  245. arrowDisplay,
  246. hasLabel,
  247. hover,
  248. isCardType,
  249. items,
  250. isVertical,
  251. containerStyle,
  252. isItemsTwoLength,
  253. handleButtonEnter,
  254. handleButtonLeave,
  255. handleIndicatorClick,
  256. handleMouseEnter,
  257. handleMouseLeave,
  258. setActiveItem,
  259. prev,
  260. next,
  261. PlaceholderItem,
  262. isTwoLengthShow,
  263. ItemsSorter,
  264. throttledArrowClick,
  265. throttledIndicatorHover
  266. };
  267. };
  268. export { useCarousel };
  269. //# sourceMappingURL=use-carousel.mjs.map