@fluentui/react-carousel 9.3.0 → 9.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (25) hide show
  1. package/CHANGELOG.md +28 -10
  2. package/dist/index.d.ts +2 -2
  3. package/lib/components/Carousel/useCarousel.js +2 -1
  4. package/lib/components/Carousel/useCarousel.js.map +1 -1
  5. package/lib/components/CarouselAutoplayButton/useCarouselAutoplayButton.js +4 -8
  6. package/lib/components/CarouselAutoplayButton/useCarouselAutoplayButton.js.map +1 -1
  7. package/lib/components/CarouselButton/useCarouselButton.js +1 -2
  8. package/lib/components/CarouselButton/useCarouselButton.js.map +1 -1
  9. package/lib/components/CarouselContext.types.js.map +1 -1
  10. package/lib/components/CarouselViewport/useCarouselViewport.js +45 -2
  11. package/lib/components/CarouselViewport/useCarouselViewport.js.map +1 -1
  12. package/lib/components/useEmblaCarousel.js +102 -83
  13. package/lib/components/useEmblaCarousel.js.map +1 -1
  14. package/lib-commonjs/components/Carousel/useCarousel.js +2 -1
  15. package/lib-commonjs/components/Carousel/useCarousel.js.map +1 -1
  16. package/lib-commonjs/components/CarouselAutoplayButton/useCarouselAutoplayButton.js +3 -7
  17. package/lib-commonjs/components/CarouselAutoplayButton/useCarouselAutoplayButton.js.map +1 -1
  18. package/lib-commonjs/components/CarouselButton/useCarouselButton.js +1 -1
  19. package/lib-commonjs/components/CarouselButton/useCarouselButton.js.map +1 -1
  20. package/lib-commonjs/components/CarouselContext.types.js.map +1 -1
  21. package/lib-commonjs/components/CarouselViewport/useCarouselViewport.js +44 -1
  22. package/lib-commonjs/components/CarouselViewport/useCarouselViewport.js.map +1 -1
  23. package/lib-commonjs/components/useEmblaCarousel.js +101 -83
  24. package/lib-commonjs/components/useEmblaCarousel.js.map +1 -1
  25. package/package.json +6 -5
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/useEmblaCarousel.ts"],"sourcesContent":["import { type EventHandler, useControllableState, useEventCallback } from '@fluentui/react-utilities';\nimport EmblaCarousel, { EmblaPluginType, type EmblaCarouselType, type EmblaOptionsType } from 'embla-carousel';\nimport * as React from 'react';\n\nimport { carouselCardClassNames } from './CarouselCard/useCarouselCardStyles.styles';\nimport { carouselSliderClassNames } from './CarouselSlider/useCarouselSliderStyles.styles';\nimport { CarouselMotion, CarouselUpdateData, CarouselVisibilityEventDetail } from '../Carousel';\nimport Autoplay from 'embla-carousel-autoplay';\nimport Fade from 'embla-carousel-fade';\nimport { pointerEventPlugin } from './pointerEvents';\nimport type { CarouselIndexChangeData } from './CarouselContext.types';\n\nconst sliderClassname = `.${carouselSliderClassNames.root}`;\n\nconst DEFAULT_EMBLA_OPTIONS: EmblaOptionsType = {\n containScroll: 'trimSnaps',\n inViewThreshold: 0.99,\n watchDrag: false,\n skipSnaps: true,\n\n container: sliderClassname,\n slides: `.${carouselCardClassNames.root}`,\n};\n\nexport const EMBLA_VISIBILITY_EVENT = 'embla:visibilitychange';\n\nexport function setTabsterDefault(element: Element, isDefault: boolean) {\n const tabsterAttr = element.getAttribute('data-tabster');\n\n if (tabsterAttr) {\n const tabsterAttributes = JSON.parse(tabsterAttr);\n if (tabsterAttributes.focusable) {\n // If tabster.focusable isn't present, we will ignore.\n tabsterAttributes.focusable.isDefault = isDefault;\n element.setAttribute('data-tabster', JSON.stringify(tabsterAttributes));\n }\n }\n}\n\nexport function useEmblaCarousel(\n options: Pick<EmblaOptionsType, 'align' | 'direction' | 'loop' | 'slidesToScroll' | 'watchDrag' | 'containScroll'> & {\n defaultActiveIndex: number | undefined;\n activeIndex: number | undefined;\n motion?: CarouselMotion;\n onDragIndexChange?: EventHandler<CarouselIndexChangeData>;\n },\n) {\n const { align, direction, loop, slidesToScroll, watchDrag, containScroll, motion, onDragIndexChange } = options;\n const [activeIndex, setActiveIndex] = useControllableState({\n defaultState: options.defaultActiveIndex,\n state: options.activeIndex,\n initialState: 0,\n });\n\n const onDragEvent = useEventCallback((event: PointerEvent | MouseEvent, index: number) => {\n onDragIndexChange?.(event, { event, type: 'drag', index });\n });\n\n const emblaOptions = React.useRef<EmblaOptionsType>({\n align,\n direction,\n loop,\n slidesToScroll,\n startIndex: activeIndex,\n watchDrag,\n containScroll,\n });\n\n const emblaApi = React.useRef<EmblaCarouselType | null>(null);\n const autoplayRef = React.useRef<boolean>(false);\n\n const resetAutoplay = React.useCallback(() => {\n emblaApi.current?.plugins().autoplay.reset();\n }, []);\n\n /* Our autoplay button, which is required by standards for autoplay to be enabled, will handle controlled state */\n const enableAutoplay = React.useCallback(\n (autoplay: boolean) => {\n autoplayRef.current = autoplay;\n if (autoplay) {\n emblaApi.current?.plugins().autoplay.play();\n // Reset after play to ensure timing and any focus/mouse pause state is reset.\n resetAutoplay();\n } else {\n emblaApi.current?.plugins().autoplay.stop();\n }\n },\n [resetAutoplay],\n );\n\n const getPlugins = React.useCallback(() => {\n const plugins: EmblaPluginType[] = [\n Autoplay({\n playOnInit: autoplayRef.current,\n stopOnInteraction: !autoplayRef.current,\n stopOnMouseEnter: true,\n stopOnFocusIn: true,\n }),\n ];\n\n // Optionally add Fade plugin\n if (motion === 'fade') {\n plugins.push(Fade());\n }\n\n if (watchDrag) {\n plugins.push(\n pointerEventPlugin({\n onSelectViaDrag: onDragEvent,\n }),\n );\n }\n\n return plugins;\n }, [motion, onDragEvent, watchDrag]);\n\n // Listeners contains callbacks for UI elements that may require state update based on embla changes\n const listeners = React.useRef(new Set<(data: CarouselUpdateData) => void>());\n const subscribeForValues = React.useCallback((listener: (data: CarouselUpdateData) => void) => {\n listeners.current.add(listener);\n\n return () => {\n listeners.current.delete(listener);\n };\n }, []);\n\n const viewportRef: React.RefObject<HTMLDivElement> = React.useRef(null);\n const containerRef: React.RefObject<HTMLDivElement> = React.useMemo(() => {\n let currentElement: HTMLDivElement | null = null;\n\n const handleIndexChange = () => {\n const newIndex = emblaApi.current?.selectedScrollSnap() ?? 0;\n const slides = emblaApi.current?.slideNodes();\n const actualIndex = emblaApi.current?.internalEngine().slideRegistry[newIndex][0] ?? 0;\n\n // We set the active or first index of group on-screen as the selected tabster index\n slides?.forEach((slide, slideIndex) => {\n setTabsterDefault(slide, slideIndex === actualIndex);\n });\n setActiveIndex(newIndex);\n };\n const handleReinit = () => {\n const nodes: HTMLElement[] = emblaApi.current?.slideNodes() ?? [];\n const groupIndexList: number[][] = emblaApi.current?.internalEngine().slideRegistry ?? [];\n const navItemsCount = groupIndexList.length > 0 ? groupIndexList.length : nodes.length;\n\n const data: CarouselUpdateData = {\n navItemsCount,\n activeIndex: emblaApi.current?.selectedScrollSnap() ?? 0,\n groupIndexList,\n slideNodes: nodes,\n };\n\n for (const listener of listeners.current) {\n listener(data);\n }\n };\n const handleVisibilityChange = () => {\n const cardElements = emblaApi.current?.slideNodes();\n const visibleIndexes = emblaApi.current?.slidesInView() ?? [];\n\n cardElements?.forEach((cardElement, index) => {\n cardElement.dispatchEvent(\n new CustomEvent<CarouselVisibilityEventDetail>(EMBLA_VISIBILITY_EVENT, {\n bubbles: false,\n detail: { isVisible: visibleIndexes.includes(index) },\n }),\n );\n });\n };\n\n const plugins = getPlugins();\n\n return {\n set current(newElement: HTMLDivElement | null) {\n if (currentElement) {\n emblaApi.current?.off('slidesInView', handleVisibilityChange);\n emblaApi.current?.off('select', handleIndexChange);\n emblaApi.current?.off('reInit', handleReinit);\n emblaApi.current?.destroy();\n }\n\n // Use direct viewport if available, else fallback to container (includes Carousel controls).\n const wrapperElement = viewportRef.current ?? newElement;\n if (wrapperElement) {\n currentElement = wrapperElement;\n emblaApi.current = EmblaCarousel(\n wrapperElement,\n {\n ...DEFAULT_EMBLA_OPTIONS,\n ...emblaOptions.current,\n },\n plugins,\n );\n\n emblaApi.current?.on('reInit', handleReinit);\n emblaApi.current?.on('slidesInView', handleVisibilityChange);\n emblaApi.current?.on('select', handleIndexChange);\n }\n },\n };\n }, [getPlugins, setActiveIndex]);\n\n const carouselApi = React.useMemo(\n () => ({\n scrollToElement: (element: HTMLElement, jump?: boolean) => {\n const cardElements = emblaApi.current?.slideNodes();\n const groupIndexList = emblaApi.current?.internalEngine().slideRegistry ?? [];\n const cardIndex = cardElements?.indexOf(element) ?? 0;\n const groupIndex = groupIndexList.findIndex(group => {\n return group.includes(cardIndex);\n });\n const indexFocus = groupIndex ?? cardIndex;\n emblaApi.current?.scrollTo(indexFocus, jump);\n\n return indexFocus;\n },\n scrollToIndex: (index: number, jump?: boolean) => {\n emblaApi.current?.scrollTo(index, jump);\n },\n scrollInDirection: (dir: 'prev' | 'next') => {\n if (dir === 'prev') {\n emblaApi.current?.scrollPrev();\n } else {\n emblaApi.current?.scrollNext();\n }\n\n return emblaApi.current?.selectedScrollSnap() ?? 0;\n },\n }),\n [],\n );\n\n React.useEffect(() => {\n // Scroll to controlled values on update\n const currentActiveIndex = emblaApi.current?.selectedScrollSnap() ?? 0;\n emblaOptions.current.startIndex = activeIndex;\n if (activeIndex !== currentActiveIndex) {\n emblaApi.current?.scrollTo(activeIndex);\n }\n }, [activeIndex]);\n\n React.useEffect(() => {\n const plugins = getPlugins();\n\n emblaOptions.current = {\n startIndex: emblaOptions.current.startIndex,\n align,\n direction,\n loop,\n slidesToScroll,\n watchDrag,\n containScroll,\n };\n emblaApi.current?.reInit(\n {\n ...DEFAULT_EMBLA_OPTIONS,\n ...emblaOptions.current,\n },\n plugins,\n );\n }, [align, direction, loop, slidesToScroll, watchDrag, containScroll, getPlugins]);\n\n return {\n activeIndex,\n carouselApi,\n viewportRef,\n containerRef,\n subscribeForValues,\n enableAutoplay,\n resetAutoplay,\n };\n}\n"],"names":["useControllableState","useEventCallback","EmblaCarousel","React","carouselCardClassNames","carouselSliderClassNames","Autoplay","Fade","pointerEventPlugin","sliderClassname","root","DEFAULT_EMBLA_OPTIONS","containScroll","inViewThreshold","watchDrag","skipSnaps","container","slides","EMBLA_VISIBILITY_EVENT","setTabsterDefault","element","isDefault","tabsterAttr","getAttribute","tabsterAttributes","JSON","parse","focusable","setAttribute","stringify","useEmblaCarousel","options","align","direction","loop","slidesToScroll","motion","onDragIndexChange","activeIndex","setActiveIndex","defaultState","defaultActiveIndex","state","initialState","onDragEvent","event","index","type","emblaOptions","useRef","startIndex","emblaApi","autoplayRef","resetAutoplay","useCallback","current","plugins","autoplay","reset","enableAutoplay","play","stop","getPlugins","playOnInit","stopOnInteraction","stopOnMouseEnter","stopOnFocusIn","push","onSelectViaDrag","listeners","Set","subscribeForValues","listener","add","delete","viewportRef","containerRef","useMemo","currentElement","handleIndexChange","newIndex","selectedScrollSnap","slideNodes","actualIndex","internalEngine","slideRegistry","forEach","slide","slideIndex","handleReinit","nodes","groupIndexList","navItemsCount","length","data","handleVisibilityChange","cardElements","visibleIndexes","slidesInView","cardElement","dispatchEvent","CustomEvent","bubbles","detail","isVisible","includes","newElement","off","destroy","wrapperElement","on","carouselApi","scrollToElement","jump","cardIndex","indexOf","groupIndex","findIndex","group","indexFocus","scrollTo","scrollToIndex","scrollInDirection","dir","scrollPrev","scrollNext","useEffect","currentActiveIndex","reInit"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../src/components/useEmblaCarousel.ts"],"sourcesContent":["import { type EventHandler, useControllableState, useEventCallback } from '@fluentui/react-utilities';\nimport EmblaCarousel, { EmblaPluginType, type EmblaCarouselType, type EmblaOptionsType } from 'embla-carousel';\nimport * as React from 'react';\n\nimport { carouselCardClassNames } from './CarouselCard/useCarouselCardStyles.styles';\nimport { carouselSliderClassNames } from './CarouselSlider/useCarouselSliderStyles.styles';\nimport { CarouselMotion, CarouselUpdateData, CarouselVisibilityEventDetail } from '../Carousel';\nimport Autoplay from 'embla-carousel-autoplay';\nimport Fade from 'embla-carousel-fade';\nimport { pointerEventPlugin } from './pointerEvents';\nimport type { CarouselIndexChangeData } from './CarouselContext.types';\n\ntype EmblaEventHandler = Parameters<EmblaCarouselType['on']>[1];\n\nconst sliderClassname = `.${carouselSliderClassNames.root}`;\n\nconst DEFAULT_EMBLA_OPTIONS: EmblaOptionsType = {\n containScroll: 'trimSnaps',\n inViewThreshold: 0.99,\n watchDrag: false,\n skipSnaps: true,\n\n container: sliderClassname,\n slides: `.${carouselCardClassNames.root}`,\n};\n\nexport const EMBLA_VISIBILITY_EVENT = 'embla:visibilitychange';\n\nexport function setTabsterDefault(element: Element, isDefault: boolean) {\n const tabsterAttr = element.getAttribute('data-tabster');\n\n if (tabsterAttr) {\n const tabsterAttributes = JSON.parse(tabsterAttr);\n if (tabsterAttributes.focusable) {\n // If tabster.focusable isn't present, we will ignore.\n tabsterAttributes.focusable.isDefault = isDefault;\n element.setAttribute('data-tabster', JSON.stringify(tabsterAttributes));\n }\n }\n}\n\nexport function useEmblaCarousel(\n options: Pick<EmblaOptionsType, 'align' | 'direction' | 'loop' | 'slidesToScroll' | 'watchDrag' | 'containScroll'> & {\n defaultActiveIndex: number | undefined;\n activeIndex: number | undefined;\n motion?: CarouselMotion;\n onDragIndexChange?: EventHandler<CarouselIndexChangeData>;\n onAutoplayIndexChange?: EventHandler<CarouselIndexChangeData>;\n },\n) {\n const {\n align,\n direction,\n loop,\n slidesToScroll,\n watchDrag,\n containScroll,\n motion,\n onDragIndexChange,\n onAutoplayIndexChange,\n } = options;\n const [activeIndex, setActiveIndex] = useControllableState({\n defaultState: options.defaultActiveIndex,\n state: options.activeIndex,\n initialState: 0,\n });\n\n const onDragEvent = useEventCallback((event: PointerEvent | MouseEvent, index: number) => {\n onDragIndexChange?.(event, { event, type: 'drag', index });\n });\n\n const emblaOptions = React.useRef<EmblaOptionsType>({\n align,\n direction,\n loop,\n slidesToScroll,\n startIndex: activeIndex,\n watchDrag,\n containScroll,\n });\n\n const emblaApi = React.useRef<EmblaCarouselType | null>(null);\n const autoplayRef = React.useRef<boolean>(false);\n\n const resetAutoplay = React.useCallback(() => {\n emblaApi.current?.plugins().autoplay?.reset();\n }, []);\n\n const getPlugins = React.useCallback(() => {\n const plugins: EmblaPluginType[] = [];\n\n plugins.push(\n Autoplay({\n playOnInit: autoplayRef.current,\n /* stopOnInteraction: false causes autoplay to restart on interaction end*/\n /* we'll handle this logic to ensure autoplay state is respected */\n stopOnInteraction: true,\n stopOnFocusIn: false, // We'll handle this one manually to prevent conflicts with tabster\n stopOnMouseEnter: false, // We will handle this manually to align functionality\n }),\n );\n\n // Optionally add Fade plugin\n if (motion === 'fade') {\n plugins.push(Fade());\n }\n\n if (watchDrag) {\n plugins.push(\n pointerEventPlugin({\n onSelectViaDrag: onDragEvent,\n }),\n );\n }\n\n return plugins;\n }, [motion, onDragEvent, watchDrag]);\n\n /* This function enables autoplay to pause/play without affecting underlying state\n * Useful for pausing on focus etc. without having to reinitialize or set autoplay to off\n */\n const enableAutoplay = React.useCallback(\n (autoplay: boolean, temporary?: boolean) => {\n if (!temporary) {\n autoplayRef.current = autoplay;\n }\n\n if (autoplay && autoplayRef.current) {\n // Autoplay should only enable in the case where underlying state is true, temporary should not override\n emblaApi.current?.plugins().autoplay?.play();\n // Reset after play to ensure timing and any focus/mouse pause state is reset.\n resetAutoplay();\n } else if (!autoplay) {\n emblaApi.current?.plugins().autoplay?.stop();\n }\n },\n [resetAutoplay],\n );\n\n // Listeners contains callbacks for UI elements that may require state update based on embla changes\n const listeners = React.useRef(new Set<(data: CarouselUpdateData) => void>());\n const subscribeForValues = React.useCallback((listener: (data: CarouselUpdateData) => void) => {\n listeners.current.add(listener);\n\n return () => {\n listeners.current.delete(listener);\n };\n }, []);\n\n const handleReinit = useEventCallback(() => {\n const nodes: HTMLElement[] = emblaApi.current?.slideNodes() ?? [];\n const groupIndexList: number[][] = emblaApi.current?.internalEngine().slideRegistry ?? [];\n const navItemsCount = groupIndexList.length > 0 ? groupIndexList.length : nodes.length;\n\n const data: CarouselUpdateData = {\n navItemsCount,\n activeIndex: emblaApi.current?.selectedScrollSnap() ?? 0,\n groupIndexList,\n slideNodes: nodes,\n };\n\n emblaApi.current?.scrollTo(activeIndex, false);\n for (const listener of listeners.current) {\n listener(data);\n }\n });\n\n const handleIndexChange: EmblaEventHandler = useEventCallback((_, eventType) => {\n const newIndex = emblaApi.current?.selectedScrollSnap() ?? 0;\n const slides = emblaApi.current?.slideNodes();\n const actualIndex = emblaApi.current?.internalEngine().slideRegistry[newIndex][0] ?? 0;\n\n // We set the active or first index of group on-screen as the selected tabster index\n slides?.forEach((slide, slideIndex) => {\n setTabsterDefault(slide, slideIndex === actualIndex);\n });\n setActiveIndex(newIndex);\n\n if (eventType === 'autoplay:select') {\n const noopEvent = new Event('autoplay');\n onAutoplayIndexChange?.(noopEvent, { event: noopEvent, type: 'autoplay', index: newIndex });\n }\n });\n\n const viewportRef: React.RefObject<HTMLDivElement> = React.useRef(null);\n const containerRef: React.RefObject<HTMLDivElement> = React.useMemo(() => {\n let currentElement: HTMLDivElement | null = null;\n\n const handleVisibilityChange = () => {\n const cardElements = emblaApi.current?.slideNodes();\n const visibleIndexes = emblaApi.current?.slidesInView() ?? [];\n\n cardElements?.forEach((cardElement, index) => {\n cardElement.dispatchEvent(\n new CustomEvent<CarouselVisibilityEventDetail>(EMBLA_VISIBILITY_EVENT, {\n bubbles: false,\n detail: { isVisible: visibleIndexes.includes(index) },\n }),\n );\n });\n };\n\n // Get plugins using autoplayRef to prevent state change recreating EmblaCarousel\n const plugins = getPlugins();\n\n return {\n set current(newElement: HTMLDivElement | null) {\n if (currentElement) {\n emblaApi.current?.off('slidesInView', handleVisibilityChange);\n emblaApi.current?.off('select', handleIndexChange);\n emblaApi.current?.off('reInit', handleReinit);\n emblaApi.current?.off('autoplay:select', handleIndexChange);\n emblaApi.current?.destroy();\n }\n\n // Use direct viewport if available, else fallback to container (includes Carousel controls).\n currentElement = viewportRef.current ?? newElement;\n if (currentElement) {\n emblaApi.current = EmblaCarousel(\n currentElement,\n {\n ...DEFAULT_EMBLA_OPTIONS,\n ...emblaOptions.current,\n },\n plugins,\n );\n\n emblaApi.current?.on('reInit', handleReinit);\n emblaApi.current?.on('slidesInView', handleVisibilityChange);\n emblaApi.current?.on('select', handleIndexChange);\n emblaApi.current?.on('autoplay:select', handleIndexChange);\n }\n },\n };\n }, [getPlugins, handleIndexChange, handleReinit]);\n\n const carouselApi = React.useMemo(\n () => ({\n scrollToElement: (element: HTMLElement, jump?: boolean) => {\n const cardElements = emblaApi.current?.slideNodes();\n const groupIndexList = emblaApi.current?.internalEngine().slideRegistry ?? [];\n const cardIndex = cardElements?.indexOf(element) ?? 0;\n const groupIndex = groupIndexList.findIndex(group => {\n return group.includes(cardIndex);\n });\n const indexFocus = groupIndex ?? cardIndex;\n emblaApi.current?.scrollTo(indexFocus, jump);\n\n return indexFocus;\n },\n scrollToIndex: (index: number, jump?: boolean) => {\n emblaApi.current?.scrollTo(index, jump);\n },\n scrollInDirection: (dir: 'prev' | 'next') => {\n if (dir === 'prev') {\n emblaApi.current?.scrollPrev();\n } else {\n emblaApi.current?.scrollNext();\n }\n\n return emblaApi.current?.selectedScrollSnap() ?? 0;\n },\n }),\n [],\n );\n\n React.useEffect(() => {\n const plugins = getPlugins();\n\n emblaOptions.current = {\n startIndex: emblaOptions.current.startIndex,\n align,\n direction,\n loop,\n slidesToScroll,\n watchDrag,\n containScroll,\n };\n\n emblaApi.current?.reInit(\n {\n ...DEFAULT_EMBLA_OPTIONS,\n ...emblaOptions.current,\n },\n plugins,\n );\n }, [align, containScroll, direction, getPlugins, loop, slidesToScroll, watchDrag]);\n\n React.useEffect(() => {\n // Scroll to controlled values on update\n // If active index is out of bounds, re-init will handle instead\n const currentActiveIndex = emblaApi.current?.selectedScrollSnap() ?? 0;\n const slideLength = emblaApi.current?.slideNodes()?.length ?? 0;\n emblaOptions.current.startIndex = activeIndex;\n if (activeIndex < slideLength && activeIndex !== currentActiveIndex) {\n emblaApi.current?.scrollTo(activeIndex);\n }\n }, [activeIndex]);\n\n return {\n activeIndex,\n carouselApi,\n viewportRef,\n containerRef,\n subscribeForValues,\n enableAutoplay,\n resetAutoplay,\n };\n}\n"],"names":["useControllableState","useEventCallback","EmblaCarousel","React","carouselCardClassNames","carouselSliderClassNames","Autoplay","Fade","pointerEventPlugin","sliderClassname","root","DEFAULT_EMBLA_OPTIONS","containScroll","inViewThreshold","watchDrag","skipSnaps","container","slides","EMBLA_VISIBILITY_EVENT","setTabsterDefault","element","isDefault","tabsterAttr","getAttribute","tabsterAttributes","JSON","parse","focusable","setAttribute","stringify","useEmblaCarousel","options","align","direction","loop","slidesToScroll","motion","onDragIndexChange","onAutoplayIndexChange","activeIndex","setActiveIndex","defaultState","defaultActiveIndex","state","initialState","onDragEvent","event","index","type","emblaOptions","useRef","startIndex","emblaApi","autoplayRef","resetAutoplay","useCallback","current","plugins","autoplay","reset","getPlugins","push","playOnInit","stopOnInteraction","stopOnFocusIn","stopOnMouseEnter","onSelectViaDrag","enableAutoplay","temporary","play","stop","listeners","Set","subscribeForValues","listener","add","delete","handleReinit","nodes","slideNodes","groupIndexList","internalEngine","slideRegistry","navItemsCount","length","data","selectedScrollSnap","scrollTo","handleIndexChange","_","eventType","newIndex","actualIndex","forEach","slide","slideIndex","noopEvent","Event","viewportRef","containerRef","useMemo","currentElement","handleVisibilityChange","cardElements","visibleIndexes","slidesInView","cardElement","dispatchEvent","CustomEvent","bubbles","detail","isVisible","includes","newElement","off","destroy","on","carouselApi","scrollToElement","jump","cardIndex","indexOf","groupIndex","findIndex","group","indexFocus","scrollToIndex","scrollInDirection","dir","scrollPrev","scrollNext","useEffect","reInit","currentActiveIndex","slideLength"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -27,7 +27,8 @@ function useCarousel_unstable(props, ref) {
27
27
  watchDrag: draggable,
28
28
  containScroll: whitespace ? false : 'keepSnaps',
29
29
  motion,
30
- onDragIndexChange: onActiveIndexChange
30
+ onDragIndexChange: onActiveIndexChange,
31
+ onAutoplayIndexChange: onActiveIndexChange
31
32
  });
32
33
  const selectPageByElement = (0, _reactutilities.useEventCallback)((event, element, jump)=>{
33
34
  const foundIndex = carouselApi.scrollToElement(element, jump);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/Carousel/useCarousel.ts"],"sourcesContent":["import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport {\n getIntrinsicElementProps,\n slot,\n useEventCallback,\n useIsomorphicLayoutEffect,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselProps, CarouselState } from './Carousel.types';\nimport type { CarouselContextValue } from '../CarouselContext.types';\nimport { useEmblaCarousel } from '../useEmblaCarousel';\nimport { useAnnounce } from '@fluentui/react-shared-contexts';\n\n/**\n * Create the state required to render Carousel.\n *\n * The returned state can be modified with hooks such as useCarouselStyles_unstable,\n * before being passed to renderCarousel_unstable.\n *\n * @param props - props from this instance of Carousel\n * @param ref - reference to root HTMLDivElement of Carousel\n */\nexport function useCarousel_unstable(props: CarouselProps, ref: React.Ref<HTMLDivElement>): CarouselState {\n 'use no memo';\n\n const {\n align = 'center',\n circular = false,\n onActiveIndexChange,\n groupSize = 'auto',\n draggable = false,\n whitespace = false,\n announcement,\n motion = 'slide',\n } = props;\n\n const { dir } = useFluent();\n const { activeIndex, carouselApi, containerRef, viewportRef, subscribeForValues, enableAutoplay, resetAutoplay } =\n useEmblaCarousel({\n align,\n direction: dir,\n loop: circular,\n slidesToScroll: groupSize,\n defaultActiveIndex: props.defaultActiveIndex,\n activeIndex: props.activeIndex,\n watchDrag: draggable,\n containScroll: whitespace ? false : 'keepSnaps',\n motion,\n onDragIndexChange: onActiveIndexChange,\n });\n\n const selectPageByElement: CarouselContextValue['selectPageByElement'] = useEventCallback((event, element, jump) => {\n const foundIndex = carouselApi.scrollToElement(element, jump);\n onActiveIndexChange?.(event, { event, type: 'focus', index: foundIndex });\n\n return foundIndex;\n });\n\n const selectPageByIndex: CarouselContextValue['selectPageByIndex'] = useEventCallback((event, index, jump) => {\n carouselApi.scrollToIndex(index, jump);\n\n onActiveIndexChange?.(event, { event, type: 'click', index });\n });\n\n const selectPageByDirection: CarouselContextValue['selectPageByDirection'] = useEventCallback((event, direction) => {\n const nextPageIndex = carouselApi.scrollInDirection(direction);\n onActiveIndexChange?.(event, { event, type: 'click', index: nextPageIndex });\n\n return nextPageIndex;\n });\n\n const mergedContainerRef = useMergedRefs(ref, containerRef);\n\n // Announce carousel updates\n const announcementTextRef = React.useRef<string>('');\n const totalNavLength = React.useRef<number>(0);\n const navGroupRef = React.useRef<number[][]>([]);\n\n const { announce } = useAnnounce();\n\n const updateAnnouncement = useEventCallback(() => {\n if (totalNavLength.current <= 0 || !announcement) {\n // Ignore announcements until slides discovered\n return;\n }\n\n const announcementText = announcement(activeIndex, totalNavLength.current, navGroupRef.current);\n\n if (announcementText !== announcementTextRef.current) {\n announcementTextRef.current = announcementText;\n announce(announcementText, { polite: true });\n }\n });\n\n useIsomorphicLayoutEffect(() => {\n // Subscribe to any non-index carousel state changes\n return subscribeForValues(data => {\n if (totalNavLength.current <= 0 && data.navItemsCount > 0 && announcement) {\n const announcementText = announcement(data.activeIndex, data.navItemsCount, data.groupIndexList);\n // Initialize our string to prevent updateAnnouncement from reading an initial load\n announcementTextRef.current = announcementText;\n }\n totalNavLength.current = data.navItemsCount;\n navGroupRef.current = data.groupIndexList;\n updateAnnouncement();\n });\n }, [subscribeForValues, updateAnnouncement, announcement]);\n\n useIsomorphicLayoutEffect(() => {\n updateAnnouncement();\n }, [activeIndex, updateAnnouncement]);\n\n return {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: mergedContainerRef,\n role: 'region',\n ...props,\n }),\n { elementType: 'div' },\n ),\n\n activeIndex,\n circular,\n containerRef: mergedContainerRef,\n viewportRef,\n selectPageByElement,\n selectPageByDirection,\n selectPageByIndex,\n subscribeForValues,\n enableAutoplay,\n resetAutoplay,\n };\n}\n"],"names":["useCarousel_unstable","props","ref","align","circular","onActiveIndexChange","groupSize","draggable","whitespace","announcement","motion","dir","useFluent","activeIndex","carouselApi","containerRef","viewportRef","subscribeForValues","enableAutoplay","resetAutoplay","useEmblaCarousel","direction","loop","slidesToScroll","defaultActiveIndex","watchDrag","containScroll","onDragIndexChange","selectPageByElement","useEventCallback","event","element","jump","foundIndex","scrollToElement","type","index","selectPageByIndex","scrollToIndex","selectPageByDirection","nextPageIndex","scrollInDirection","mergedContainerRef","useMergedRefs","announcementTextRef","React","useRef","totalNavLength","navGroupRef","announce","useAnnounce","updateAnnouncement","current","announcementText","polite","useIsomorphicLayoutEffect","data","navItemsCount","groupIndexList","components","root","slot","always","getIntrinsicElementProps","role","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../src/components/Carousel/useCarousel.ts"],"sourcesContent":["import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\nimport {\n getIntrinsicElementProps,\n slot,\n useEventCallback,\n useIsomorphicLayoutEffect,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselProps, CarouselState } from './Carousel.types';\nimport type { CarouselContextValue } from '../CarouselContext.types';\nimport { useEmblaCarousel } from '../useEmblaCarousel';\nimport { useAnnounce } from '@fluentui/react-shared-contexts';\n\n/**\n * Create the state required to render Carousel.\n *\n * The returned state can be modified with hooks such as useCarouselStyles_unstable,\n * before being passed to renderCarousel_unstable.\n *\n * @param props - props from this instance of Carousel\n * @param ref - reference to root HTMLDivElement of Carousel\n */\nexport function useCarousel_unstable(props: CarouselProps, ref: React.Ref<HTMLDivElement>): CarouselState {\n 'use no memo';\n\n const {\n align = 'center',\n circular = false,\n onActiveIndexChange,\n groupSize = 'auto',\n draggable = false,\n whitespace = false,\n announcement,\n motion = 'slide',\n } = props;\n\n const { dir } = useFluent();\n const { activeIndex, carouselApi, containerRef, viewportRef, subscribeForValues, enableAutoplay, resetAutoplay } =\n useEmblaCarousel({\n align,\n direction: dir,\n loop: circular,\n slidesToScroll: groupSize,\n defaultActiveIndex: props.defaultActiveIndex,\n activeIndex: props.activeIndex,\n watchDrag: draggable,\n containScroll: whitespace ? false : 'keepSnaps',\n motion,\n onDragIndexChange: onActiveIndexChange,\n onAutoplayIndexChange: onActiveIndexChange,\n });\n\n const selectPageByElement: CarouselContextValue['selectPageByElement'] = useEventCallback((event, element, jump) => {\n const foundIndex = carouselApi.scrollToElement(element, jump);\n onActiveIndexChange?.(event, { event, type: 'focus', index: foundIndex });\n\n return foundIndex;\n });\n\n const selectPageByIndex: CarouselContextValue['selectPageByIndex'] = useEventCallback((event, index, jump) => {\n carouselApi.scrollToIndex(index, jump);\n\n onActiveIndexChange?.(event, { event, type: 'click', index });\n });\n\n const selectPageByDirection: CarouselContextValue['selectPageByDirection'] = useEventCallback((event, direction) => {\n const nextPageIndex = carouselApi.scrollInDirection(direction);\n onActiveIndexChange?.(event, { event, type: 'click', index: nextPageIndex });\n\n return nextPageIndex;\n });\n\n const mergedContainerRef = useMergedRefs(ref, containerRef);\n\n // Announce carousel updates\n const announcementTextRef = React.useRef<string>('');\n const totalNavLength = React.useRef<number>(0);\n const navGroupRef = React.useRef<number[][]>([]);\n\n const { announce } = useAnnounce();\n\n const updateAnnouncement = useEventCallback(() => {\n if (totalNavLength.current <= 0 || !announcement) {\n // Ignore announcements until slides discovered\n return;\n }\n\n const announcementText = announcement(activeIndex, totalNavLength.current, navGroupRef.current);\n\n if (announcementText !== announcementTextRef.current) {\n announcementTextRef.current = announcementText;\n announce(announcementText, { polite: true });\n }\n });\n\n useIsomorphicLayoutEffect(() => {\n // Subscribe to any non-index carousel state changes\n return subscribeForValues(data => {\n if (totalNavLength.current <= 0 && data.navItemsCount > 0 && announcement) {\n const announcementText = announcement(data.activeIndex, data.navItemsCount, data.groupIndexList);\n // Initialize our string to prevent updateAnnouncement from reading an initial load\n announcementTextRef.current = announcementText;\n }\n totalNavLength.current = data.navItemsCount;\n navGroupRef.current = data.groupIndexList;\n updateAnnouncement();\n });\n }, [subscribeForValues, updateAnnouncement, announcement]);\n\n useIsomorphicLayoutEffect(() => {\n updateAnnouncement();\n }, [activeIndex, updateAnnouncement]);\n\n return {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: mergedContainerRef,\n role: 'region',\n ...props,\n }),\n { elementType: 'div' },\n ),\n\n activeIndex,\n circular,\n containerRef: mergedContainerRef,\n viewportRef,\n selectPageByElement,\n selectPageByDirection,\n selectPageByIndex,\n subscribeForValues,\n enableAutoplay,\n resetAutoplay,\n };\n}\n"],"names":["useCarousel_unstable","props","ref","align","circular","onActiveIndexChange","groupSize","draggable","whitespace","announcement","motion","dir","useFluent","activeIndex","carouselApi","containerRef","viewportRef","subscribeForValues","enableAutoplay","resetAutoplay","useEmblaCarousel","direction","loop","slidesToScroll","defaultActiveIndex","watchDrag","containScroll","onDragIndexChange","onAutoplayIndexChange","selectPageByElement","useEventCallback","event","element","jump","foundIndex","scrollToElement","type","index","selectPageByIndex","scrollToIndex","selectPageByDirection","nextPageIndex","scrollInDirection","mergedContainerRef","useMergedRefs","announcementTextRef","React","useRef","totalNavLength","navGroupRef","announce","useAnnounce","updateAnnouncement","current","announcementText","polite","useIsomorphicLayoutEffect","data","navItemsCount","groupIndexList","components","root","slot","always","getIntrinsicElementProps","role","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -23,16 +23,12 @@ const useCarouselAutoplayButton_unstable = (props, ref)=>{
23
23
  });
24
24
  const enableAutoplay = (0, _CarouselContext.useCarouselContext_unstable)((ctx)=>ctx.enableAutoplay);
25
25
  _react.useEffect(()=>{
26
+ // Initialize carousel autoplay based on button state
27
+ enableAutoplay(autoplay);
26
28
  return ()=>{
27
- // We disable autoplay if the button gets unmounted.
29
+ // We uninitialize autoplay if the button gets unmounted.
28
30
  enableAutoplay(false);
29
31
  };
30
- }, [
31
- enableAutoplay
32
- ]);
33
- (0, _reactutilities.useIsomorphicLayoutEffect)(()=>{
34
- // Enable/disable autoplay on state change
35
- enableAutoplay(autoplay);
36
32
  }, [
37
33
  autoplay,
38
34
  enableAutoplay
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/CarouselAutoplayButton/useCarouselAutoplayButton.tsx"],"sourcesContent":["import type { ARIAButtonElement } from '@fluentui/react-aria';\nimport { useToggleButton_unstable } from '@fluentui/react-button';\nimport { PlayCircleRegular, PauseCircleRegular } from '@fluentui/react-icons';\nimport {\n mergeCallbacks,\n slot,\n useControllableState,\n useEventCallback,\n useIsomorphicLayoutEffect,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselAutoplayButtonProps, CarouselAutoplayButtonState } from './CarouselAutoplayButton.types';\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\n\n/**\n * Create the state required to render CarouselAutoplayButton.\n *\n * The returned state can be modified with hooks such as useCarouselAutoplayButtonStyles_unstable,\n * before being passed to renderCarouselAutoplayButton_unstable.\n *\n * @param props - props from this instance of CarouselAutoplayButton\n * @param ref - reference to root HTMLDivElement of CarouselAutoplayButton\n */\nexport const useCarouselAutoplayButton_unstable = (\n props: CarouselAutoplayButtonProps,\n ref: React.Ref<ARIAButtonElement>,\n): CarouselAutoplayButtonState => {\n const { onCheckedChange, checked, defaultChecked } = props;\n\n const [autoplay, setAutoplay] = useControllableState({\n state: checked,\n defaultState: defaultChecked,\n initialState: false,\n });\n const enableAutoplay = useCarouselContext(ctx => ctx.enableAutoplay);\n\n React.useEffect(() => {\n return () => {\n // We disable autoplay if the button gets unmounted.\n enableAutoplay(false);\n };\n }, [enableAutoplay]);\n\n useIsomorphicLayoutEffect(() => {\n // Enable/disable autoplay on state change\n enableAutoplay(autoplay);\n }, [autoplay, enableAutoplay]);\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement & HTMLAnchorElement>) => {\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const newValue = !autoplay;\n\n setAutoplay(newValue);\n onCheckedChange?.(event, { event, type: 'click', checked: newValue });\n };\n\n return {\n // We lean on react-button class to handle styling and icon enhancements\n ...useToggleButton_unstable(\n {\n icon: slot.optional(props.icon, {\n defaultProps: {\n children: autoplay ? <PauseCircleRegular /> : <PlayCircleRegular />,\n },\n renderByDefault: true,\n elementType: 'span',\n }),\n ...props,\n checked: autoplay,\n onClick: useEventCallback(mergeCallbacks(handleClick, props.onClick)),\n },\n ref as React.Ref<HTMLButtonElement>,\n ),\n };\n};\n"],"names":["useCarouselAutoplayButton_unstable","props","ref","onCheckedChange","checked","defaultChecked","autoplay","setAutoplay","useControllableState","state","defaultState","initialState","enableAutoplay","useCarouselContext","ctx","React","useEffect","useIsomorphicLayoutEffect","handleClick","event","isDefaultPrevented","newValue","type","useToggleButton_unstable","icon","slot","optional","defaultProps","children","createElement","PauseCircleRegular","PlayCircleRegular","renderByDefault","elementType","onClick","useEventCallback","mergeCallbacks"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAwBaA;;;eAAAA;;;;6BAvB4B;4BACa;gCAO/C;iEACgB;iCAG2C;AAW3D,MAAMA,qCAAqC,CAChDC,OACAC;IAEA,MAAM,EAAEC,eAAe,EAAEC,OAAO,EAAEC,cAAc,EAAE,GAAGJ;IAErD,MAAM,CAACK,UAAUC,YAAY,GAAGC,IAAAA,oCAAAA,EAAqB;QACnDC,OAAOL;QACPM,cAAcL;QACdM,cAAc;IAChB;IACA,MAAMC,iBAAiBC,IAAAA,4CAAAA,EAAmBC,CAAAA,MAAOA,IAAIF,cAAc;IAEnEG,OAAMC,SAAS,CAAC;QACd,OAAO;YACL,oDAAoD;YACpDJ,eAAe;QACjB;IACF,GAAG;QAACA;KAAe;IAEnBK,IAAAA,yCAAAA,EAA0B;QACxB,0CAA0C;QAC1CL,eAAeN;IACjB,GAAG;QAACA;QAAUM;KAAe;IAE7B,MAAMM,cAAc,CAACC;QACnB,IAAIA,MAAMC,kBAAkB,IAAI;YAC9B;QACF;QAEA,MAAMC,WAAW,CAACf;QAElBC,YAAYc;QACZlB,oBAAAA,QAAAA,oBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,gBAAkBgB,OAAO;YAAEA;YAAOG,MAAM;YAASlB,SAASiB;QAAS;IACrE;IAEA,OAAO;QACL,wEAAwE;QACxE,GAAGE,IAAAA,qCAAAA,EACD;YACEC,MAAMC,oBAAAA,CAAKC,QAAQ,CAACzB,MAAMuB,IAAI,EAAE;gBAC9BG,cAAc;oBACZC,UAAUtB,WAAAA,WAAAA,GAAWS,OAAAc,aAAA,CAACC,8BAAAA,EAAAA,QAAAA,WAAAA,GAAwBf,OAAAc,aAAA,CAACE,6BAAAA,EAAAA;gBACjD;gBACAC,iBAAiB;gBACjBC,aAAa;YACf;YACA,GAAGhC,KAAK;YACRG,SAASE;YACT4B,SAASC,IAAAA,gCAAAA,EAAiBC,IAAAA,8BAAAA,EAAelB,aAAajB,MAAMiC,OAAO;QACrE,GACAhC,IACD;IACH;AACF"}
1
+ {"version":3,"sources":["../src/components/CarouselAutoplayButton/useCarouselAutoplayButton.tsx"],"sourcesContent":["import type { ARIAButtonElement } from '@fluentui/react-aria';\nimport { useToggleButton_unstable } from '@fluentui/react-button';\nimport { PlayCircleRegular, PauseCircleRegular } from '@fluentui/react-icons';\nimport { mergeCallbacks, slot, useControllableState, useEventCallback } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselAutoplayButtonProps, CarouselAutoplayButtonState } from './CarouselAutoplayButton.types';\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\n\n/**\n * Create the state required to render CarouselAutoplayButton.\n *\n * The returned state can be modified with hooks such as useCarouselAutoplayButtonStyles_unstable,\n * before being passed to renderCarouselAutoplayButton_unstable.\n *\n * @param props - props from this instance of CarouselAutoplayButton\n * @param ref - reference to root HTMLDivElement of CarouselAutoplayButton\n */\nexport const useCarouselAutoplayButton_unstable = (\n props: CarouselAutoplayButtonProps,\n ref: React.Ref<ARIAButtonElement>,\n): CarouselAutoplayButtonState => {\n const { onCheckedChange, checked, defaultChecked } = props;\n\n const [autoplay, setAutoplay] = useControllableState({\n state: checked,\n defaultState: defaultChecked,\n initialState: false,\n });\n const enableAutoplay = useCarouselContext(ctx => ctx.enableAutoplay);\n\n React.useEffect(() => {\n // Initialize carousel autoplay based on button state\n enableAutoplay(autoplay);\n\n return () => {\n // We uninitialize autoplay if the button gets unmounted.\n enableAutoplay(false);\n };\n }, [autoplay, enableAutoplay]);\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement & HTMLAnchorElement>) => {\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const newValue = !autoplay;\n\n setAutoplay(newValue);\n onCheckedChange?.(event, { event, type: 'click', checked: newValue });\n };\n\n return {\n // We lean on react-button class to handle styling and icon enhancements\n ...useToggleButton_unstable(\n {\n icon: slot.optional(props.icon, {\n defaultProps: {\n children: autoplay ? <PauseCircleRegular /> : <PlayCircleRegular />,\n },\n renderByDefault: true,\n elementType: 'span',\n }),\n ...props,\n checked: autoplay,\n onClick: useEventCallback(mergeCallbacks(handleClick, props.onClick)),\n },\n ref as React.Ref<HTMLButtonElement>,\n ),\n };\n};\n"],"names":["useCarouselAutoplayButton_unstable","props","ref","onCheckedChange","checked","defaultChecked","autoplay","setAutoplay","useControllableState","state","defaultState","initialState","enableAutoplay","useCarouselContext","ctx","React","useEffect","handleClick","event","isDefaultPrevented","newValue","type","useToggleButton_unstable","icon","slot","optional","defaultProps","children","createElement","PauseCircleRegular","PlayCircleRegular","renderByDefault","elementType","onClick","useEventCallback","mergeCallbacks"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAkBaA;;;eAAAA;;;;6BAjB4B;4BACa;gCACuB;iEACtD;iCAG2C;AAW3D,MAAMA,qCAAqC,CAChDC,OACAC;IAEA,MAAM,EAAEC,eAAe,EAAEC,OAAO,EAAEC,cAAc,EAAE,GAAGJ;IAErD,MAAM,CAACK,UAAUC,YAAY,GAAGC,IAAAA,oCAAAA,EAAqB;QACnDC,OAAOL;QACPM,cAAcL;QACdM,cAAc;IAChB;IACA,MAAMC,iBAAiBC,IAAAA,4CAAAA,EAAmBC,CAAAA,MAAOA,IAAIF,cAAc;IAEnEG,OAAMC,SAAS,CAAC;QACd,qDAAqD;QACrDJ,eAAeN;QAEf,OAAO;YACL,yDAAyD;YACzDM,eAAe;QACjB;IACF,GAAG;QAACN;QAAUM;KAAe;IAE7B,MAAMK,cAAc,CAACC;QACnB,IAAIA,MAAMC,kBAAkB,IAAI;YAC9B;QACF;QAEA,MAAMC,WAAW,CAACd;QAElBC,YAAYa;QACZjB,oBAAAA,QAAAA,oBAAAA,KAAAA,IAAAA,KAAAA,IAAAA,gBAAkBe,OAAO;YAAEA;YAAOG,MAAM;YAASjB,SAASgB;QAAS;IACrE;IAEA,OAAO;QACL,wEAAwE;QACxE,GAAGE,IAAAA,qCAAAA,EACD;YACEC,MAAMC,oBAAAA,CAAKC,QAAQ,CAACxB,MAAMsB,IAAI,EAAE;gBAC9BG,cAAc;oBACZC,UAAUrB,WAAAA,WAAAA,GAAWS,OAAAa,aAAA,CAACC,8BAAAA,EAAAA,QAAAA,WAAAA,GAAwBd,OAAAa,aAAA,CAACE,6BAAAA,EAAAA;gBACjD;gBACAC,iBAAiB;gBACjBC,aAAa;YACf;YACA,GAAG/B,KAAK;YACRG,SAASE;YACT2B,SAASC,IAAAA,gCAAAA,EAAiBC,IAAAA,8BAAAA,EAAelB,aAAahB,MAAMgC,OAAO;QACrE,GACA/B,IACD;IACH;AACF"}
@@ -21,7 +21,7 @@ const useCarouselButton_unstable = (props, ref)=>{
21
21
  // Locally tracks the total number of slides, will only update if this changes.
22
22
  const [totalSlides, setTotalSlides] = _react.useState(0);
23
23
  const { dir } = (0, _reactsharedcontexts.useFluent_unstable)();
24
- const buttonRef = (0, _react.useRef)();
24
+ const buttonRef = _react.useRef();
25
25
  const circular = (0, _CarouselContext.useCarouselContext_unstable)((ctx)=>ctx.circular);
26
26
  const containerRef = (0, _CarouselContext.useCarouselContext_unstable)((ctx)=>ctx.containerRef);
27
27
  const selectPageByDirection = (0, _CarouselContext.useCarouselContext_unstable)((ctx)=>ctx.selectPageByDirection);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/CarouselButton/useCarouselButton.tsx"],"sourcesContent":["import { type ARIAButtonElement } from '@fluentui/react-aria';\nimport { useButton_unstable } from '@fluentui/react-button';\nimport { ChevronLeftRegular, ChevronRightRegular } from '@fluentui/react-icons';\nimport {\n mergeCallbacks,\n useEventCallback,\n slot,\n useIsomorphicLayoutEffect,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\nimport type { CarouselButtonProps, CarouselButtonState } from './CarouselButton.types';\nimport type { CarouselUpdateData } from '../Carousel/Carousel.types';\nimport { carouselButtonClassNames } from './useCarouselButtonStyles.styles';\nimport { useRef } from 'react';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\n\n/**\n * Create the state required to render CarouselButton.\n *\n * The returned state can be modified with hooks such as useCarouselButtonStyles_unstable,\n * before being passed to renderCarouselButton_unstable.\n *\n * @param props - props from this instance of CarouselButton\n * @param ref - reference to root HTMLDivElement of CarouselButton\n */\nexport const useCarouselButton_unstable = (\n props: CarouselButtonProps,\n ref: React.Ref<ARIAButtonElement>,\n): CarouselButtonState => {\n const { navType = 'next' } = props;\n\n // Locally tracks the total number of slides, will only update if this changes.\n const [totalSlides, setTotalSlides] = React.useState(0);\n\n const { dir } = useFluent();\n const buttonRef = useRef<HTMLButtonElement>();\n const circular = useCarouselContext(ctx => ctx.circular);\n const containerRef = useCarouselContext(ctx => ctx.containerRef);\n const selectPageByDirection = useCarouselContext(ctx => ctx.selectPageByDirection);\n const subscribeForValues = useCarouselContext(ctx => ctx.subscribeForValues);\n const resetAutoplay = useCarouselContext(ctx => ctx.resetAutoplay);\n\n const isTrailing = useCarouselContext(ctx => {\n if (circular) {\n return false;\n }\n\n if (navType === 'prev') {\n return ctx.activeIndex === 0;\n }\n\n return ctx.activeIndex === totalSlides - 1;\n });\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement & HTMLAnchorElement>) => {\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const nextIndex = selectPageByDirection(event, navType);\n\n let _trailing = false;\n if (navType === 'prev') {\n _trailing = nextIndex === 0;\n } else {\n _trailing = nextIndex === totalSlides - 1;\n }\n\n if (!circular && _trailing && containerRef?.current) {\n // Focus non-disabled element\n const buttonRefs: NodeListOf<HTMLButtonElement> = containerRef.current.querySelectorAll(\n `.${carouselButtonClassNames.root}`,\n );\n buttonRefs.forEach(_buttonRef => {\n if (_buttonRef !== buttonRef.current) {\n _buttonRef.focus();\n }\n });\n }\n\n resetAutoplay();\n };\n\n useIsomorphicLayoutEffect(() => {\n return subscribeForValues((data: CarouselUpdateData) => {\n setTotalSlides(data.navItemsCount);\n });\n }, [subscribeForValues]);\n\n const nextArrowIcon = dir === 'ltr' ? <ChevronRightRegular /> : <ChevronLeftRegular />;\n const prevArrowIcon = dir === 'ltr' ? <ChevronLeftRegular /> : <ChevronRightRegular />;\n\n return {\n navType,\n // We lean on react-button class to handle styling and icon enhancements\n ...useButton_unstable(\n {\n icon: slot.optional(props.icon, {\n defaultProps: {\n children: navType === 'next' ? nextArrowIcon : prevArrowIcon,\n },\n renderByDefault: true,\n elementType: 'span',\n }),\n disabled: isTrailing,\n tabIndex: isTrailing ? -1 : 0,\n 'aria-disabled': isTrailing,\n appearance: 'subtle',\n ...props,\n onClick: useEventCallback(mergeCallbacks(handleClick, props.onClick)),\n },\n useMergedRefs(ref, buttonRef) as React.Ref<HTMLButtonElement>,\n ),\n };\n};\n"],"names":["useCarouselButton_unstable","props","ref","navType","totalSlides","setTotalSlides","React","useState","dir","useFluent","buttonRef","useRef","circular","useCarouselContext","ctx","containerRef","selectPageByDirection","subscribeForValues","resetAutoplay","isTrailing","activeIndex","handleClick","event","isDefaultPrevented","nextIndex","_trailing","current","buttonRefs","querySelectorAll","carouselButtonClassNames","root","forEach","_buttonRef","focus","useIsomorphicLayoutEffect","data","navItemsCount","nextArrowIcon","createElement","ChevronRightRegular","ChevronLeftRegular","prevArrowIcon","useButton_unstable","icon","slot","optional","defaultProps","children","renderByDefault","elementType","disabled","tabIndex","appearance","onClick","useEventCallback","mergeCallbacks","useMergedRefs"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
1
+ {"version":3,"sources":["../src/components/CarouselButton/useCarouselButton.tsx"],"sourcesContent":["import { type ARIAButtonElement } from '@fluentui/react-aria';\nimport { useButton_unstable } from '@fluentui/react-button';\nimport { ChevronLeftRegular, ChevronRightRegular } from '@fluentui/react-icons';\nimport {\n mergeCallbacks,\n useEventCallback,\n slot,\n useIsomorphicLayoutEffect,\n useMergedRefs,\n} from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\nimport type { CarouselButtonProps, CarouselButtonState } from './CarouselButton.types';\nimport type { CarouselUpdateData } from '../Carousel/Carousel.types';\nimport { carouselButtonClassNames } from './useCarouselButtonStyles.styles';\nimport { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';\n\n/**\n * Create the state required to render CarouselButton.\n *\n * The returned state can be modified with hooks such as useCarouselButtonStyles_unstable,\n * before being passed to renderCarouselButton_unstable.\n *\n * @param props - props from this instance of CarouselButton\n * @param ref - reference to root HTMLDivElement of CarouselButton\n */\nexport const useCarouselButton_unstable = (\n props: CarouselButtonProps,\n ref: React.Ref<ARIAButtonElement>,\n): CarouselButtonState => {\n const { navType = 'next' } = props;\n\n // Locally tracks the total number of slides, will only update if this changes.\n const [totalSlides, setTotalSlides] = React.useState(0);\n\n const { dir } = useFluent();\n const buttonRef = React.useRef<HTMLButtonElement>();\n const circular = useCarouselContext(ctx => ctx.circular);\n const containerRef = useCarouselContext(ctx => ctx.containerRef);\n const selectPageByDirection = useCarouselContext(ctx => ctx.selectPageByDirection);\n const subscribeForValues = useCarouselContext(ctx => ctx.subscribeForValues);\n const resetAutoplay = useCarouselContext(ctx => ctx.resetAutoplay);\n\n const isTrailing = useCarouselContext(ctx => {\n if (circular) {\n return false;\n }\n\n if (navType === 'prev') {\n return ctx.activeIndex === 0;\n }\n\n return ctx.activeIndex === totalSlides - 1;\n });\n\n const handleClick = (event: React.MouseEvent<HTMLButtonElement & HTMLAnchorElement>) => {\n if (event.isDefaultPrevented()) {\n return;\n }\n\n const nextIndex = selectPageByDirection(event, navType);\n\n let _trailing = false;\n if (navType === 'prev') {\n _trailing = nextIndex === 0;\n } else {\n _trailing = nextIndex === totalSlides - 1;\n }\n\n if (!circular && _trailing && containerRef?.current) {\n // Focus non-disabled element\n const buttonRefs: NodeListOf<HTMLButtonElement> = containerRef.current.querySelectorAll(\n `.${carouselButtonClassNames.root}`,\n );\n buttonRefs.forEach(_buttonRef => {\n if (_buttonRef !== buttonRef.current) {\n _buttonRef.focus();\n }\n });\n }\n\n resetAutoplay();\n };\n\n useIsomorphicLayoutEffect(() => {\n return subscribeForValues((data: CarouselUpdateData) => {\n setTotalSlides(data.navItemsCount);\n });\n }, [subscribeForValues]);\n\n const nextArrowIcon = dir === 'ltr' ? <ChevronRightRegular /> : <ChevronLeftRegular />;\n const prevArrowIcon = dir === 'ltr' ? <ChevronLeftRegular /> : <ChevronRightRegular />;\n\n return {\n navType,\n // We lean on react-button class to handle styling and icon enhancements\n ...useButton_unstable(\n {\n icon: slot.optional(props.icon, {\n defaultProps: {\n children: navType === 'next' ? nextArrowIcon : prevArrowIcon,\n },\n renderByDefault: true,\n elementType: 'span',\n }),\n disabled: isTrailing,\n tabIndex: isTrailing ? -1 : 0,\n 'aria-disabled': isTrailing,\n appearance: 'subtle',\n ...props,\n onClick: useEventCallback(mergeCallbacks(handleClick, props.onClick)),\n },\n useMergedRefs(ref, buttonRef) as React.Ref<HTMLButtonElement>,\n ),\n };\n};\n"],"names":["useCarouselButton_unstable","props","ref","navType","totalSlides","setTotalSlides","React","useState","dir","useFluent","buttonRef","useRef","circular","useCarouselContext","ctx","containerRef","selectPageByDirection","subscribeForValues","resetAutoplay","isTrailing","activeIndex","handleClick","event","isDefaultPrevented","nextIndex","_trailing","current","buttonRefs","querySelectorAll","carouselButtonClassNames","root","forEach","_buttonRef","focus","useIsomorphicLayoutEffect","data","navItemsCount","nextArrowIcon","createElement","ChevronRightRegular","ChevronLeftRegular","prevArrowIcon","useButton_unstable","icon","slot","optional","defaultProps","children","renderByDefault","elementType","disabled","tabIndex","appearance","onClick","useEventCallback","mergeCallbacks","useMergedRefs"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/CarouselContext.types.ts"],"sourcesContent":["import type { EventData } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselUpdateData } from '../Carousel';\n\nexport type CarouselIndexChangeData = (\n | EventData<'click', React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>>\n | EventData<'focus', React.FocusEvent>\n | EventData<'drag', PointerEvent | MouseEvent>\n) & {\n /**\n * The index to be set after event has occurred.\n */\n index: number;\n};\n\nexport type CarouselContextValue = {\n activeIndex: number;\n circular: boolean;\n selectPageByElement: (event: React.FocusEvent, element: HTMLElement, jump?: boolean) => number;\n selectPageByDirection: (\n event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>,\n direction: 'next' | 'prev',\n ) => number;\n selectPageByIndex: (\n event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>,\n value: number,\n jump?: boolean,\n ) => void;\n subscribeForValues: (listener: (data: CarouselUpdateData) => void) => () => void;\n enableAutoplay: (autoplay: boolean) => void;\n resetAutoplay: () => void;\n // Container with controls passed to carousel engine\n containerRef?: React.RefObject<HTMLDivElement>;\n // Viewport without controls used for interactive functionality (draggable, pause autoplay etc.)\n viewportRef?: React.RefObject<HTMLDivElement>;\n};\n\n/**\n * Context shared between Carousel and its children components\n */\nexport type CarouselContextValues = {\n carousel: CarouselContextValue;\n};\n"],"names":[],"rangeMappings":";;;;;","mappings":";;;;;iEACuB"}
1
+ {"version":3,"sources":["../src/components/CarouselContext.types.ts"],"sourcesContent":["import type { EventData } from '@fluentui/react-utilities';\nimport * as React from 'react';\n\nimport type { CarouselUpdateData } from '../Carousel';\n\nexport type CarouselIndexChangeData = (\n | EventData<'click', React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>>\n | EventData<'focus', React.FocusEvent>\n | EventData<'drag', PointerEvent | MouseEvent>\n | EventData<'autoplay', Event>\n) & {\n /**\n * The index to be set after event has occurred.\n */\n index: number;\n};\n\nexport type CarouselContextValue = {\n activeIndex: number;\n circular: boolean;\n selectPageByElement: (event: React.FocusEvent, element: HTMLElement, jump?: boolean) => number;\n selectPageByDirection: (\n event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>,\n direction: 'next' | 'prev',\n ) => number;\n selectPageByIndex: (\n event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>,\n value: number,\n jump?: boolean,\n ) => void;\n subscribeForValues: (listener: (data: CarouselUpdateData) => void) => () => void;\n enableAutoplay: (autoplay: boolean, temporary?: boolean) => void;\n resetAutoplay: () => void;\n // Container with controls passed to carousel engine\n containerRef?: React.RefObject<HTMLDivElement>;\n // Viewport without controls used for interactive functionality (draggable, pause autoplay etc.)\n viewportRef?: React.RefObject<HTMLDivElement>;\n};\n\n/**\n * Context shared between Carousel and its children components\n */\nexport type CarouselContextValues = {\n carousel: CarouselContextValue;\n};\n"],"names":[],"rangeMappings":";;;;;","mappings":";;;;;iEACuB"}
@@ -13,7 +13,46 @@ const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
13
13
  const _reactutilities = require("@fluentui/react-utilities");
14
14
  const _CarouselContext = require("../CarouselContext");
15
15
  const useCarouselViewport_unstable = (props, ref)=>{
16
+ const hasFocus = _react.useRef(false);
17
+ const hasMouse = _react.useRef(false);
16
18
  const viewportRef = (0, _CarouselContext.useCarouselContext_unstable)((ctx)=>ctx.viewportRef);
19
+ const enableAutoplay = (0, _CarouselContext.useCarouselContext_unstable)((ctx)=>ctx.enableAutoplay);
20
+ const handleFocusCapture = _react.useCallback((e)=>{
21
+ hasFocus.current = true;
22
+ // Will pause autoplay when focus is captured within viewport (if autoplay is initialized)
23
+ enableAutoplay(false, true);
24
+ }, [
25
+ enableAutoplay
26
+ ]);
27
+ const handleBlurCapture = _react.useCallback((e)=>{
28
+ // Will enable autoplay (if initialized) when focus exits viewport
29
+ if (!e.currentTarget.contains(e.relatedTarget)) {
30
+ hasFocus.current = false;
31
+ if (!hasMouse.current) {
32
+ enableAutoplay(true, true);
33
+ }
34
+ }
35
+ }, [
36
+ enableAutoplay
37
+ ]);
38
+ const handleMouseEnter = _react.useCallback((event)=>{
39
+ hasMouse.current = true;
40
+ enableAutoplay(false, true);
41
+ }, [
42
+ enableAutoplay
43
+ ]);
44
+ const handleMouseLeave = _react.useCallback((event)=>{
45
+ hasMouse.current = false;
46
+ if (!hasFocus.current) {
47
+ enableAutoplay(true, true);
48
+ }
49
+ }, [
50
+ enableAutoplay
51
+ ]);
52
+ const onFocusCapture = (0, _reactutilities.mergeCallbacks)(props.onFocusCapture, handleFocusCapture);
53
+ const onBlurCapture = (0, _reactutilities.mergeCallbacks)(props.onBlurCapture, handleBlurCapture);
54
+ const onMouseEnter = (0, _reactutilities.mergeCallbacks)(props.onMouseEnter, handleMouseEnter);
55
+ const onMouseLeave = (0, _reactutilities.mergeCallbacks)(props.onMouseLeave, handleMouseLeave);
17
56
  return {
18
57
  components: {
19
58
  root: 'div'
@@ -23,7 +62,11 @@ const useCarouselViewport_unstable = (props, ref)=>{
23
62
  role: 'presentation',
24
63
  // Draggable ensures dragging is supported (even if not enabled)
25
64
  draggable: true,
26
- ...props
65
+ ...props,
66
+ onFocusCapture,
67
+ onBlurCapture,
68
+ onMouseEnter,
69
+ onMouseLeave
27
70
  }), {
28
71
  elementType: 'div'
29
72
  })
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/CarouselViewport/useCarouselViewport.ts"],"sourcesContent":["import * as React from 'react';\nimport { getIntrinsicElementProps, slot, useMergedRefs } from '@fluentui/react-utilities';\nimport type { CarouselViewportProps, CarouselViewportState } from './CarouselViewport.types';\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\n\n/**\n * Create the state required to render CarouselViewport.\n *\n * The returned state can be modified with hooks such as useCarouselViewportStyles_unstable,\n * before being passed to renderCarouselViewport_unstable.\n *\n * @param props - props from this instance of CarouselViewport\n * @param ref - reference to root HTMLDivElement of CarouselViewport\n */\nexport const useCarouselViewport_unstable = (\n props: CarouselViewportProps,\n ref: React.Ref<HTMLDivElement>,\n): CarouselViewportState => {\n const viewportRef = useCarouselContext(ctx => ctx.viewportRef);\n\n return {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: useMergedRefs(ref, viewportRef),\n role: 'presentation',\n // Draggable ensures dragging is supported (even if not enabled)\n draggable: true,\n ...props,\n }),\n { elementType: 'div' },\n ),\n };\n};\n"],"names":["useCarouselViewport_unstable","props","ref","viewportRef","useCarouselContext","ctx","components","root","slot","always","getIntrinsicElementProps","useMergedRefs","role","draggable","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAcaA;;;eAAAA;;;;iEAdU;gCACuC;iCAEI;AAW3D,MAAMA,+BAA+B,CAC1CC,OACAC;IAEA,MAAMC,cAAcC,IAAAA,4CAAAA,EAAmBC,CAAAA,MAAOA,IAAIF,WAAW;IAE7D,OAAO;QACLG,YAAY;YACVC,MAAM;QACR;QACAA,MAAMC,oBAAAA,CAAKC,MAAM,CACfC,IAAAA,wCAAAA,EAAyB,OAAO;YAC9BR,KAAKS,IAAAA,6BAAAA,EAAcT,KAAKC;YACxBS,MAAM;YACN,gEAAgE;YAChEC,WAAW;YACX,GAAGZ,KAAK;QACV,IACA;YAAEa,aAAa;QAAM;IAEzB;AACF"}
1
+ {"version":3,"sources":["../src/components/CarouselViewport/useCarouselViewport.ts"],"sourcesContent":["import * as React from 'react';\nimport { getIntrinsicElementProps, mergeCallbacks, slot, useMergedRefs } from '@fluentui/react-utilities';\nimport type { CarouselViewportProps, CarouselViewportState } from './CarouselViewport.types';\nimport { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';\n\n/**\n * Create the state required to render CarouselViewport.\n *\n * The returned state can be modified with hooks such as useCarouselViewportStyles_unstable,\n * before being passed to renderCarouselViewport_unstable.\n *\n * @param props - props from this instance of CarouselViewport\n * @param ref - reference to root HTMLDivElement of CarouselViewport\n */\nexport const useCarouselViewport_unstable = (\n props: CarouselViewportProps,\n ref: React.Ref<HTMLDivElement>,\n): CarouselViewportState => {\n const hasFocus = React.useRef(false);\n const hasMouse = React.useRef(false);\n const viewportRef = useCarouselContext(ctx => ctx.viewportRef);\n const enableAutoplay = useCarouselContext(ctx => ctx.enableAutoplay);\n\n const handleFocusCapture = React.useCallback(\n (e: React.FocusEvent) => {\n hasFocus.current = true;\n // Will pause autoplay when focus is captured within viewport (if autoplay is initialized)\n enableAutoplay(false, true);\n },\n [enableAutoplay],\n );\n\n const handleBlurCapture = React.useCallback(\n (e: React.FocusEvent) => {\n // Will enable autoplay (if initialized) when focus exits viewport\n if (!e.currentTarget.contains(e.relatedTarget)) {\n hasFocus.current = false;\n if (!hasMouse.current) {\n enableAutoplay(true, true);\n }\n }\n },\n [enableAutoplay],\n );\n\n const handleMouseEnter = React.useCallback(\n (event: React.MouseEvent) => {\n hasMouse.current = true;\n enableAutoplay(false, true);\n },\n [enableAutoplay],\n );\n const handleMouseLeave = React.useCallback(\n (event: React.MouseEvent) => {\n hasMouse.current = false;\n if (!hasFocus.current) {\n enableAutoplay(true, true);\n }\n },\n [enableAutoplay],\n );\n\n const onFocusCapture = mergeCallbacks(props.onFocusCapture, handleFocusCapture);\n const onBlurCapture = mergeCallbacks(props.onBlurCapture, handleBlurCapture);\n const onMouseEnter = mergeCallbacks(props.onMouseEnter, handleMouseEnter);\n const onMouseLeave = mergeCallbacks(props.onMouseLeave, handleMouseLeave);\n\n return {\n components: {\n root: 'div',\n },\n root: slot.always(\n getIntrinsicElementProps('div', {\n ref: useMergedRefs(ref, viewportRef),\n role: 'presentation',\n // Draggable ensures dragging is supported (even if not enabled)\n draggable: true,\n ...props,\n onFocusCapture,\n onBlurCapture,\n onMouseEnter,\n onMouseLeave,\n }),\n { elementType: 'div' },\n ),\n };\n};\n"],"names":["useCarouselViewport_unstable","props","ref","hasFocus","React","useRef","hasMouse","viewportRef","useCarouselContext","ctx","enableAutoplay","handleFocusCapture","useCallback","e","current","handleBlurCapture","currentTarget","contains","relatedTarget","handleMouseEnter","event","handleMouseLeave","onFocusCapture","mergeCallbacks","onBlurCapture","onMouseEnter","onMouseLeave","components","root","slot","always","getIntrinsicElementProps","useMergedRefs","role","draggable","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":";;;;+BAcaA;;;eAAAA;;;;iEAdU;gCACuD;iCAEZ;AAW3D,MAAMA,+BAA+B,CAC1CC,OACAC;IAEA,MAAMC,WAAWC,OAAMC,MAAM,CAAC;IAC9B,MAAMC,WAAWF,OAAMC,MAAM,CAAC;IAC9B,MAAME,cAAcC,IAAAA,4CAAAA,EAAmBC,CAAAA,MAAOA,IAAIF,WAAW;IAC7D,MAAMG,iBAAiBF,IAAAA,4CAAAA,EAAmBC,CAAAA,MAAOA,IAAIC,cAAc;IAEnE,MAAMC,qBAAqBP,OAAMQ,WAAW,CAC1C,CAACC;QACCV,SAASW,OAAO,GAAG;QACnB,0FAA0F;QAC1FJ,eAAe,OAAO;IACxB,GACA;QAACA;KAAe;IAGlB,MAAMK,oBAAoBX,OAAMQ,WAAW,CACzC,CAACC;QACC,kEAAkE;QAClE,IAAI,CAACA,EAAEG,aAAa,CAACC,QAAQ,CAACJ,EAAEK,aAAa,GAAG;YAC9Cf,SAASW,OAAO,GAAG;YACnB,IAAI,CAACR,SAASQ,OAAO,EAAE;gBACrBJ,eAAe,MAAM;YACvB;QACF;IACF,GACA;QAACA;KAAe;IAGlB,MAAMS,mBAAmBf,OAAMQ,WAAW,CACxC,CAACQ;QACCd,SAASQ,OAAO,GAAG;QACnBJ,eAAe,OAAO;IACxB,GACA;QAACA;KAAe;IAElB,MAAMW,mBAAmBjB,OAAMQ,WAAW,CACxC,CAACQ;QACCd,SAASQ,OAAO,GAAG;QACnB,IAAI,CAACX,SAASW,OAAO,EAAE;YACrBJ,eAAe,MAAM;QACvB;IACF,GACA;QAACA;KAAe;IAGlB,MAAMY,iBAAiBC,IAAAA,8BAAAA,EAAetB,MAAMqB,cAAc,EAAEX;IAC5D,MAAMa,gBAAgBD,IAAAA,8BAAAA,EAAetB,MAAMuB,aAAa,EAAET;IAC1D,MAAMU,eAAeF,IAAAA,8BAAAA,EAAetB,MAAMwB,YAAY,EAAEN;IACxD,MAAMO,eAAeH,IAAAA,8BAAAA,EAAetB,MAAMyB,YAAY,EAAEL;IAExD,OAAO;QACLM,YAAY;YACVC,MAAM;QACR;QACAA,MAAMC,oBAAAA,CAAKC,MAAM,CACfC,IAAAA,wCAAAA,EAAyB,OAAO;YAC9B7B,KAAK8B,IAAAA,6BAAAA,EAAc9B,KAAKK;YACxB0B,MAAM;YACN,gEAAgE;YAChEC,WAAW;YACX,GAAGjC,KAAK;YACRqB;YACAE;YACAC;YACAC;QACF,IACA;YAAES,aAAa;QAAM;IAEzB;AACF"}
@@ -51,7 +51,7 @@ function setTabsterDefault(element, isDefault) {
51
51
  }
52
52
  }
53
53
  function useEmblaCarousel(options) {
54
- const { align, direction, loop, slidesToScroll, watchDrag, containScroll, motion, onDragIndexChange } = options;
54
+ const { align, direction, loop, slidesToScroll, watchDrag, containScroll, motion, onDragIndexChange, onAutoplayIndexChange } = options;
55
55
  const [activeIndex, setActiveIndex] = (0, _reactutilities.useControllableState)({
56
56
  defaultState: options.defaultActiveIndex,
57
57
  state: options.activeIndex,
@@ -76,32 +76,17 @@ function useEmblaCarousel(options) {
76
76
  const emblaApi = _react.useRef(null);
77
77
  const autoplayRef = _react.useRef(false);
78
78
  const resetAutoplay = _react.useCallback(()=>{
79
- var _emblaApi_current;
80
- (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.plugins().autoplay.reset();
79
+ var _emblaApi_current_plugins_autoplay, _emblaApi_current;
80
+ (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay = _emblaApi_current.plugins().autoplay) === null || _emblaApi_current_plugins_autoplay === void 0 ? void 0 : _emblaApi_current_plugins_autoplay.reset();
81
81
  }, []);
82
- /* Our autoplay button, which is required by standards for autoplay to be enabled, will handle controlled state */ const enableAutoplay = _react.useCallback((autoplay)=>{
83
- autoplayRef.current = autoplay;
84
- if (autoplay) {
85
- var _emblaApi_current;
86
- (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.plugins().autoplay.play();
87
- // Reset after play to ensure timing and any focus/mouse pause state is reset.
88
- resetAutoplay();
89
- } else {
90
- var _emblaApi_current1;
91
- (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.plugins().autoplay.stop();
92
- }
93
- }, [
94
- resetAutoplay
95
- ]);
96
82
  const getPlugins = _react.useCallback(()=>{
97
- const plugins = [
98
- (0, _emblacarouselautoplay.default)({
99
- playOnInit: autoplayRef.current,
100
- stopOnInteraction: !autoplayRef.current,
101
- stopOnMouseEnter: true,
102
- stopOnFocusIn: true
103
- })
104
- ];
83
+ const plugins = [];
84
+ plugins.push((0, _emblacarouselautoplay.default)({
85
+ playOnInit: autoplayRef.current,
86
+ /* stopOnInteraction: false causes autoplay to restart on interaction end*/ /* we'll handle this logic to ensure autoplay state is respected */ stopOnInteraction: true,
87
+ stopOnFocusIn: false,
88
+ stopOnMouseEnter: false
89
+ }));
105
90
  // Optionally add Fade plugin
106
91
  if (motion === 'fade') {
107
92
  plugins.push((0, _emblacarouselfade.default)());
@@ -117,6 +102,24 @@ function useEmblaCarousel(options) {
117
102
  onDragEvent,
118
103
  watchDrag
119
104
  ]);
105
+ /* This function enables autoplay to pause/play without affecting underlying state
106
+ * Useful for pausing on focus etc. without having to reinitialize or set autoplay to off
107
+ */ const enableAutoplay = _react.useCallback((autoplay, temporary)=>{
108
+ if (!temporary) {
109
+ autoplayRef.current = autoplay;
110
+ }
111
+ if (autoplay && autoplayRef.current) {
112
+ var _emblaApi_current_plugins_autoplay, _emblaApi_current;
113
+ (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay = _emblaApi_current.plugins().autoplay) === null || _emblaApi_current_plugins_autoplay === void 0 ? void 0 : _emblaApi_current_plugins_autoplay.play();
114
+ // Reset after play to ensure timing and any focus/mouse pause state is reset.
115
+ resetAutoplay();
116
+ } else if (!autoplay) {
117
+ var _emblaApi_current_plugins_autoplay1, _emblaApi_current1;
118
+ (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : (_emblaApi_current_plugins_autoplay1 = _emblaApi_current1.plugins().autoplay) === null || _emblaApi_current_plugins_autoplay1 === void 0 ? void 0 : _emblaApi_current_plugins_autoplay1.stop();
119
+ }
120
+ }, [
121
+ resetAutoplay
122
+ ]);
120
123
  // Listeners contains callbacks for UI elements that may require state update based on embla changes
121
124
  const listeners = _react.useRef(new Set());
122
125
  const subscribeForValues = _react.useCallback((listener)=>{
@@ -125,40 +128,49 @@ function useEmblaCarousel(options) {
125
128
  listeners.current.delete(listener);
126
129
  };
127
130
  }, []);
131
+ const handleReinit = (0, _reactutilities.useEventCallback)(()=>{
132
+ var _emblaApi_current, _emblaApi_current1, _emblaApi_current2, _emblaApi_current3;
133
+ var _emblaApi_current_slideNodes;
134
+ const nodes = (_emblaApi_current_slideNodes = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.slideNodes()) !== null && _emblaApi_current_slideNodes !== void 0 ? _emblaApi_current_slideNodes : [];
135
+ var _emblaApi_current_internalEngine_slideRegistry;
136
+ const groupIndexList = (_emblaApi_current_internalEngine_slideRegistry = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.internalEngine().slideRegistry) !== null && _emblaApi_current_internalEngine_slideRegistry !== void 0 ? _emblaApi_current_internalEngine_slideRegistry : [];
137
+ const navItemsCount = groupIndexList.length > 0 ? groupIndexList.length : nodes.length;
138
+ var _emblaApi_current_selectedScrollSnap;
139
+ const data = {
140
+ navItemsCount,
141
+ activeIndex: (_emblaApi_current_selectedScrollSnap = (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0,
142
+ groupIndexList,
143
+ slideNodes: nodes
144
+ };
145
+ (_emblaApi_current3 = emblaApi.current) === null || _emblaApi_current3 === void 0 ? void 0 : _emblaApi_current3.scrollTo(activeIndex, false);
146
+ for (const listener of listeners.current){
147
+ listener(data);
148
+ }
149
+ });
150
+ const handleIndexChange = (0, _reactutilities.useEventCallback)((_, eventType)=>{
151
+ var _emblaApi_current, _emblaApi_current1, _emblaApi_current2;
152
+ var _emblaApi_current_selectedScrollSnap;
153
+ const newIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
154
+ const slides = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.slideNodes();
155
+ var _emblaApi_current_internalEngine_slideRegistry_newIndex_;
156
+ const actualIndex = (_emblaApi_current_internalEngine_slideRegistry_newIndex_ = (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.internalEngine().slideRegistry[newIndex][0]) !== null && _emblaApi_current_internalEngine_slideRegistry_newIndex_ !== void 0 ? _emblaApi_current_internalEngine_slideRegistry_newIndex_ : 0;
157
+ // We set the active or first index of group on-screen as the selected tabster index
158
+ slides === null || slides === void 0 ? void 0 : slides.forEach((slide, slideIndex)=>{
159
+ setTabsterDefault(slide, slideIndex === actualIndex);
160
+ });
161
+ setActiveIndex(newIndex);
162
+ if (eventType === 'autoplay:select') {
163
+ const noopEvent = new Event('autoplay');
164
+ onAutoplayIndexChange === null || onAutoplayIndexChange === void 0 ? void 0 : onAutoplayIndexChange(noopEvent, {
165
+ event: noopEvent,
166
+ type: 'autoplay',
167
+ index: newIndex
168
+ });
169
+ }
170
+ });
128
171
  const viewportRef = _react.useRef(null);
129
172
  const containerRef = _react.useMemo(()=>{
130
173
  let currentElement = null;
131
- const handleIndexChange = ()=>{
132
- var _emblaApi_current, _emblaApi_current1, _emblaApi_current2;
133
- var _emblaApi_current_selectedScrollSnap;
134
- const newIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
135
- const slides = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.slideNodes();
136
- var _emblaApi_current_internalEngine_slideRegistry_newIndex_;
137
- const actualIndex = (_emblaApi_current_internalEngine_slideRegistry_newIndex_ = (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.internalEngine().slideRegistry[newIndex][0]) !== null && _emblaApi_current_internalEngine_slideRegistry_newIndex_ !== void 0 ? _emblaApi_current_internalEngine_slideRegistry_newIndex_ : 0;
138
- // We set the active or first index of group on-screen as the selected tabster index
139
- slides === null || slides === void 0 ? void 0 : slides.forEach((slide, slideIndex)=>{
140
- setTabsterDefault(slide, slideIndex === actualIndex);
141
- });
142
- setActiveIndex(newIndex);
143
- };
144
- const handleReinit = ()=>{
145
- var _emblaApi_current, _emblaApi_current1, _emblaApi_current2;
146
- var _emblaApi_current_slideNodes;
147
- const nodes = (_emblaApi_current_slideNodes = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.slideNodes()) !== null && _emblaApi_current_slideNodes !== void 0 ? _emblaApi_current_slideNodes : [];
148
- var _emblaApi_current_internalEngine_slideRegistry;
149
- const groupIndexList = (_emblaApi_current_internalEngine_slideRegistry = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.internalEngine().slideRegistry) !== null && _emblaApi_current_internalEngine_slideRegistry !== void 0 ? _emblaApi_current_internalEngine_slideRegistry : [];
150
- const navItemsCount = groupIndexList.length > 0 ? groupIndexList.length : nodes.length;
151
- var _emblaApi_current_selectedScrollSnap;
152
- const data = {
153
- navItemsCount,
154
- activeIndex: (_emblaApi_current_selectedScrollSnap = (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0,
155
- groupIndexList,
156
- slideNodes: nodes
157
- };
158
- for (const listener of listeners.current){
159
- listener(data);
160
- }
161
- };
162
174
  const handleVisibilityChange = ()=>{
163
175
  var _emblaApi_current, _emblaApi_current1;
164
176
  const cardElements = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.slideNodes();
@@ -173,35 +185,38 @@ function useEmblaCarousel(options) {
173
185
  }));
174
186
  });
175
187
  };
188
+ // Get plugins using autoplayRef to prevent state change recreating EmblaCarousel
176
189
  const plugins = getPlugins();
177
190
  return {
178
191
  set current (newElement){
179
192
  if (currentElement) {
180
- var _emblaApi_current, _emblaApi_current1, _emblaApi_current2, _emblaApi_current3;
193
+ var _emblaApi_current, _emblaApi_current1, _emblaApi_current2, _emblaApi_current3, _emblaApi_current4;
181
194
  (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.off('slidesInView', handleVisibilityChange);
182
195
  (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.off('select', handleIndexChange);
183
196
  (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.off('reInit', handleReinit);
184
- (_emblaApi_current3 = emblaApi.current) === null || _emblaApi_current3 === void 0 ? void 0 : _emblaApi_current3.destroy();
197
+ (_emblaApi_current3 = emblaApi.current) === null || _emblaApi_current3 === void 0 ? void 0 : _emblaApi_current3.off('autoplay:select', handleIndexChange);
198
+ (_emblaApi_current4 = emblaApi.current) === null || _emblaApi_current4 === void 0 ? void 0 : _emblaApi_current4.destroy();
185
199
  }
186
200
  var _viewportRef_current;
187
201
  // Use direct viewport if available, else fallback to container (includes Carousel controls).
188
- const wrapperElement = (_viewportRef_current = viewportRef.current) !== null && _viewportRef_current !== void 0 ? _viewportRef_current : newElement;
189
- if (wrapperElement) {
190
- var _emblaApi_current4, _emblaApi_current5, _emblaApi_current6;
191
- currentElement = wrapperElement;
192
- emblaApi.current = (0, _emblacarousel.default)(wrapperElement, {
202
+ currentElement = (_viewportRef_current = viewportRef.current) !== null && _viewportRef_current !== void 0 ? _viewportRef_current : newElement;
203
+ if (currentElement) {
204
+ var _emblaApi_current5, _emblaApi_current6, _emblaApi_current7, _emblaApi_current8;
205
+ emblaApi.current = (0, _emblacarousel.default)(currentElement, {
193
206
  ...DEFAULT_EMBLA_OPTIONS,
194
207
  ...emblaOptions.current
195
208
  }, plugins);
196
- (_emblaApi_current4 = emblaApi.current) === null || _emblaApi_current4 === void 0 ? void 0 : _emblaApi_current4.on('reInit', handleReinit);
197
- (_emblaApi_current5 = emblaApi.current) === null || _emblaApi_current5 === void 0 ? void 0 : _emblaApi_current5.on('slidesInView', handleVisibilityChange);
198
- (_emblaApi_current6 = emblaApi.current) === null || _emblaApi_current6 === void 0 ? void 0 : _emblaApi_current6.on('select', handleIndexChange);
209
+ (_emblaApi_current5 = emblaApi.current) === null || _emblaApi_current5 === void 0 ? void 0 : _emblaApi_current5.on('reInit', handleReinit);
210
+ (_emblaApi_current6 = emblaApi.current) === null || _emblaApi_current6 === void 0 ? void 0 : _emblaApi_current6.on('slidesInView', handleVisibilityChange);
211
+ (_emblaApi_current7 = emblaApi.current) === null || _emblaApi_current7 === void 0 ? void 0 : _emblaApi_current7.on('select', handleIndexChange);
212
+ (_emblaApi_current8 = emblaApi.current) === null || _emblaApi_current8 === void 0 ? void 0 : _emblaApi_current8.on('autoplay:select', handleIndexChange);
199
213
  }
200
214
  }
201
215
  };
202
216
  }, [
203
217
  getPlugins,
204
- setActiveIndex
218
+ handleIndexChange,
219
+ handleReinit
205
220
  ]);
206
221
  const carouselApi = _react.useMemo(()=>({
207
222
  scrollToElement: (element, jump)=>{
@@ -235,19 +250,6 @@ function useEmblaCarousel(options) {
235
250
  return (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
236
251
  }
237
252
  }), []);
238
- _react.useEffect(()=>{
239
- var _emblaApi_current;
240
- var _emblaApi_current_selectedScrollSnap;
241
- // Scroll to controlled values on update
242
- const currentActiveIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
243
- emblaOptions.current.startIndex = activeIndex;
244
- if (activeIndex !== currentActiveIndex) {
245
- var _emblaApi_current1;
246
- (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.scrollTo(activeIndex);
247
- }
248
- }, [
249
- activeIndex
250
- ]);
251
253
  _react.useEffect(()=>{
252
254
  var _emblaApi_current;
253
255
  const plugins = getPlugins();
@@ -266,12 +268,28 @@ function useEmblaCarousel(options) {
266
268
  }, plugins);
267
269
  }, [
268
270
  align,
271
+ containScroll,
269
272
  direction,
273
+ getPlugins,
270
274
  loop,
271
275
  slidesToScroll,
272
- watchDrag,
273
- containScroll,
274
- getPlugins
276
+ watchDrag
277
+ ]);
278
+ _react.useEffect(()=>{
279
+ var _emblaApi_current, _emblaApi_current_slideNodes, _emblaApi_current1;
280
+ var _emblaApi_current_selectedScrollSnap;
281
+ // Scroll to controlled values on update
282
+ // If active index is out of bounds, re-init will handle instead
283
+ const currentActiveIndex = (_emblaApi_current_selectedScrollSnap = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.selectedScrollSnap()) !== null && _emblaApi_current_selectedScrollSnap !== void 0 ? _emblaApi_current_selectedScrollSnap : 0;
284
+ var _emblaApi_current_slideNodes_length;
285
+ const slideLength = (_emblaApi_current_slideNodes_length = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : (_emblaApi_current_slideNodes = _emblaApi_current1.slideNodes()) === null || _emblaApi_current_slideNodes === void 0 ? void 0 : _emblaApi_current_slideNodes.length) !== null && _emblaApi_current_slideNodes_length !== void 0 ? _emblaApi_current_slideNodes_length : 0;
286
+ emblaOptions.current.startIndex = activeIndex;
287
+ if (activeIndex < slideLength && activeIndex !== currentActiveIndex) {
288
+ var _emblaApi_current2;
289
+ (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.scrollTo(activeIndex);
290
+ }
291
+ }, [
292
+ activeIndex
275
293
  ]);
276
294
  return {
277
295
  activeIndex,