@fluentui/react-carousel 9.3.1 → 9.4.1

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 +27 -2
  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 +82 -68
  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 +81 -68
  24. package/lib-commonjs/components/useEmblaCarousel.js.map +1 -1
  25. package/package.json +14 -13
package/CHANGELOG.md CHANGED
@@ -1,12 +1,37 @@
1
1
  # Change Log - @fluentui/react-carousel
2
2
 
3
- This log was last generated on Tue, 12 Nov 2024 09:30:42 GMT and should not be manually modified.
3
+ This log was last generated on Fri, 06 Dec 2024 12:49:19 GMT and should not be manually modified.
4
4
 
5
5
  <!-- Start content -->
6
6
 
7
+ ## [9.4.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-carousel_v9.4.1)
8
+
9
+ Fri, 06 Dec 2024 12:49:19 GMT
10
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-carousel_v9.4.0..@fluentui/react-carousel_v9.4.1)
11
+
12
+ ### Patches
13
+
14
+ - Bump @fluentui/react-aria to v9.13.10 ([PR #33414](https://github.com/microsoft/fluentui/pull/33414) by beachball)
15
+ - Bump @fluentui/react-button to v9.3.96 ([PR #33414](https://github.com/microsoft/fluentui/pull/33414) by beachball)
16
+ - Bump @fluentui/react-context-selector to v9.1.70 ([PR #33414](https://github.com/microsoft/fluentui/pull/33414) by beachball)
17
+ - Bump @fluentui/react-jsx-runtime to v9.0.47 ([PR #33414](https://github.com/microsoft/fluentui/pull/33414) by beachball)
18
+ - Bump @fluentui/react-shared-contexts to v9.21.1 ([PR #33414](https://github.com/microsoft/fluentui/pull/33414) by beachball)
19
+ - Bump @fluentui/react-tabster to v9.23.1 ([PR #33414](https://github.com/microsoft/fluentui/pull/33414) by beachball)
20
+ - Bump @fluentui/react-theme to v9.1.23 ([PR #33414](https://github.com/microsoft/fluentui/pull/33414) by beachball)
21
+ - Bump @fluentui/react-utilities to v9.18.18 ([PR #33414](https://github.com/microsoft/fluentui/pull/33414) by beachball)
22
+
23
+ ## [9.4.0](https://github.com/microsoft/fluentui/tree/@fluentui/react-carousel_v9.4.0)
24
+
25
+ Thu, 28 Nov 2024 09:30:49 GMT
26
+ [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-carousel_v9.3.1..@fluentui/react-carousel_v9.4.0)
27
+
28
+ ### Minor changes
29
+
30
+ - feat: Add autoplay index change callback and fix autoplay pause on interaction ([PR #33291](https://github.com/microsoft/fluentui/pull/33291) by mifraser@microsoft.com)
31
+
7
32
  ## [9.3.1](https://github.com/microsoft/fluentui/tree/@fluentui/react-carousel_v9.3.1)
8
33
 
9
- Tue, 12 Nov 2024 09:30:42 GMT
34
+ Tue, 12 Nov 2024 09:31:25 GMT
10
35
  [Compare changes](https://github.com/microsoft/fluentui/compare/@fluentui/react-carousel_v9.3.0..@fluentui/react-carousel_v9.3.1)
11
36
 
12
37
  ### Patches
package/dist/index.d.ts CHANGED
@@ -139,7 +139,7 @@ export declare type CarouselContextValue = {
139
139
  selectPageByDirection: (event: React_2.MouseEvent<HTMLButtonElement | HTMLAnchorElement>, direction: 'next' | 'prev') => number;
140
140
  selectPageByIndex: (event: React_2.MouseEvent<HTMLButtonElement | HTMLAnchorElement>, value: number, jump?: boolean) => void;
141
141
  subscribeForValues: (listener: (data: CarouselUpdateData) => void) => () => void;
142
- enableAutoplay: (autoplay: boolean) => void;
142
+ enableAutoplay: (autoplay: boolean, temporary?: boolean) => void;
143
143
  resetAutoplay: () => void;
144
144
  containerRef?: React_2.RefObject<HTMLDivElement>;
145
145
  viewportRef?: React_2.RefObject<HTMLDivElement>;
@@ -152,7 +152,7 @@ export declare type CarouselContextValues = {
152
152
  carousel: CarouselContextValue;
153
153
  };
154
154
 
155
- export declare type CarouselIndexChangeData = (EventData<'click', React_2.MouseEvent<HTMLButtonElement | HTMLAnchorElement>> | EventData<'focus', React_2.FocusEvent> | EventData<'drag', PointerEvent | MouseEvent>) & {
155
+ export declare type CarouselIndexChangeData = (EventData<'click', React_2.MouseEvent<HTMLButtonElement | HTMLAnchorElement>> | EventData<'focus', React_2.FocusEvent> | EventData<'drag', PointerEvent | MouseEvent> | EventData<'autoplay', Event>) & {
156
156
  /**
157
157
  * The index to be set after event has occurred.
158
158
  */
@@ -25,7 +25,8 @@ import { useAnnounce } from '@fluentui/react-shared-contexts';
25
25
  watchDrag: draggable,
26
26
  containScroll: whitespace ? false : 'keepSnaps',
27
27
  motion,
28
- onDragIndexChange: onActiveIndexChange
28
+ onDragIndexChange: onActiveIndexChange,
29
+ onAutoplayIndexChange: onActiveIndexChange
29
30
  });
30
31
  const selectPageByElement = useEventCallback((event, element, jump)=>{
31
32
  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":["useFluent_unstable","useFluent","getIntrinsicElementProps","slot","useEventCallback","useIsomorphicLayoutEffect","useMergedRefs","React","useEmblaCarousel","useAnnounce","useCarousel_unstable","props","ref","align","circular","onActiveIndexChange","groupSize","draggable","whitespace","announcement","motion","dir","activeIndex","carouselApi","containerRef","viewportRef","subscribeForValues","enableAutoplay","resetAutoplay","direction","loop","slidesToScroll","defaultActiveIndex","watchDrag","containScroll","onDragIndexChange","selectPageByElement","event","element","jump","foundIndex","scrollToElement","type","index","selectPageByIndex","scrollToIndex","selectPageByDirection","nextPageIndex","scrollInDirection","mergedContainerRef","announcementTextRef","useRef","totalNavLength","navGroupRef","announce","updateAnnouncement","current","announcementText","polite","data","navItemsCount","groupIndexList","components","root","always","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":["useFluent_unstable","useFluent","getIntrinsicElementProps","slot","useEventCallback","useIsomorphicLayoutEffect","useMergedRefs","React","useEmblaCarousel","useAnnounce","useCarousel_unstable","props","ref","align","circular","onActiveIndexChange","groupSize","draggable","whitespace","announcement","motion","dir","activeIndex","carouselApi","containerRef","viewportRef","subscribeForValues","enableAutoplay","resetAutoplay","direction","loop","slidesToScroll","defaultActiveIndex","watchDrag","containScroll","onDragIndexChange","onAutoplayIndexChange","selectPageByElement","event","element","jump","foundIndex","scrollToElement","type","index","selectPageByIndex","scrollToIndex","selectPageByDirection","nextPageIndex","scrollInDirection","mergedContainerRef","announcementTextRef","useRef","totalNavLength","navGroupRef","announce","updateAnnouncement","current","announcementText","polite","data","navItemsCount","groupIndexList","components","root","always","role","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { useToggleButton_unstable } from '@fluentui/react-button';
2
2
  import { PlayCircleRegular, PauseCircleRegular } from '@fluentui/react-icons';
3
- import { mergeCallbacks, slot, useControllableState, useEventCallback, useIsomorphicLayoutEffect } from '@fluentui/react-utilities';
3
+ import { mergeCallbacks, slot, useControllableState, useEventCallback } from '@fluentui/react-utilities';
4
4
  import * as React from 'react';
5
5
  import { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';
6
6
  /**
@@ -20,16 +20,12 @@ import { useCarouselContext_unstable as useCarouselContext } from '../CarouselCo
20
20
  });
21
21
  const enableAutoplay = useCarouselContext((ctx)=>ctx.enableAutoplay);
22
22
  React.useEffect(()=>{
23
+ // Initialize carousel autoplay based on button state
24
+ enableAutoplay(autoplay);
23
25
  return ()=>{
24
- // We disable autoplay if the button gets unmounted.
26
+ // We uninitialize autoplay if the button gets unmounted.
25
27
  enableAutoplay(false);
26
28
  };
27
- }, [
28
- enableAutoplay
29
- ]);
30
- useIsomorphicLayoutEffect(()=>{
31
- // Enable/disable autoplay on state change
32
- enableAutoplay(autoplay);
33
29
  }, [
34
30
  autoplay,
35
31
  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":["useToggleButton_unstable","PlayCircleRegular","PauseCircleRegular","mergeCallbacks","slot","useControllableState","useEventCallback","useIsomorphicLayoutEffect","React","useCarouselContext_unstable","useCarouselContext","useCarouselAutoplayButton_unstable","props","ref","onCheckedChange","checked","defaultChecked","autoplay","setAutoplay","state","defaultState","initialState","enableAutoplay","ctx","useEffect","handleClick","event","isDefaultPrevented","newValue","type","icon","optional","defaultProps","children","renderByDefault","elementType","onClick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,wBAAwB,QAAQ,yBAAyB;AAClE,SAASC,iBAAiB,EAAEC,kBAAkB,QAAQ,wBAAwB;AAC9E,SACEC,cAAc,EACdC,IAAI,EACJC,oBAAoB,EACpBC,gBAAgB,EAChBC,yBAAyB,QACpB,4BAA4B;AACnC,YAAYC,WAAW,QAAQ;AAG/B,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAEvF;;;;;;;;CAQC,GACD,OAAO,MAAMC,qCAAqC,CAChDC,OACAC;IAEA,MAAM,EAAEC,eAAe,EAAEC,OAAO,EAAEC,cAAc,EAAE,GAAGJ;IAErD,MAAM,CAACK,UAAUC,YAAY,GAAGb,qBAAqB;QACnDc,OAAOJ;QACPK,cAAcJ;QACdK,cAAc;IAChB;IACA,MAAMC,iBAAiBZ,mBAAmBa,CAAAA,MAAOA,IAAID,cAAc;IAEnEd,MAAMgB,SAAS,CAAC;QACd,OAAO;YACL,oDAAoD;YACpDF,eAAe;QACjB;IACF,GAAG;QAACA;KAAe;IAEnBf,0BAA0B;QACxB,0CAA0C;QAC1Ce,eAAeL;IACjB,GAAG;QAACA;QAAUK;KAAe;IAE7B,MAAMG,cAAc,CAACC;QACnB,IAAIA,MAAMC,kBAAkB,IAAI;YAC9B;QACF;QAEA,MAAMC,WAAW,CAACX;QAElBC,YAAYU;QACZd,4BAAAA,sCAAAA,gBAAkBY,OAAO;YAAEA;YAAOG,MAAM;YAASd,SAASa;QAAS;IACrE;IAEA,OAAO;QACL,wEAAwE;QACxE,GAAG5B,yBACD;YACE8B,MAAM1B,KAAK2B,QAAQ,CAACnB,MAAMkB,IAAI,EAAE;gBAC9BE,cAAc;oBACZC,UAAUhB,yBAAW,oBAACf,0CAAwB,oBAACD;gBACjD;gBACAiC,iBAAiB;gBACjBC,aAAa;YACf;YACA,GAAGvB,KAAK;YACRG,SAASE;YACTmB,SAAS9B,iBAAiBH,eAAesB,aAAab,MAAMwB,OAAO;QACrE,GACAvB,IACD;IACH;AACF,EAAE"}
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":["useToggleButton_unstable","PlayCircleRegular","PauseCircleRegular","mergeCallbacks","slot","useControllableState","useEventCallback","React","useCarouselContext_unstable","useCarouselContext","useCarouselAutoplayButton_unstable","props","ref","onCheckedChange","checked","defaultChecked","autoplay","setAutoplay","state","defaultState","initialState","enableAutoplay","ctx","useEffect","handleClick","event","isDefaultPrevented","newValue","type","icon","optional","defaultProps","children","renderByDefault","elementType","onClick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,wBAAwB,QAAQ,yBAAyB;AAClE,SAASC,iBAAiB,EAAEC,kBAAkB,QAAQ,wBAAwB;AAC9E,SAASC,cAAc,EAAEC,IAAI,EAAEC,oBAAoB,EAAEC,gBAAgB,QAAQ,4BAA4B;AACzG,YAAYC,WAAW,QAAQ;AAG/B,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAEvF;;;;;;;;CAQC,GACD,OAAO,MAAMC,qCAAqC,CAChDC,OACAC;IAEA,MAAM,EAAEC,eAAe,EAAEC,OAAO,EAAEC,cAAc,EAAE,GAAGJ;IAErD,MAAM,CAACK,UAAUC,YAAY,GAAGZ,qBAAqB;QACnDa,OAAOJ;QACPK,cAAcJ;QACdK,cAAc;IAChB;IACA,MAAMC,iBAAiBZ,mBAAmBa,CAAAA,MAAOA,IAAID,cAAc;IAEnEd,MAAMgB,SAAS,CAAC;QACd,qDAAqD;QACrDF,eAAeL;QAEf,OAAO;YACL,yDAAyD;YACzDK,eAAe;QACjB;IACF,GAAG;QAACL;QAAUK;KAAe;IAE7B,MAAMG,cAAc,CAACC;QACnB,IAAIA,MAAMC,kBAAkB,IAAI;YAC9B;QACF;QAEA,MAAMC,WAAW,CAACX;QAElBC,YAAYU;QACZd,4BAAAA,sCAAAA,gBAAkBY,OAAO;YAAEA;YAAOG,MAAM;YAASd,SAASa;QAAS;IACrE;IAEA,OAAO;QACL,wEAAwE;QACxE,GAAG3B,yBACD;YACE6B,MAAMzB,KAAK0B,QAAQ,CAACnB,MAAMkB,IAAI,EAAE;gBAC9BE,cAAc;oBACZC,UAAUhB,yBAAW,oBAACd,0CAAwB,oBAACD;gBACjD;gBACAgC,iBAAiB;gBACjBC,aAAa;YACf;YACA,GAAGvB,KAAK;YACRG,SAASE;YACTmB,SAAS7B,iBAAiBH,eAAeqB,aAAab,MAAMwB,OAAO;QACrE,GACAvB,IACD;IACH;AACF,EAAE"}
@@ -4,7 +4,6 @@ import { mergeCallbacks, useEventCallback, slot, useIsomorphicLayoutEffect, useM
4
4
  import * as React from 'react';
5
5
  import { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';
6
6
  import { carouselButtonClassNames } from './useCarouselButtonStyles.styles';
7
- import { useRef } from 'react';
8
7
  import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts';
9
8
  /**
10
9
  * Create the state required to render CarouselButton.
@@ -19,7 +18,7 @@ import { useFluent_unstable as useFluent } from '@fluentui/react-shared-contexts
19
18
  // Locally tracks the total number of slides, will only update if this changes.
20
19
  const [totalSlides, setTotalSlides] = React.useState(0);
21
20
  const { dir } = useFluent();
22
- const buttonRef = useRef();
21
+ const buttonRef = React.useRef();
23
22
  const circular = useCarouselContext((ctx)=>ctx.circular);
24
23
  const containerRef = useCarouselContext((ctx)=>ctx.containerRef);
25
24
  const selectPageByDirection = useCarouselContext((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":["useButton_unstable","ChevronLeftRegular","ChevronRightRegular","mergeCallbacks","useEventCallback","slot","useIsomorphicLayoutEffect","useMergedRefs","React","useCarouselContext_unstable","useCarouselContext","carouselButtonClassNames","useRef","useFluent_unstable","useFluent","useCarouselButton_unstable","props","ref","navType","totalSlides","setTotalSlides","useState","dir","buttonRef","circular","ctx","containerRef","selectPageByDirection","subscribeForValues","resetAutoplay","isTrailing","activeIndex","handleClick","event","isDefaultPrevented","nextIndex","_trailing","current","buttonRefs","querySelectorAll","root","forEach","_buttonRef","focus","data","navItemsCount","nextArrowIcon","prevArrowIcon","icon","optional","defaultProps","children","renderByDefault","elementType","disabled","tabIndex","appearance","onClick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,kBAAkB,QAAQ,yBAAyB;AAC5D,SAASC,kBAAkB,EAAEC,mBAAmB,QAAQ,wBAAwB;AAChF,SACEC,cAAc,EACdC,gBAAgB,EAChBC,IAAI,EACJC,yBAAyB,EACzBC,aAAa,QACR,4BAA4B;AACnC,YAAYC,WAAW,QAAQ;AAE/B,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAGvF,SAASC,wBAAwB,QAAQ,mCAAmC;AAC5E,SAASC,MAAM,QAAQ,QAAQ;AAC/B,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAElF;;;;;;;;CAQC,GACD,OAAO,MAAMC,6BAA6B,CACxCC,OACAC;IAEA,MAAM,EAAEC,UAAU,MAAM,EAAE,GAAGF;IAE7B,+EAA+E;IAC/E,MAAM,CAACG,aAAaC,eAAe,GAAGZ,MAAMa,QAAQ,CAAC;IAErD,MAAM,EAAEC,GAAG,EAAE,GAAGR;IAChB,MAAMS,YAAYX;IAClB,MAAMY,WAAWd,mBAAmBe,CAAAA,MAAOA,IAAID,QAAQ;IACvD,MAAME,eAAehB,mBAAmBe,CAAAA,MAAOA,IAAIC,YAAY;IAC/D,MAAMC,wBAAwBjB,mBAAmBe,CAAAA,MAAOA,IAAIE,qBAAqB;IACjF,MAAMC,qBAAqBlB,mBAAmBe,CAAAA,MAAOA,IAAIG,kBAAkB;IAC3E,MAAMC,gBAAgBnB,mBAAmBe,CAAAA,MAAOA,IAAII,aAAa;IAEjE,MAAMC,aAAapB,mBAAmBe,CAAAA;QACpC,IAAID,UAAU;YACZ,OAAO;QACT;QAEA,IAAIN,YAAY,QAAQ;YACtB,OAAOO,IAAIM,WAAW,KAAK;QAC7B;QAEA,OAAON,IAAIM,WAAW,KAAKZ,cAAc;IAC3C;IAEA,MAAMa,cAAc,CAACC;QACnB,IAAIA,MAAMC,kBAAkB,IAAI;YAC9B;QACF;QAEA,MAAMC,YAAYR,sBAAsBM,OAAOf;QAE/C,IAAIkB,YAAY;QAChB,IAAIlB,YAAY,QAAQ;YACtBkB,YAAYD,cAAc;QAC5B,OAAO;YACLC,YAAYD,cAAchB,cAAc;QAC1C;QAEA,IAAI,CAACK,YAAYY,cAAaV,yBAAAA,mCAAAA,aAAcW,OAAO,GAAE;YACnD,6BAA6B;YAC7B,MAAMC,aAA4CZ,aAAaW,OAAO,CAACE,gBAAgB,CACrF,CAAC,CAAC,EAAE5B,yBAAyB6B,IAAI,CAAC,CAAC;YAErCF,WAAWG,OAAO,CAACC,CAAAA;gBACjB,IAAIA,eAAenB,UAAUc,OAAO,EAAE;oBACpCK,WAAWC,KAAK;gBAClB;YACF;QACF;QAEAd;IACF;IAEAvB,0BAA0B;QACxB,OAAOsB,mBAAmB,CAACgB;YACzBxB,eAAewB,KAAKC,aAAa;QACnC;IACF,GAAG;QAACjB;KAAmB;IAEvB,MAAMkB,gBAAgBxB,QAAQ,sBAAQ,oBAACpB,2CAAyB,oBAACD;IACjE,MAAM8C,gBAAgBzB,QAAQ,sBAAQ,oBAACrB,0CAAwB,oBAACC;IAEhE,OAAO;QACLgB;QACA,wEAAwE;QACxE,GAAGlB,mBACD;YACEgD,MAAM3C,KAAK4C,QAAQ,CAACjC,MAAMgC,IAAI,EAAE;gBAC9BE,cAAc;oBACZC,UAAUjC,YAAY,SAAS4B,gBAAgBC;gBACjD;gBACAK,iBAAiB;gBACjBC,aAAa;YACf;YACAC,UAAUxB;YACVyB,UAAUzB,aAAa,CAAC,IAAI;YAC5B,iBAAiBA;YACjB0B,YAAY;YACZ,GAAGxC,KAAK;YACRyC,SAASrD,iBAAiBD,eAAe6B,aAAahB,MAAMyC,OAAO;QACrE,GACAlD,cAAcU,KAAKM,WACpB;IACH;AACF,EAAE"}
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":["useButton_unstable","ChevronLeftRegular","ChevronRightRegular","mergeCallbacks","useEventCallback","slot","useIsomorphicLayoutEffect","useMergedRefs","React","useCarouselContext_unstable","useCarouselContext","carouselButtonClassNames","useFluent_unstable","useFluent","useCarouselButton_unstable","props","ref","navType","totalSlides","setTotalSlides","useState","dir","buttonRef","useRef","circular","ctx","containerRef","selectPageByDirection","subscribeForValues","resetAutoplay","isTrailing","activeIndex","handleClick","event","isDefaultPrevented","nextIndex","_trailing","current","buttonRefs","querySelectorAll","root","forEach","_buttonRef","focus","data","navItemsCount","nextArrowIcon","prevArrowIcon","icon","optional","defaultProps","children","renderByDefault","elementType","disabled","tabIndex","appearance","onClick"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AACA,SAASA,kBAAkB,QAAQ,yBAAyB;AAC5D,SAASC,kBAAkB,EAAEC,mBAAmB,QAAQ,wBAAwB;AAChF,SACEC,cAAc,EACdC,gBAAgB,EAChBC,IAAI,EACJC,yBAAyB,EACzBC,aAAa,QACR,4BAA4B;AACnC,YAAYC,WAAW,QAAQ;AAE/B,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAGvF,SAASC,wBAAwB,QAAQ,mCAAmC;AAC5E,SAASC,sBAAsBC,SAAS,QAAQ,kCAAkC;AAElF;;;;;;;;CAQC,GACD,OAAO,MAAMC,6BAA6B,CACxCC,OACAC;IAEA,MAAM,EAAEC,UAAU,MAAM,EAAE,GAAGF;IAE7B,+EAA+E;IAC/E,MAAM,CAACG,aAAaC,eAAe,GAAGX,MAAMY,QAAQ,CAAC;IAErD,MAAM,EAAEC,GAAG,EAAE,GAAGR;IAChB,MAAMS,YAAYd,MAAMe,MAAM;IAC9B,MAAMC,WAAWd,mBAAmBe,CAAAA,MAAOA,IAAID,QAAQ;IACvD,MAAME,eAAehB,mBAAmBe,CAAAA,MAAOA,IAAIC,YAAY;IAC/D,MAAMC,wBAAwBjB,mBAAmBe,CAAAA,MAAOA,IAAIE,qBAAqB;IACjF,MAAMC,qBAAqBlB,mBAAmBe,CAAAA,MAAOA,IAAIG,kBAAkB;IAC3E,MAAMC,gBAAgBnB,mBAAmBe,CAAAA,MAAOA,IAAII,aAAa;IAEjE,MAAMC,aAAapB,mBAAmBe,CAAAA;QACpC,IAAID,UAAU;YACZ,OAAO;QACT;QAEA,IAAIP,YAAY,QAAQ;YACtB,OAAOQ,IAAIM,WAAW,KAAK;QAC7B;QAEA,OAAON,IAAIM,WAAW,KAAKb,cAAc;IAC3C;IAEA,MAAMc,cAAc,CAACC;QACnB,IAAIA,MAAMC,kBAAkB,IAAI;YAC9B;QACF;QAEA,MAAMC,YAAYR,sBAAsBM,OAAOhB;QAE/C,IAAImB,YAAY;QAChB,IAAInB,YAAY,QAAQ;YACtBmB,YAAYD,cAAc;QAC5B,OAAO;YACLC,YAAYD,cAAcjB,cAAc;QAC1C;QAEA,IAAI,CAACM,YAAYY,cAAaV,yBAAAA,mCAAAA,aAAcW,OAAO,GAAE;YACnD,6BAA6B;YAC7B,MAAMC,aAA4CZ,aAAaW,OAAO,CAACE,gBAAgB,CACrF,CAAC,CAAC,EAAE5B,yBAAyB6B,IAAI,CAAC,CAAC;YAErCF,WAAWG,OAAO,CAACC,CAAAA;gBACjB,IAAIA,eAAepB,UAAUe,OAAO,EAAE;oBACpCK,WAAWC,KAAK;gBAClB;YACF;QACF;QAEAd;IACF;IAEAvB,0BAA0B;QACxB,OAAOsB,mBAAmB,CAACgB;YACzBzB,eAAeyB,KAAKC,aAAa;QACnC;IACF,GAAG;QAACjB;KAAmB;IAEvB,MAAMkB,gBAAgBzB,QAAQ,sBAAQ,oBAACnB,2CAAyB,oBAACD;IACjE,MAAM8C,gBAAgB1B,QAAQ,sBAAQ,oBAACpB,0CAAwB,oBAACC;IAEhE,OAAO;QACLe;QACA,wEAAwE;QACxE,GAAGjB,mBACD;YACEgD,MAAM3C,KAAK4C,QAAQ,CAAClC,MAAMiC,IAAI,EAAE;gBAC9BE,cAAc;oBACZC,UAAUlC,YAAY,SAAS6B,gBAAgBC;gBACjD;gBACAK,iBAAiB;gBACjBC,aAAa;YACf;YACAC,UAAUxB;YACVyB,UAAUzB,aAAa,CAAC,IAAI;YAC5B,iBAAiBA;YACjB0B,YAAY;YACZ,GAAGzC,KAAK;YACR0C,SAASrD,iBAAiBD,eAAe6B,aAAajB,MAAM0C,OAAO;QACrE,GACAlD,cAAcS,KAAKM,WACpB;IACH;AACF,EAAE"}
@@ -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":["React"],"rangeMappings":"","mappings":"AACA,YAAYA,WAAW,QAAQ"}
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":["React"],"rangeMappings":"","mappings":"AACA,YAAYA,WAAW,QAAQ"}
@@ -1,5 +1,5 @@
1
1
  import * as React from 'react';
2
- import { getIntrinsicElementProps, slot, useMergedRefs } from '@fluentui/react-utilities';
2
+ import { getIntrinsicElementProps, mergeCallbacks, slot, useMergedRefs } from '@fluentui/react-utilities';
3
3
  import { useCarouselContext_unstable as useCarouselContext } from '../CarouselContext';
4
4
  /**
5
5
  * Create the state required to render CarouselViewport.
@@ -10,7 +10,46 @@ import { useCarouselContext_unstable as useCarouselContext } from '../CarouselCo
10
10
  * @param props - props from this instance of CarouselViewport
11
11
  * @param ref - reference to root HTMLDivElement of CarouselViewport
12
12
  */ export const useCarouselViewport_unstable = (props, ref)=>{
13
+ const hasFocus = React.useRef(false);
14
+ const hasMouse = React.useRef(false);
13
15
  const viewportRef = useCarouselContext((ctx)=>ctx.viewportRef);
16
+ const enableAutoplay = useCarouselContext((ctx)=>ctx.enableAutoplay);
17
+ const handleFocusCapture = React.useCallback((e)=>{
18
+ hasFocus.current = true;
19
+ // Will pause autoplay when focus is captured within viewport (if autoplay is initialized)
20
+ enableAutoplay(false, true);
21
+ }, [
22
+ enableAutoplay
23
+ ]);
24
+ const handleBlurCapture = React.useCallback((e)=>{
25
+ // Will enable autoplay (if initialized) when focus exits viewport
26
+ if (!e.currentTarget.contains(e.relatedTarget)) {
27
+ hasFocus.current = false;
28
+ if (!hasMouse.current) {
29
+ enableAutoplay(true, true);
30
+ }
31
+ }
32
+ }, [
33
+ enableAutoplay
34
+ ]);
35
+ const handleMouseEnter = React.useCallback((event)=>{
36
+ hasMouse.current = true;
37
+ enableAutoplay(false, true);
38
+ }, [
39
+ enableAutoplay
40
+ ]);
41
+ const handleMouseLeave = React.useCallback((event)=>{
42
+ hasMouse.current = false;
43
+ if (!hasFocus.current) {
44
+ enableAutoplay(true, true);
45
+ }
46
+ }, [
47
+ enableAutoplay
48
+ ]);
49
+ const onFocusCapture = mergeCallbacks(props.onFocusCapture, handleFocusCapture);
50
+ const onBlurCapture = mergeCallbacks(props.onBlurCapture, handleBlurCapture);
51
+ const onMouseEnter = mergeCallbacks(props.onMouseEnter, handleMouseEnter);
52
+ const onMouseLeave = mergeCallbacks(props.onMouseLeave, handleMouseLeave);
14
53
  return {
15
54
  components: {
16
55
  root: 'div'
@@ -20,7 +59,11 @@ import { useCarouselContext_unstable as useCarouselContext } from '../CarouselCo
20
59
  role: 'presentation',
21
60
  // Draggable ensures dragging is supported (even if not enabled)
22
61
  draggable: true,
23
- ...props
62
+ ...props,
63
+ onFocusCapture,
64
+ onBlurCapture,
65
+ onMouseEnter,
66
+ onMouseLeave
24
67
  }), {
25
68
  elementType: 'div'
26
69
  })
@@ -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":["React","getIntrinsicElementProps","slot","useMergedRefs","useCarouselContext_unstable","useCarouselContext","useCarouselViewport_unstable","props","ref","viewportRef","ctx","components","root","always","role","draggable","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,wBAAwB,EAAEC,IAAI,EAAEC,aAAa,QAAQ,4BAA4B;AAE1F,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAEvF;;;;;;;;CAQC,GACD,OAAO,MAAMC,+BAA+B,CAC1CC,OACAC;IAEA,MAAMC,cAAcJ,mBAAmBK,CAAAA,MAAOA,IAAID,WAAW;IAE7D,OAAO;QACLE,YAAY;YACVC,MAAM;QACR;QACAA,MAAMV,KAAKW,MAAM,CACfZ,yBAAyB,OAAO;YAC9BO,KAAKL,cAAcK,KAAKC;YACxBK,MAAM;YACN,gEAAgE;YAChEC,WAAW;YACX,GAAGR,KAAK;QACV,IACA;YAAES,aAAa;QAAM;IAEzB;AACF,EAAE"}
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":["React","getIntrinsicElementProps","mergeCallbacks","slot","useMergedRefs","useCarouselContext_unstable","useCarouselContext","useCarouselViewport_unstable","props","ref","hasFocus","useRef","hasMouse","viewportRef","ctx","enableAutoplay","handleFocusCapture","useCallback","e","current","handleBlurCapture","currentTarget","contains","relatedTarget","handleMouseEnter","event","handleMouseLeave","onFocusCapture","onBlurCapture","onMouseEnter","onMouseLeave","components","root","always","role","draggable","elementType"],"rangeMappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;","mappings":"AAAA,YAAYA,WAAW,QAAQ;AAC/B,SAASC,wBAAwB,EAAEC,cAAc,EAAEC,IAAI,EAAEC,aAAa,QAAQ,4BAA4B;AAE1G,SAASC,+BAA+BC,kBAAkB,QAAQ,qBAAqB;AAEvF;;;;;;;;CAQC,GACD,OAAO,MAAMC,+BAA+B,CAC1CC,OACAC;IAEA,MAAMC,WAAWV,MAAMW,MAAM,CAAC;IAC9B,MAAMC,WAAWZ,MAAMW,MAAM,CAAC;IAC9B,MAAME,cAAcP,mBAAmBQ,CAAAA,MAAOA,IAAID,WAAW;IAC7D,MAAME,iBAAiBT,mBAAmBQ,CAAAA,MAAOA,IAAIC,cAAc;IAEnE,MAAMC,qBAAqBhB,MAAMiB,WAAW,CAC1C,CAACC;QACCR,SAASS,OAAO,GAAG;QACnB,0FAA0F;QAC1FJ,eAAe,OAAO;IACxB,GACA;QAACA;KAAe;IAGlB,MAAMK,oBAAoBpB,MAAMiB,WAAW,CACzC,CAACC;QACC,kEAAkE;QAClE,IAAI,CAACA,EAAEG,aAAa,CAACC,QAAQ,CAACJ,EAAEK,aAAa,GAAG;YAC9Cb,SAASS,OAAO,GAAG;YACnB,IAAI,CAACP,SAASO,OAAO,EAAE;gBACrBJ,eAAe,MAAM;YACvB;QACF;IACF,GACA;QAACA;KAAe;IAGlB,MAAMS,mBAAmBxB,MAAMiB,WAAW,CACxC,CAACQ;QACCb,SAASO,OAAO,GAAG;QACnBJ,eAAe,OAAO;IACxB,GACA;QAACA;KAAe;IAElB,MAAMW,mBAAmB1B,MAAMiB,WAAW,CACxC,CAACQ;QACCb,SAASO,OAAO,GAAG;QACnB,IAAI,CAACT,SAASS,OAAO,EAAE;YACrBJ,eAAe,MAAM;QACvB;IACF,GACA;QAACA;KAAe;IAGlB,MAAMY,iBAAiBzB,eAAeM,MAAMmB,cAAc,EAAEX;IAC5D,MAAMY,gBAAgB1B,eAAeM,MAAMoB,aAAa,EAAER;IAC1D,MAAMS,eAAe3B,eAAeM,MAAMqB,YAAY,EAAEL;IACxD,MAAMM,eAAe5B,eAAeM,MAAMsB,YAAY,EAAEJ;IAExD,OAAO;QACLK,YAAY;YACVC,MAAM;QACR;QACAA,MAAM7B,KAAK8B,MAAM,CACfhC,yBAAyB,OAAO;YAC9BQ,KAAKL,cAAcK,KAAKI;YACxBqB,MAAM;YACN,gEAAgE;YAChEC,WAAW;YACX,GAAG3B,KAAK;YACRmB;YACAC;YACAC;YACAC;QACF,IACA;YAAEM,aAAa;QAAM;IAEzB;AACF,EAAE"}
@@ -28,7 +28,7 @@ export function setTabsterDefault(element, isDefault) {
28
28
  }
29
29
  }
30
30
  export function useEmblaCarousel(options) {
31
- const { align, direction, loop, slidesToScroll, watchDrag, containScroll, motion, onDragIndexChange } = options;
31
+ const { align, direction, loop, slidesToScroll, watchDrag, containScroll, motion, onDragIndexChange, onAutoplayIndexChange } = options;
32
32
  const [activeIndex, setActiveIndex] = useControllableState({
33
33
  defaultState: options.defaultActiveIndex,
34
34
  state: options.activeIndex,
@@ -53,32 +53,17 @@ export function useEmblaCarousel(options) {
53
53
  const emblaApi = React.useRef(null);
54
54
  const autoplayRef = React.useRef(false);
55
55
  const resetAutoplay = React.useCallback(()=>{
56
- var _emblaApi_current;
57
- (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.plugins().autoplay.reset();
56
+ var _emblaApi_current_plugins_autoplay, _emblaApi_current;
57
+ (_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();
58
58
  }, []);
59
- /* Our autoplay button, which is required by standards for autoplay to be enabled, will handle controlled state */ const enableAutoplay = React.useCallback((autoplay)=>{
60
- autoplayRef.current = autoplay;
61
- if (autoplay) {
62
- var _emblaApi_current;
63
- (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.plugins().autoplay.play();
64
- // Reset after play to ensure timing and any focus/mouse pause state is reset.
65
- resetAutoplay();
66
- } else {
67
- var _emblaApi_current1;
68
- (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.plugins().autoplay.stop();
69
- }
70
- }, [
71
- resetAutoplay
72
- ]);
73
59
  const getPlugins = React.useCallback(()=>{
74
- const plugins = [
75
- Autoplay({
76
- playOnInit: autoplayRef.current,
77
- stopOnInteraction: !autoplayRef.current,
78
- stopOnMouseEnter: true,
79
- stopOnFocusIn: true
80
- })
81
- ];
60
+ const plugins = [];
61
+ plugins.push(Autoplay({
62
+ playOnInit: autoplayRef.current,
63
+ /* stopOnInteraction: false causes autoplay to restart on interaction end*/ /* we'll handle this logic to ensure autoplay state is respected */ stopOnInteraction: true,
64
+ stopOnFocusIn: false,
65
+ stopOnMouseEnter: false
66
+ }));
82
67
  // Optionally add Fade plugin
83
68
  if (motion === 'fade') {
84
69
  plugins.push(Fade());
@@ -94,6 +79,25 @@ export function useEmblaCarousel(options) {
94
79
  onDragEvent,
95
80
  watchDrag
96
81
  ]);
82
+ /* This function enables autoplay to pause/play without affecting underlying state
83
+ * Useful for pausing on focus etc. without having to reinitialize or set autoplay to off
84
+ */ const enableAutoplay = React.useCallback((autoplay, temporary)=>{
85
+ if (!temporary) {
86
+ autoplayRef.current = autoplay;
87
+ }
88
+ if (autoplay && autoplayRef.current) {
89
+ var // Autoplay should only enable in the case where underlying state is true, temporary should not override
90
+ _emblaApi_current_plugins_autoplay, _emblaApi_current;
91
+ (_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();
92
+ // Reset after play to ensure timing and any focus/mouse pause state is reset.
93
+ resetAutoplay();
94
+ } else if (!autoplay) {
95
+ var _emblaApi_current_plugins_autoplay1, _emblaApi_current1;
96
+ (_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();
97
+ }
98
+ }, [
99
+ resetAutoplay
100
+ ]);
97
101
  // Listeners contains callbacks for UI elements that may require state update based on embla changes
98
102
  const listeners = React.useRef(new Set());
99
103
  const subscribeForValues = React.useCallback((listener)=>{
@@ -121,22 +125,30 @@ export function useEmblaCarousel(options) {
121
125
  listener(data);
122
126
  }
123
127
  });
128
+ const handleIndexChange = useEventCallback((_, eventType)=>{
129
+ var _emblaApi_current, _emblaApi_current1, _emblaApi_current2;
130
+ var _emblaApi_current_selectedScrollSnap;
131
+ 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;
132
+ const slides = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.slideNodes();
133
+ var _emblaApi_current_internalEngine_slideRegistry_newIndex_;
134
+ 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;
135
+ // We set the active or first index of group on-screen as the selected tabster index
136
+ slides === null || slides === void 0 ? void 0 : slides.forEach((slide, slideIndex)=>{
137
+ setTabsterDefault(slide, slideIndex === actualIndex);
138
+ });
139
+ setActiveIndex(newIndex);
140
+ if (eventType === 'autoplay:select') {
141
+ const noopEvent = new Event('autoplay');
142
+ onAutoplayIndexChange === null || onAutoplayIndexChange === void 0 ? void 0 : onAutoplayIndexChange(noopEvent, {
143
+ event: noopEvent,
144
+ type: 'autoplay',
145
+ index: newIndex
146
+ });
147
+ }
148
+ });
124
149
  const viewportRef = React.useRef(null);
125
150
  const containerRef = React.useMemo(()=>{
126
151
  let currentElement = null;
127
- const handleIndexChange = ()=>{
128
- var _emblaApi_current, _emblaApi_current1, _emblaApi_current2;
129
- var _emblaApi_current_selectedScrollSnap;
130
- 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;
131
- const slides = (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.slideNodes();
132
- var _emblaApi_current_internalEngine_slideRegistry_newIndex_;
133
- 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;
134
- // We set the active or first index of group on-screen as the selected tabster index
135
- slides === null || slides === void 0 ? void 0 : slides.forEach((slide, slideIndex)=>{
136
- setTabsterDefault(slide, slideIndex === actualIndex);
137
- });
138
- setActiveIndex(newIndex);
139
- };
140
152
  const handleVisibilityChange = ()=>{
141
153
  var _emblaApi_current, _emblaApi_current1;
142
154
  const cardElements = (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.slideNodes();
@@ -151,35 +163,37 @@ export function useEmblaCarousel(options) {
151
163
  }));
152
164
  });
153
165
  };
166
+ // Get plugins using autoplayRef to prevent state change recreating EmblaCarousel
154
167
  const plugins = getPlugins();
155
168
  return {
156
169
  set current (newElement){
157
170
  if (currentElement) {
158
- var _emblaApi_current, _emblaApi_current1, _emblaApi_current2, _emblaApi_current3;
171
+ var _emblaApi_current, _emblaApi_current1, _emblaApi_current2, _emblaApi_current3, _emblaApi_current4;
159
172
  (_emblaApi_current = emblaApi.current) === null || _emblaApi_current === void 0 ? void 0 : _emblaApi_current.off('slidesInView', handleVisibilityChange);
160
173
  (_emblaApi_current1 = emblaApi.current) === null || _emblaApi_current1 === void 0 ? void 0 : _emblaApi_current1.off('select', handleIndexChange);
161
174
  (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.off('reInit', handleReinit);
162
- (_emblaApi_current3 = emblaApi.current) === null || _emblaApi_current3 === void 0 ? void 0 : _emblaApi_current3.destroy();
175
+ (_emblaApi_current3 = emblaApi.current) === null || _emblaApi_current3 === void 0 ? void 0 : _emblaApi_current3.off('autoplay:select', handleIndexChange);
176
+ (_emblaApi_current4 = emblaApi.current) === null || _emblaApi_current4 === void 0 ? void 0 : _emblaApi_current4.destroy();
163
177
  }
164
178
  var _viewportRef_current;
165
179
  // Use direct viewport if available, else fallback to container (includes Carousel controls).
166
- const wrapperElement = (_viewportRef_current = viewportRef.current) !== null && _viewportRef_current !== void 0 ? _viewportRef_current : newElement;
167
- if (wrapperElement) {
168
- var _emblaApi_current4, _emblaApi_current5, _emblaApi_current6;
169
- currentElement = wrapperElement;
170
- emblaApi.current = EmblaCarousel(wrapperElement, {
180
+ currentElement = (_viewportRef_current = viewportRef.current) !== null && _viewportRef_current !== void 0 ? _viewportRef_current : newElement;
181
+ if (currentElement) {
182
+ var _emblaApi_current5, _emblaApi_current6, _emblaApi_current7, _emblaApi_current8;
183
+ emblaApi.current = EmblaCarousel(currentElement, {
171
184
  ...DEFAULT_EMBLA_OPTIONS,
172
185
  ...emblaOptions.current
173
186
  }, plugins);
174
- (_emblaApi_current4 = emblaApi.current) === null || _emblaApi_current4 === void 0 ? void 0 : _emblaApi_current4.on('reInit', handleReinit);
175
- (_emblaApi_current5 = emblaApi.current) === null || _emblaApi_current5 === void 0 ? void 0 : _emblaApi_current5.on('slidesInView', handleVisibilityChange);
176
- (_emblaApi_current6 = emblaApi.current) === null || _emblaApi_current6 === void 0 ? void 0 : _emblaApi_current6.on('select', handleIndexChange);
187
+ (_emblaApi_current5 = emblaApi.current) === null || _emblaApi_current5 === void 0 ? void 0 : _emblaApi_current5.on('reInit', handleReinit);
188
+ (_emblaApi_current6 = emblaApi.current) === null || _emblaApi_current6 === void 0 ? void 0 : _emblaApi_current6.on('slidesInView', handleVisibilityChange);
189
+ (_emblaApi_current7 = emblaApi.current) === null || _emblaApi_current7 === void 0 ? void 0 : _emblaApi_current7.on('select', handleIndexChange);
190
+ (_emblaApi_current8 = emblaApi.current) === null || _emblaApi_current8 === void 0 ? void 0 : _emblaApi_current8.on('autoplay:select', handleIndexChange);
177
191
  }
178
192
  }
179
193
  };
180
194
  }, [
181
195
  getPlugins,
182
- setActiveIndex,
196
+ handleIndexChange,
183
197
  handleReinit
184
198
  ]);
185
199
  const carouselApi = React.useMemo(()=>({
@@ -214,22 +228,6 @@ export function useEmblaCarousel(options) {
214
228
  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;
215
229
  }
216
230
  }), []);
217
- React.useEffect(()=>{
218
- var _emblaApi_current, _emblaApi_current_slideNodes, _emblaApi_current1;
219
- var _emblaApi_current_selectedScrollSnap;
220
- // Scroll to controlled values on update
221
- // If active index is out of bounds, re-init will handle instead
222
- 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;
223
- var _emblaApi_current_slideNodes_length;
224
- 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;
225
- emblaOptions.current.startIndex = activeIndex;
226
- if (activeIndex < slideLength && activeIndex !== currentActiveIndex) {
227
- var _emblaApi_current2;
228
- (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.scrollTo(activeIndex);
229
- }
230
- }, [
231
- activeIndex
232
- ]);
233
231
  React.useEffect(()=>{
234
232
  var _emblaApi_current;
235
233
  const plugins = getPlugins();
@@ -248,12 +246,28 @@ export function useEmblaCarousel(options) {
248
246
  }, plugins);
249
247
  }, [
250
248
  align,
249
+ containScroll,
251
250
  direction,
251
+ getPlugins,
252
252
  loop,
253
253
  slidesToScroll,
254
- watchDrag,
255
- containScroll,
256
- getPlugins
254
+ watchDrag
255
+ ]);
256
+ React.useEffect(()=>{
257
+ var _emblaApi_current, _emblaApi_current_slideNodes, _emblaApi_current1;
258
+ var _emblaApi_current_selectedScrollSnap;
259
+ // Scroll to controlled values on update
260
+ // If active index is out of bounds, re-init will handle instead
261
+ 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;
262
+ var _emblaApi_current_slideNodes_length;
263
+ 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;
264
+ emblaOptions.current.startIndex = activeIndex;
265
+ if (activeIndex < slideLength && activeIndex !== currentActiveIndex) {
266
+ var _emblaApi_current2;
267
+ (_emblaApi_current2 = emblaApi.current) === null || _emblaApi_current2 === void 0 ? void 0 : _emblaApi_current2.scrollTo(activeIndex);
268
+ }
269
+ }, [
270
+ activeIndex
257
271
  ]);
258
272
  return {
259
273
  activeIndex,